1 //=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*- 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This tablegen backend emits Clang Static Analyzer checkers tables. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "ClangSACheckersEmitter.h" 15 #include "llvm/TableGen/Record.h" 16 #include "llvm/ADT/DenseSet.h" 17 #include <map> 18 #include <string> 19 using namespace llvm; 20 21 //===----------------------------------------------------------------------===// 22 // Static Analyzer Checkers Tables generation 23 //===----------------------------------------------------------------------===// 24 25 /// \brief True if it is specified hidden or a parent package is specified 26 /// as hidden, otherwise false. 27 static bool isHidden(const Record &R) { 28 if (R.getValueAsBit("Hidden")) 29 return true; 30 // Not declared as hidden, check the parent package if it is hidden. 31 if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("ParentPackage"))) 32 return isHidden(*DI->getDef()); 33 34 return false; 35 } 36 37 static bool isCheckerNamed(const Record *R) { 38 return !R->getValueAsString("CheckerName").empty(); 39 } 40 41 static std::string getPackageFullName(const Record *R); 42 43 static std::string getParentPackageFullName(const Record *R) { 44 std::string name; 45 if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("ParentPackage"))) 46 name = getPackageFullName(DI->getDef()); 47 return name; 48 } 49 50 static std::string getPackageFullName(const Record *R) { 51 std::string name = getParentPackageFullName(R); 52 if (!name.empty()) name += "."; 53 return name + R->getValueAsString("PackageName"); 54 } 55 56 static std::string getCheckerFullName(const Record *R) { 57 std::string name = getParentPackageFullName(R); 58 if (isCheckerNamed(R)) { 59 if (!name.empty()) name += "."; 60 name += R->getValueAsString("CheckerName"); 61 } 62 return name; 63 } 64 65 static std::string getStringValue(const Record &R, StringRef field) { 66 if (StringInit * 67 SI = dynamic_cast<StringInit*>(R.getValueInit(field))) 68 return SI->getValue(); 69 return std::string(); 70 } 71 72 namespace { 73 struct GroupInfo { 74 llvm::DenseSet<const Record*> Checkers; 75 llvm::DenseSet<const Record *> SubGroups; 76 bool Hidden; 77 unsigned Index; 78 79 GroupInfo() : Hidden(false) { } 80 }; 81 } 82 83 static void addPackageToCheckerGroup(const Record *package, const Record *group, 84 llvm::DenseMap<const Record *, GroupInfo *> &recordGroupMap) { 85 llvm::DenseSet<const Record *> &checkers = recordGroupMap[package]->Checkers; 86 for (llvm::DenseSet<const Record *>::iterator 87 I = checkers.begin(), E = checkers.end(); I != E; ++I) 88 recordGroupMap[group]->Checkers.insert(*I); 89 90 llvm::DenseSet<const Record *> &subGroups = recordGroupMap[package]->SubGroups; 91 for (llvm::DenseSet<const Record *>::iterator 92 I = subGroups.begin(), E = subGroups.end(); I != E; ++I) 93 addPackageToCheckerGroup(*I, group, recordGroupMap); 94 } 95 96 void ClangSACheckersEmitter::run(raw_ostream &OS) { 97 std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker"); 98 llvm::DenseMap<const Record *, unsigned> checkerRecIndexMap; 99 for (unsigned i = 0, e = checkers.size(); i != e; ++i) 100 checkerRecIndexMap[checkers[i]] = i; 101 102 // Invert the mapping of checkers to package/group into a one to many 103 // mapping of packages/groups to checkers. 104 std::map<std::string, GroupInfo> groupInfoByName; 105 llvm::DenseMap<const Record *, GroupInfo *> recordGroupMap; 106 107 std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package"); 108 for (unsigned i = 0, e = packages.size(); i != e; ++i) { 109 Record *R = packages[i]; 110 std::string fullName = getPackageFullName(R); 111 if (!fullName.empty()) { 112 GroupInfo &info = groupInfoByName[fullName]; 113 info.Hidden = isHidden(*R); 114 recordGroupMap[R] = &info; 115 } 116 } 117 118 std::vector<Record*> 119 checkerGroups = Records.getAllDerivedDefinitions("CheckerGroup"); 120 for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) { 121 Record *R = checkerGroups[i]; 122 std::string name = R->getValueAsString("GroupName"); 123 if (!name.empty()) { 124 GroupInfo &info = groupInfoByName[name]; 125 recordGroupMap[R] = &info; 126 } 127 } 128 129 for (unsigned i = 0, e = checkers.size(); i != e; ++i) { 130 Record *R = checkers[i]; 131 Record *package = 0; 132 if (DefInit * 133 DI = dynamic_cast<DefInit*>(R->getValueInit("ParentPackage"))) 134 package = DI->getDef(); 135 if (!isCheckerNamed(R) && !package) 136 throw "Checker '" + R->getName() + "' is neither named, nor in a package!"; 137 138 if (isCheckerNamed(R)) { 139 // Create a pseudo-group to hold this checker. 140 std::string fullName = getCheckerFullName(R); 141 GroupInfo &info = groupInfoByName[fullName]; 142 info.Hidden = R->getValueAsBit("Hidden"); 143 recordGroupMap[R] = &info; 144 info.Checkers.insert(R); 145 } else { 146 recordGroupMap[package]->Checkers.insert(R); 147 } 148 149 Record *currR = isCheckerNamed(R) ? R : package; 150 // Insert the checker and its parent packages into the subgroups set of 151 // the corresponding parent package. 152 while (DefInit *DI 153 = dynamic_cast<DefInit*>(currR->getValueInit("ParentPackage"))) { 154 Record *parentPackage = DI->getDef(); 155 recordGroupMap[parentPackage]->SubGroups.insert(currR); 156 currR = parentPackage; 157 } 158 // Insert the checker into the set of its group. 159 if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group"))) 160 recordGroupMap[DI->getDef()]->Checkers.insert(R); 161 } 162 163 // If a package is in group, add all its checkers and its sub-packages 164 // checkers into the group. 165 for (unsigned i = 0, e = packages.size(); i != e; ++i) 166 if (DefInit *DI = dynamic_cast<DefInit*>(packages[i]->getValueInit("Group"))) 167 addPackageToCheckerGroup(packages[i], DI->getDef(), recordGroupMap); 168 169 typedef std::map<std::string, const Record *> SortedRecords; 170 typedef llvm::DenseMap<const Record *, unsigned> RecToSortIndex; 171 172 SortedRecords sortedGroups; 173 RecToSortIndex groupToSortIndex; 174 OS << "\n#ifdef GET_GROUPS\n"; 175 { 176 for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) 177 sortedGroups[checkerGroups[i]->getValueAsString("GroupName")] 178 = checkerGroups[i]; 179 180 unsigned sortIndex = 0; 181 for (SortedRecords::iterator 182 I = sortedGroups.begin(), E = sortedGroups.end(); I != E; ++I) { 183 const Record *R = I->second; 184 185 OS << "GROUP(" << "\""; 186 OS.write_escaped(R->getValueAsString("GroupName")) << "\""; 187 OS << ")\n"; 188 189 groupToSortIndex[R] = sortIndex++; 190 } 191 } 192 OS << "#endif // GET_GROUPS\n\n"; 193 194 OS << "\n#ifdef GET_PACKAGES\n"; 195 { 196 SortedRecords sortedPackages; 197 for (unsigned i = 0, e = packages.size(); i != e; ++i) 198 sortedPackages[getPackageFullName(packages[i])] = packages[i]; 199 200 for (SortedRecords::iterator 201 I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) { 202 const Record &R = *I->second; 203 204 OS << "PACKAGE(" << "\""; 205 OS.write_escaped(getPackageFullName(&R)) << "\", "; 206 // Group index 207 if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) 208 OS << groupToSortIndex[DI->getDef()] << ", "; 209 else 210 OS << "-1, "; 211 // Hidden bit 212 if (isHidden(R)) 213 OS << "true"; 214 else 215 OS << "false"; 216 OS << ")\n"; 217 } 218 } 219 OS << "#endif // GET_PACKAGES\n\n"; 220 221 OS << "\n#ifdef GET_CHECKERS\n"; 222 for (unsigned i = 0, e = checkers.size(); i != e; ++i) { 223 const Record &R = *checkers[i]; 224 225 OS << "CHECKER(" << "\""; 226 std::string name; 227 if (isCheckerNamed(&R)) 228 name = getCheckerFullName(&R); 229 OS.write_escaped(name) << "\", "; 230 OS << R.getName() << ", "; 231 OS << getStringValue(R, "DescFile") << ", "; 232 OS << "\""; 233 OS.write_escaped(getStringValue(R, "HelpText")) << "\", "; 234 // Group index 235 if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) 236 OS << groupToSortIndex[DI->getDef()] << ", "; 237 else 238 OS << "-1, "; 239 // Hidden bit 240 if (isHidden(R)) 241 OS << "true"; 242 else 243 OS << "false"; 244 OS << ")\n"; 245 } 246 OS << "#endif // GET_CHECKERS\n\n"; 247 248 unsigned index = 0; 249 for (std::map<std::string, GroupInfo>::iterator 250 I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) 251 I->second.Index = index++; 252 253 // Walk through the packages/groups/checkers emitting an array for each 254 // set of checkers and an array for each set of subpackages. 255 256 OS << "\n#ifdef GET_MEMBER_ARRAYS\n"; 257 unsigned maxLen = 0; 258 for (std::map<std::string, GroupInfo>::iterator 259 I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) { 260 maxLen = std::max(maxLen, (unsigned)I->first.size()); 261 262 llvm::DenseSet<const Record *> &checkers = I->second.Checkers; 263 if (!checkers.empty()) { 264 OS << "static const short CheckerArray" << I->second.Index << "[] = { "; 265 // Make the output order deterministic. 266 std::map<int, const Record *> sorted; 267 for (llvm::DenseSet<const Record *>::iterator 268 I = checkers.begin(), E = checkers.end(); I != E; ++I) 269 sorted[(*I)->getID()] = *I; 270 271 for (std::map<int, const Record *>::iterator 272 I = sorted.begin(), E = sorted.end(); I != E; ++I) 273 OS << checkerRecIndexMap[I->second] << ", "; 274 OS << "-1 };\n"; 275 } 276 277 llvm::DenseSet<const Record *> &subGroups = I->second.SubGroups; 278 if (!subGroups.empty()) { 279 OS << "static const short SubPackageArray" << I->second.Index << "[] = { "; 280 // Make the output order deterministic. 281 std::map<int, const Record *> sorted; 282 for (llvm::DenseSet<const Record *>::iterator 283 I = subGroups.begin(), E = subGroups.end(); I != E; ++I) 284 sorted[(*I)->getID()] = *I; 285 286 for (std::map<int, const Record *>::iterator 287 I = sorted.begin(), E = sorted.end(); I != E; ++I) { 288 OS << recordGroupMap[I->second]->Index << ", "; 289 } 290 OS << "-1 };\n"; 291 } 292 } 293 OS << "#endif // GET_MEMBER_ARRAYS\n\n"; 294 295 OS << "\n#ifdef GET_CHECKNAME_TABLE\n"; 296 for (std::map<std::string, GroupInfo>::iterator 297 I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) { 298 // Group option string. 299 OS << " { \""; 300 OS.write_escaped(I->first) << "\"," 301 << std::string(maxLen-I->first.size()+1, ' '); 302 303 if (I->second.Checkers.empty()) 304 OS << "0, "; 305 else 306 OS << "CheckerArray" << I->second.Index << ", "; 307 308 // Subgroups. 309 if (I->second.SubGroups.empty()) 310 OS << "0, "; 311 else 312 OS << "SubPackageArray" << I->second.Index << ", "; 313 314 OS << (I->second.Hidden ? "true" : "false"); 315 316 OS << " },\n"; 317 } 318 OS << "#endif // GET_CHECKNAME_TABLE\n\n"; 319 } 320