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 "llvm/ADT/DenseSet.h" 15 #include "llvm/TableGen/Record.h" 16 #include "llvm/TableGen/TableGenBackend.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 namespace clang { 97 void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) { 98 std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker"); 99 llvm::DenseMap<const Record *, unsigned> checkerRecIndexMap; 100 for (unsigned i = 0, e = checkers.size(); i != e; ++i) 101 checkerRecIndexMap[checkers[i]] = i; 102 103 // Invert the mapping of checkers to package/group into a one to many 104 // mapping of packages/groups to checkers. 105 std::map<std::string, GroupInfo> groupInfoByName; 106 llvm::DenseMap<const Record *, GroupInfo *> recordGroupMap; 107 108 std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package"); 109 for (unsigned i = 0, e = packages.size(); i != e; ++i) { 110 Record *R = packages[i]; 111 std::string fullName = getPackageFullName(R); 112 if (!fullName.empty()) { 113 GroupInfo &info = groupInfoByName[fullName]; 114 info.Hidden = isHidden(*R); 115 recordGroupMap[R] = &info; 116 } 117 } 118 119 std::vector<Record*> 120 checkerGroups = Records.getAllDerivedDefinitions("CheckerGroup"); 121 for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) { 122 Record *R = checkerGroups[i]; 123 std::string name = R->getValueAsString("GroupName"); 124 if (!name.empty()) { 125 GroupInfo &info = groupInfoByName[name]; 126 recordGroupMap[R] = &info; 127 } 128 } 129 130 for (unsigned i = 0, e = checkers.size(); i != e; ++i) { 131 Record *R = checkers[i]; 132 Record *package = 0; 133 if (DefInit * 134 DI = dynamic_cast<DefInit*>(R->getValueInit("ParentPackage"))) 135 package = DI->getDef(); 136 if (!isCheckerNamed(R) && !package) 137 throw "Checker '" + R->getName() + "' is neither named, nor in a package!"; 138 139 if (isCheckerNamed(R)) { 140 // Create a pseudo-group to hold this checker. 141 std::string fullName = getCheckerFullName(R); 142 GroupInfo &info = groupInfoByName[fullName]; 143 info.Hidden = R->getValueAsBit("Hidden"); 144 recordGroupMap[R] = &info; 145 info.Checkers.insert(R); 146 } else { 147 recordGroupMap[package]->Checkers.insert(R); 148 } 149 150 Record *currR = isCheckerNamed(R) ? R : package; 151 // Insert the checker and its parent packages into the subgroups set of 152 // the corresponding parent package. 153 while (DefInit *DI 154 = dynamic_cast<DefInit*>(currR->getValueInit("ParentPackage"))) { 155 Record *parentPackage = DI->getDef(); 156 recordGroupMap[parentPackage]->SubGroups.insert(currR); 157 currR = parentPackage; 158 } 159 // Insert the checker into the set of its group. 160 if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group"))) 161 recordGroupMap[DI->getDef()]->Checkers.insert(R); 162 } 163 164 // If a package is in group, add all its checkers and its sub-packages 165 // checkers into the group. 166 for (unsigned i = 0, e = packages.size(); i != e; ++i) 167 if (DefInit *DI = dynamic_cast<DefInit*>(packages[i]->getValueInit("Group"))) 168 addPackageToCheckerGroup(packages[i], DI->getDef(), recordGroupMap); 169 170 typedef std::map<std::string, const Record *> SortedRecords; 171 typedef llvm::DenseMap<const Record *, unsigned> RecToSortIndex; 172 173 SortedRecords sortedGroups; 174 RecToSortIndex groupToSortIndex; 175 OS << "\n#ifdef GET_GROUPS\n"; 176 { 177 for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) 178 sortedGroups[checkerGroups[i]->getValueAsString("GroupName")] 179 = checkerGroups[i]; 180 181 unsigned sortIndex = 0; 182 for (SortedRecords::iterator 183 I = sortedGroups.begin(), E = sortedGroups.end(); I != E; ++I) { 184 const Record *R = I->second; 185 186 OS << "GROUP(" << "\""; 187 OS.write_escaped(R->getValueAsString("GroupName")) << "\""; 188 OS << ")\n"; 189 190 groupToSortIndex[R] = sortIndex++; 191 } 192 } 193 OS << "#endif // GET_GROUPS\n\n"; 194 195 OS << "\n#ifdef GET_PACKAGES\n"; 196 { 197 SortedRecords sortedPackages; 198 for (unsigned i = 0, e = packages.size(); i != e; ++i) 199 sortedPackages[getPackageFullName(packages[i])] = packages[i]; 200 201 for (SortedRecords::iterator 202 I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) { 203 const Record &R = *I->second; 204 205 OS << "PACKAGE(" << "\""; 206 OS.write_escaped(getPackageFullName(&R)) << "\", "; 207 // Group index 208 if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) 209 OS << groupToSortIndex[DI->getDef()] << ", "; 210 else 211 OS << "-1, "; 212 // Hidden bit 213 if (isHidden(R)) 214 OS << "true"; 215 else 216 OS << "false"; 217 OS << ")\n"; 218 } 219 } 220 OS << "#endif // GET_PACKAGES\n\n"; 221 222 OS << "\n#ifdef GET_CHECKERS\n"; 223 for (unsigned i = 0, e = checkers.size(); i != e; ++i) { 224 const Record &R = *checkers[i]; 225 226 OS << "CHECKER(" << "\""; 227 std::string name; 228 if (isCheckerNamed(&R)) 229 name = getCheckerFullName(&R); 230 OS.write_escaped(name) << "\", "; 231 OS << R.getName() << ", "; 232 OS << getStringValue(R, "DescFile") << ", "; 233 OS << "\""; 234 OS.write_escaped(getStringValue(R, "HelpText")) << "\", "; 235 // Group index 236 if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) 237 OS << groupToSortIndex[DI->getDef()] << ", "; 238 else 239 OS << "-1, "; 240 // Hidden bit 241 if (isHidden(R)) 242 OS << "true"; 243 else 244 OS << "false"; 245 OS << ")\n"; 246 } 247 OS << "#endif // GET_CHECKERS\n\n"; 248 249 unsigned index = 0; 250 for (std::map<std::string, GroupInfo>::iterator 251 I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) 252 I->second.Index = index++; 253 254 // Walk through the packages/groups/checkers emitting an array for each 255 // set of checkers and an array for each set of subpackages. 256 257 OS << "\n#ifdef GET_MEMBER_ARRAYS\n"; 258 unsigned maxLen = 0; 259 for (std::map<std::string, GroupInfo>::iterator 260 I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) { 261 maxLen = std::max(maxLen, (unsigned)I->first.size()); 262 263 llvm::DenseSet<const Record *> &checkers = I->second.Checkers; 264 if (!checkers.empty()) { 265 OS << "static const short CheckerArray" << I->second.Index << "[] = { "; 266 // Make the output order deterministic. 267 std::map<int, const Record *> sorted; 268 for (llvm::DenseSet<const Record *>::iterator 269 I = checkers.begin(), E = checkers.end(); I != E; ++I) 270 sorted[(*I)->getID()] = *I; 271 272 for (std::map<int, const Record *>::iterator 273 I = sorted.begin(), E = sorted.end(); I != E; ++I) 274 OS << checkerRecIndexMap[I->second] << ", "; 275 OS << "-1 };\n"; 276 } 277 278 llvm::DenseSet<const Record *> &subGroups = I->second.SubGroups; 279 if (!subGroups.empty()) { 280 OS << "static const short SubPackageArray" << I->second.Index << "[] = { "; 281 // Make the output order deterministic. 282 std::map<int, const Record *> sorted; 283 for (llvm::DenseSet<const Record *>::iterator 284 I = subGroups.begin(), E = subGroups.end(); I != E; ++I) 285 sorted[(*I)->getID()] = *I; 286 287 for (std::map<int, const Record *>::iterator 288 I = sorted.begin(), E = sorted.end(); I != E; ++I) { 289 OS << recordGroupMap[I->second]->Index << ", "; 290 } 291 OS << "-1 };\n"; 292 } 293 } 294 OS << "#endif // GET_MEMBER_ARRAYS\n\n"; 295 296 OS << "\n#ifdef GET_CHECKNAME_TABLE\n"; 297 for (std::map<std::string, GroupInfo>::iterator 298 I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) { 299 // Group option string. 300 OS << " { \""; 301 OS.write_escaped(I->first) << "\"," 302 << std::string(maxLen-I->first.size()+1, ' '); 303 304 if (I->second.Checkers.empty()) 305 OS << "0, "; 306 else 307 OS << "CheckerArray" << I->second.Index << ", "; 308 309 // Subgroups. 310 if (I->second.SubGroups.empty()) 311 OS << "0, "; 312 else 313 OS << "SubPackageArray" << I->second.Index << ", "; 314 315 OS << (I->second.Hidden ? "true" : "false"); 316 317 OS << " },\n"; 318 } 319 OS << "#endif // GET_CHECKNAME_TABLE\n\n"; 320 } 321 } // end namespace clang 322