1 //=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*- 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This tablegen backend emits Clang Static Analyzer checkers tables. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "TableGenBackends.h" 14 #include "llvm/ADT/StringMap.h" 15 #include "llvm/TableGen/Error.h" 16 #include "llvm/TableGen/Record.h" 17 #include "llvm/TableGen/TableGenBackend.h" 18 #include <map> 19 #include <string> 20 21 using namespace llvm; 22 23 //===----------------------------------------------------------------------===// 24 // Static Analyzer Checkers Tables generation 25 //===----------------------------------------------------------------------===// 26 27 static std::string getPackageFullName(const Record *R, StringRef Sep = "."); 28 29 static std::string getParentPackageFullName(const Record *R, 30 StringRef Sep = ".") { 31 std::string name; 32 if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage"))) 33 name = getPackageFullName(DI->getDef(), Sep); 34 return name; 35 } 36 37 static std::string getPackageFullName(const Record *R, StringRef Sep) { 38 std::string name = getParentPackageFullName(R, Sep); 39 if (!name.empty()) 40 name += Sep; 41 assert(!R->getValueAsString("PackageName").empty()); 42 name += R->getValueAsString("PackageName"); 43 return name; 44 } 45 46 static std::string getCheckerFullName(const Record *R, StringRef Sep = ".") { 47 std::string name = getParentPackageFullName(R, Sep); 48 if (!name.empty()) 49 name += Sep; 50 assert(!R->getValueAsString("CheckerName").empty()); 51 name += R->getValueAsString("CheckerName"); 52 return name; 53 } 54 55 static std::string getStringValue(const Record &R, StringRef field) { 56 if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field))) 57 return std::string(SI->getValue()); 58 return std::string(); 59 } 60 61 // Calculates the integer value representing the BitsInit object 62 static inline uint64_t getValueFromBitsInit(const BitsInit *B, const Record &R) { 63 assert(B->getNumBits() <= sizeof(uint64_t) * 8 && "BitInits' too long!"); 64 65 uint64_t Value = 0; 66 for (unsigned i = 0, e = B->getNumBits(); i != e; ++i) { 67 const auto *Bit = dyn_cast<BitInit>(B->getBit(i)); 68 if (Bit) 69 Value |= uint64_t(Bit->getValue()) << i; 70 else 71 PrintFatalError(R.getLoc(), 72 "missing Documentation for " + getCheckerFullName(&R)); 73 } 74 return Value; 75 } 76 77 static std::string getCheckerDocs(const Record &R) { 78 const BitsInit *BI = R.getValueAsBitsInit("Documentation"); 79 if (!BI) 80 PrintFatalError(R.getLoc(), "missing Documentation<...> member for " + 81 getCheckerFullName(&R)); 82 83 // Ignore 'Documentation<NotDocumented>' checkers. 84 if (getValueFromBitsInit(BI, R) == 0) 85 return ""; 86 87 std::string CheckerFullName = StringRef(getCheckerFullName(&R, "-")).lower(); 88 return (llvm::Twine("https://clang.llvm.org/docs/analyzer/checkers.html#") + 89 CheckerFullName) 90 .str(); 91 } 92 93 /// Retrieves the type from a CmdOptionTypeEnum typed Record object. Note that 94 /// the class itself has to be modified for adding a new option type in 95 /// CheckerBase.td. 96 static std::string getCheckerOptionType(const Record &R) { 97 if (BitsInit *BI = R.getValueAsBitsInit("Type")) { 98 switch(getValueFromBitsInit(BI, R)) { 99 case 0: 100 return "int"; 101 case 1: 102 return "string"; 103 case 2: 104 return "bool"; 105 } 106 } 107 PrintFatalError(R.getLoc(), 108 "unable to parse command line option type for " 109 + getCheckerFullName(&R)); 110 return ""; 111 } 112 113 static std::string getDevelopmentStage(const Record &R) { 114 if (BitsInit *BI = R.getValueAsBitsInit("DevelopmentStage")) { 115 switch(getValueFromBitsInit(BI, R)) { 116 case 0: 117 return "alpha"; 118 case 1: 119 return "released"; 120 } 121 } 122 123 PrintFatalError(R.getLoc(), 124 "unable to parse command line option type for " 125 + getCheckerFullName(&R)); 126 return ""; 127 } 128 129 static bool isHidden(const Record *R) { 130 if (R->getValueAsBit("Hidden")) 131 return true; 132 133 // Not declared as hidden, check the parent package if it is hidden. 134 if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage"))) 135 return isHidden(DI->getDef()); 136 137 return false; 138 } 139 140 static void printChecker(llvm::raw_ostream &OS, const Record &R) { 141 OS << "CHECKER(" << "\""; 142 OS.write_escaped(getCheckerFullName(&R)) << "\", "; 143 OS << R.getName() << ", "; 144 OS << "\""; 145 OS.write_escaped(getStringValue(R, "HelpText")) << "\", "; 146 OS << "\""; 147 OS.write_escaped(getCheckerDocs(R)); 148 OS << "\", "; 149 150 if (!isHidden(&R)) 151 OS << "false"; 152 else 153 OS << "true"; 154 155 OS << ")\n"; 156 } 157 158 static void printOption(llvm::raw_ostream &OS, StringRef FullName, 159 const Record &R) { 160 OS << "\""; 161 OS.write_escaped(getCheckerOptionType(R)) << "\", \""; 162 OS.write_escaped(FullName) << "\", "; 163 OS << '\"' << getStringValue(R, "CmdFlag") << "\", "; 164 OS << '\"'; 165 OS.write_escaped(getStringValue(R, "Desc")) << "\", "; 166 OS << '\"'; 167 OS.write_escaped(getStringValue(R, "DefaultVal")) << "\", "; 168 OS << '\"'; 169 OS << getDevelopmentStage(R) << "\", "; 170 171 if (!R.getValueAsBit("Hidden")) 172 OS << "false"; 173 else 174 OS << "true"; 175 } 176 177 void clang::EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) { 178 std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker"); 179 std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package"); 180 181 using SortedRecords = llvm::StringMap<const Record *>; 182 183 OS << "// This file is automatically generated. Do not edit this file by " 184 "hand.\n"; 185 186 // Emit packages. 187 // 188 // PACKAGE(PACKAGENAME) 189 // - PACKAGENAME: The name of the package. 190 OS << "\n" 191 "#ifdef GET_PACKAGES\n"; 192 { 193 SortedRecords sortedPackages; 194 for (unsigned i = 0, e = packages.size(); i != e; ++i) 195 sortedPackages[getPackageFullName(packages[i])] = packages[i]; 196 197 for (SortedRecords::iterator 198 I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) { 199 const Record &R = *I->second; 200 201 OS << "PACKAGE(" << "\""; 202 OS.write_escaped(getPackageFullName(&R)) << '\"'; 203 OS << ")\n"; 204 } 205 } 206 OS << "#endif // GET_PACKAGES\n" 207 "\n"; 208 209 // Emit a package option. 210 // 211 // PACKAGE_OPTION(OPTIONTYPE, PACKAGENAME, OPTIONNAME, DESCRIPTION, DEFAULT) 212 // - OPTIONTYPE: Type of the option, whether it's integer or boolean etc. 213 // This is important for validating user input. Note that 214 // it's a string, rather than an actual type: since we can 215 // load checkers runtime, we can't use template hackery for 216 // sorting this out compile-time. 217 // - PACKAGENAME: Name of the package. 218 // - OPTIONNAME: Name of the option. 219 // - DESCRIPTION 220 // - DEFAULT: The default value for this option. 221 // 222 // The full option can be specified in the command like like this: 223 // -analyzer-config PACKAGENAME:OPTIONNAME=VALUE 224 OS << "\n" 225 "#ifdef GET_PACKAGE_OPTIONS\n"; 226 for (const Record *Package : packages) { 227 228 if (Package->isValueUnset("PackageOptions")) 229 continue; 230 231 std::vector<Record *> PackageOptions = Package 232 ->getValueAsListOfDefs("PackageOptions"); 233 for (Record *PackageOpt : PackageOptions) { 234 OS << "PACKAGE_OPTION("; 235 printOption(OS, getPackageFullName(Package), *PackageOpt); 236 OS << ")\n"; 237 } 238 } 239 OS << "#endif // GET_PACKAGE_OPTIONS\n" 240 "\n"; 241 242 // Emit checkers. 243 // 244 // CHECKER(FULLNAME, CLASS, HELPTEXT) 245 // - FULLNAME: The full name of the checker, including packages, e.g.: 246 // alpha.cplusplus.UninitializedObject 247 // - CLASS: The name of the checker, with "Checker" appended, e.g.: 248 // UninitializedObjectChecker 249 // - HELPTEXT: The description of the checker. 250 OS << "\n" 251 "#ifdef GET_CHECKERS\n" 252 "\n"; 253 for (const Record *checker : checkers) { 254 printChecker(OS, *checker); 255 } 256 OS << "\n" 257 "#endif // GET_CHECKERS\n" 258 "\n"; 259 260 // Emit dependencies. 261 // 262 // CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) 263 // - FULLNAME: The full name of the checker that depends on another checker. 264 // - DEPENDENCY: The full name of the checker FULLNAME depends on. 265 OS << "\n" 266 "#ifdef GET_CHECKER_DEPENDENCIES\n"; 267 for (const Record *Checker : checkers) { 268 if (Checker->isValueUnset("Dependencies")) 269 continue; 270 271 for (const Record *Dependency : 272 Checker->getValueAsListOfDefs("Dependencies")) { 273 OS << "CHECKER_DEPENDENCY("; 274 OS << '\"'; 275 OS.write_escaped(getCheckerFullName(Checker)) << "\", "; 276 OS << '\"'; 277 OS.write_escaped(getCheckerFullName(Dependency)) << '\"'; 278 OS << ")\n"; 279 } 280 } 281 OS << "\n" 282 "#endif // GET_CHECKER_DEPENDENCIES\n"; 283 284 // Emit weak dependencies. 285 // 286 // CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) 287 // - FULLNAME: The full name of the checker that is supposed to be 288 // registered first. 289 // - DEPENDENCY: The full name of the checker FULLNAME weak depends on. 290 OS << "\n" 291 "#ifdef GET_CHECKER_WEAK_DEPENDENCIES\n"; 292 for (const Record *Checker : checkers) { 293 if (Checker->isValueUnset("WeakDependencies")) 294 continue; 295 296 for (const Record *Dependency : 297 Checker->getValueAsListOfDefs("WeakDependencies")) { 298 OS << "CHECKER_WEAK_DEPENDENCY("; 299 OS << '\"'; 300 OS.write_escaped(getCheckerFullName(Checker)) << "\", "; 301 OS << '\"'; 302 OS.write_escaped(getCheckerFullName(Dependency)) << '\"'; 303 OS << ")\n"; 304 } 305 } 306 OS << "\n" 307 "#endif // GET_CHECKER_WEAK_DEPENDENCIES\n"; 308 309 // Emit a package option. 310 // 311 // CHECKER_OPTION(OPTIONTYPE, CHECKERNAME, OPTIONNAME, DESCRIPTION, DEFAULT) 312 // - OPTIONTYPE: Type of the option, whether it's integer or boolean etc. 313 // This is important for validating user input. Note that 314 // it's a string, rather than an actual type: since we can 315 // load checkers runtime, we can't use template hackery for 316 // sorting this out compile-time. 317 // - CHECKERNAME: Name of the package. 318 // - OPTIONNAME: Name of the option. 319 // - DESCRIPTION 320 // - DEFAULT: The default value for this option. 321 // 322 // The full option can be specified in the command like like this: 323 // -analyzer-config CHECKERNAME:OPTIONNAME=VALUE 324 OS << "\n" 325 "#ifdef GET_CHECKER_OPTIONS\n"; 326 for (const Record *Checker : checkers) { 327 328 if (Checker->isValueUnset("CheckerOptions")) 329 continue; 330 331 std::vector<Record *> CheckerOptions = Checker 332 ->getValueAsListOfDefs("CheckerOptions"); 333 for (Record *CheckerOpt : CheckerOptions) { 334 OS << "CHECKER_OPTION("; 335 printOption(OS, getCheckerFullName(Checker), *CheckerOpt); 336 OS << ")\n"; 337 } 338 } 339 OS << "#endif // GET_CHECKER_OPTIONS\n" 340 "\n"; 341 } 342