1 //=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics 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 // These tablegen backends emit Clang diagnostics tables. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "ClangDiagnosticsEmitter.h" 15 #include "llvm/TableGen/Record.h" 16 #include "llvm/Support/Debug.h" 17 #include "llvm/Support/Compiler.h" 18 #include "llvm/ADT/DenseSet.h" 19 #include "llvm/ADT/StringMap.h" 20 #include "llvm/ADT/SmallString.h" 21 #include <map> 22 #include <algorithm> 23 #include <functional> 24 #include <set> 25 using namespace llvm; 26 27 //===----------------------------------------------------------------------===// 28 // Diagnostic category computation code. 29 //===----------------------------------------------------------------------===// 30 31 namespace { 32 class DiagGroupParentMap { 33 RecordKeeper &Records; 34 std::map<const Record*, std::vector<Record*> > Mapping; 35 public: 36 DiagGroupParentMap(RecordKeeper &records) : Records(records) { 37 std::vector<Record*> DiagGroups 38 = Records.getAllDerivedDefinitions("DiagGroup"); 39 for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { 40 std::vector<Record*> SubGroups = 41 DiagGroups[i]->getValueAsListOfDefs("SubGroups"); 42 for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) 43 Mapping[SubGroups[j]].push_back(DiagGroups[i]); 44 } 45 } 46 47 const std::vector<Record*> &getParents(const Record *Group) { 48 return Mapping[Group]; 49 } 50 }; 51 } // end anonymous namespace. 52 53 static std::string 54 getCategoryFromDiagGroup(const Record *Group, 55 DiagGroupParentMap &DiagGroupParents) { 56 // If the DiagGroup has a category, return it. 57 std::string CatName = Group->getValueAsString("CategoryName"); 58 if (!CatName.empty()) return CatName; 59 60 // The diag group may the subgroup of one or more other diagnostic groups, 61 // check these for a category as well. 62 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 63 for (unsigned i = 0, e = Parents.size(); i != e; ++i) { 64 CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents); 65 if (!CatName.empty()) return CatName; 66 } 67 return ""; 68 } 69 70 /// getDiagnosticCategory - Return the category that the specified diagnostic 71 /// lives in. 72 static std::string getDiagnosticCategory(const Record *R, 73 DiagGroupParentMap &DiagGroupParents) { 74 // If the diagnostic is in a group, and that group has a category, use it. 75 if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group"))) { 76 // Check the diagnostic's diag group for a category. 77 std::string CatName = getCategoryFromDiagGroup(Group->getDef(), 78 DiagGroupParents); 79 if (!CatName.empty()) return CatName; 80 } 81 82 // If the diagnostic itself has a category, get it. 83 return R->getValueAsString("CategoryName"); 84 } 85 86 namespace { 87 class DiagCategoryIDMap { 88 RecordKeeper &Records; 89 StringMap<unsigned> CategoryIDs; 90 std::vector<std::string> CategoryStrings; 91 public: 92 DiagCategoryIDMap(RecordKeeper &records) : Records(records) { 93 DiagGroupParentMap ParentInfo(Records); 94 95 // The zero'th category is "". 96 CategoryStrings.push_back(""); 97 CategoryIDs[""] = 0; 98 99 std::vector<Record*> Diags = 100 Records.getAllDerivedDefinitions("Diagnostic"); 101 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 102 std::string Category = getDiagnosticCategory(Diags[i], ParentInfo); 103 if (Category.empty()) continue; // Skip diags with no category. 104 105 unsigned &ID = CategoryIDs[Category]; 106 if (ID != 0) continue; // Already seen. 107 108 ID = CategoryStrings.size(); 109 CategoryStrings.push_back(Category); 110 } 111 } 112 113 unsigned getID(StringRef CategoryString) { 114 return CategoryIDs[CategoryString]; 115 } 116 117 typedef std::vector<std::string>::iterator iterator; 118 iterator begin() { return CategoryStrings.begin(); } 119 iterator end() { return CategoryStrings.end(); } 120 }; 121 122 struct GroupInfo { 123 std::vector<const Record*> DiagsInGroup; 124 std::vector<std::string> SubGroups; 125 unsigned IDNo; 126 }; 127 } // end anonymous namespace. 128 129 /// \brief Invert the 1-[0/1] mapping of diags to group into a one to many 130 /// mapping of groups to diags in the group. 131 static void groupDiagnostics(const std::vector<Record*> &Diags, 132 const std::vector<Record*> &DiagGroups, 133 std::map<std::string, GroupInfo> &DiagsInGroup) { 134 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 135 const Record *R = Diags[i]; 136 DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group")); 137 if (DI == 0) continue; 138 std::string GroupName = DI->getDef()->getValueAsString("GroupName"); 139 DiagsInGroup[GroupName].DiagsInGroup.push_back(R); 140 } 141 142 // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty 143 // groups (these are warnings that GCC supports that clang never produces). 144 for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { 145 Record *Group = DiagGroups[i]; 146 GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; 147 148 std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups"); 149 for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) 150 GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName")); 151 } 152 153 // Assign unique ID numbers to the groups. 154 unsigned IDNo = 0; 155 for (std::map<std::string, GroupInfo>::iterator 156 I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo) 157 I->second.IDNo = IDNo; 158 } 159 160 //===----------------------------------------------------------------------===// 161 // Warning Tables (.inc file) generation. 162 //===----------------------------------------------------------------------===// 163 164 void ClangDiagsDefsEmitter::run(raw_ostream &OS) { 165 // Write the #if guard 166 if (!Component.empty()) { 167 std::string ComponentName = StringRef(Component).upper(); 168 OS << "#ifdef " << ComponentName << "START\n"; 169 OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName 170 << ",\n"; 171 OS << "#undef " << ComponentName << "START\n"; 172 OS << "#endif\n\n"; 173 } 174 175 const std::vector<Record*> &Diags = 176 Records.getAllDerivedDefinitions("Diagnostic"); 177 178 std::vector<Record*> DiagGroups 179 = Records.getAllDerivedDefinitions("DiagGroup"); 180 181 std::map<std::string, GroupInfo> DiagsInGroup; 182 groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 183 184 DiagCategoryIDMap CategoryIDs(Records); 185 DiagGroupParentMap DGParentMap(Records); 186 187 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 188 const Record &R = *Diags[i]; 189 // Filter by component. 190 if (!Component.empty() && Component != R.getValueAsString("Component")) 191 continue; 192 193 OS << "DIAG(" << R.getName() << ", "; 194 OS << R.getValueAsDef("Class")->getName(); 195 OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName(); 196 197 // Description string. 198 OS << ", \""; 199 OS.write_escaped(R.getValueAsString("Text")) << '"'; 200 201 // Warning associated with the diagnostic. This is stored as an index into 202 // the alphabetically sorted warning table. 203 if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) { 204 std::map<std::string, GroupInfo>::iterator I = 205 DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName")); 206 assert(I != DiagsInGroup.end()); 207 OS << ", " << I->second.IDNo; 208 } else { 209 OS << ", 0"; 210 } 211 212 // SFINAE bit 213 if (R.getValueAsBit("SFINAE")) 214 OS << ", true"; 215 else 216 OS << ", false"; 217 218 // Access control bit 219 if (R.getValueAsBit("AccessControl")) 220 OS << ", true"; 221 else 222 OS << ", false"; 223 224 // FIXME: This condition is just to avoid temporary revlock, it can be 225 // removed. 226 if (R.getValue("WarningNoWerror")) { 227 // Default warning has no Werror bit. 228 if (R.getValueAsBit("WarningNoWerror")) 229 OS << ", true"; 230 else 231 OS << ", false"; 232 233 // Default warning show in system header bit. 234 if (R.getValueAsBit("WarningShowInSystemHeader")) 235 OS << ", true"; 236 else 237 OS << ", false"; 238 } 239 240 // Category number. 241 OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap)); 242 OS << ")\n"; 243 } 244 } 245 246 //===----------------------------------------------------------------------===// 247 // Warning Group Tables generation 248 //===----------------------------------------------------------------------===// 249 250 static std::string getDiagCategoryEnum(llvm::StringRef name) { 251 if (name.empty()) 252 return "DiagCat_None"; 253 SmallString<256> enumName = llvm::StringRef("DiagCat_"); 254 for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I) 255 enumName += isalnum(*I) ? *I : '_'; 256 return enumName.str(); 257 } 258 259 void ClangDiagGroupsEmitter::run(raw_ostream &OS) { 260 // Compute a mapping from a DiagGroup to all of its parents. 261 DiagGroupParentMap DGParentMap(Records); 262 263 std::vector<Record*> Diags = 264 Records.getAllDerivedDefinitions("Diagnostic"); 265 266 std::vector<Record*> DiagGroups 267 = Records.getAllDerivedDefinitions("DiagGroup"); 268 269 std::map<std::string, GroupInfo> DiagsInGroup; 270 groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 271 272 // Walk through the groups emitting an array for each diagnostic of the diags 273 // that are mapped to. 274 OS << "\n#ifdef GET_DIAG_ARRAYS\n"; 275 unsigned MaxLen = 0; 276 for (std::map<std::string, GroupInfo>::iterator 277 I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { 278 MaxLen = std::max(MaxLen, (unsigned)I->first.size()); 279 280 std::vector<const Record*> &V = I->second.DiagsInGroup; 281 if (!V.empty()) { 282 OS << "static const short DiagArray" << I->second.IDNo << "[] = { "; 283 for (unsigned i = 0, e = V.size(); i != e; ++i) 284 OS << "diag::" << V[i]->getName() << ", "; 285 OS << "-1 };\n"; 286 } 287 288 const std::vector<std::string> &SubGroups = I->second.SubGroups; 289 if (!SubGroups.empty()) { 290 OS << "static const short DiagSubGroup" << I->second.IDNo << "[] = { "; 291 for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) { 292 std::map<std::string, GroupInfo>::iterator RI = 293 DiagsInGroup.find(SubGroups[i]); 294 assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 295 OS << RI->second.IDNo << ", "; 296 } 297 OS << "-1 };\n"; 298 } 299 } 300 OS << "#endif // GET_DIAG_ARRAYS\n\n"; 301 302 // Emit the table now. 303 OS << "\n#ifdef GET_DIAG_TABLE\n"; 304 for (std::map<std::string, GroupInfo>::iterator 305 I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { 306 // Group option string. 307 OS << " { "; 308 OS << I->first.size() << ", "; 309 OS << "\""; 310 if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz" 311 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 312 "0123456789!@#$%^*-+=:?")!=std::string::npos) 313 throw "Invalid character in diagnostic group '" + I->first + "'"; 314 OS.write_escaped(I->first) << "\"," 315 << std::string(MaxLen-I->first.size()+1, ' '); 316 317 // Diagnostics in the group. 318 if (I->second.DiagsInGroup.empty()) 319 OS << "0, "; 320 else 321 OS << "DiagArray" << I->second.IDNo << ", "; 322 323 // Subgroups. 324 if (I->second.SubGroups.empty()) 325 OS << 0; 326 else 327 OS << "DiagSubGroup" << I->second.IDNo; 328 OS << " },\n"; 329 } 330 OS << "#endif // GET_DIAG_TABLE\n\n"; 331 332 // Emit the category table next. 333 DiagCategoryIDMap CategoriesByID(Records); 334 OS << "\n#ifdef GET_CATEGORY_TABLE\n"; 335 for (DiagCategoryIDMap::iterator I = CategoriesByID.begin(), 336 E = CategoriesByID.end(); I != E; ++I) 337 OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n"; 338 OS << "#endif // GET_CATEGORY_TABLE\n\n"; 339 } 340 341 //===----------------------------------------------------------------------===// 342 // Diagnostic name index generation 343 //===----------------------------------------------------------------------===// 344 345 namespace { 346 struct RecordIndexElement 347 { 348 RecordIndexElement() {} 349 explicit RecordIndexElement(Record const &R): 350 Name(R.getName()) {} 351 352 std::string Name; 353 }; 354 355 struct RecordIndexElementSorter : 356 public std::binary_function<RecordIndexElement, RecordIndexElement, bool> { 357 358 bool operator()(RecordIndexElement const &Lhs, 359 RecordIndexElement const &Rhs) const { 360 return Lhs.Name < Rhs.Name; 361 } 362 363 }; 364 365 } // end anonymous namespace. 366 367 void ClangDiagsIndexNameEmitter::run(raw_ostream &OS) { 368 const std::vector<Record*> &Diags = 369 Records.getAllDerivedDefinitions("Diagnostic"); 370 371 std::vector<RecordIndexElement> Index; 372 Index.reserve(Diags.size()); 373 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 374 const Record &R = *(Diags[i]); 375 Index.push_back(RecordIndexElement(R)); 376 } 377 378 std::sort(Index.begin(), Index.end(), RecordIndexElementSorter()); 379 380 for (unsigned i = 0, e = Index.size(); i != e; ++i) { 381 const RecordIndexElement &R = Index[i]; 382 383 OS << "DIAG_NAME_INDEX(" << R.Name << ")\n"; 384 } 385 } 386