1 1.1 joerg //=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*- 2 1.1 joerg // 3 1.1 joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 1.1 joerg // See https://llvm.org/LICENSE.txt for license information. 5 1.1 joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 1.1 joerg // 7 1.1 joerg //===----------------------------------------------------------------------===// 8 1.1 joerg // 9 1.1 joerg // These tablegen backends emit Clang diagnostics tables. 10 1.1 joerg // 11 1.1 joerg //===----------------------------------------------------------------------===// 12 1.1 joerg 13 1.1 joerg #include "TableGenBackends.h" 14 1.1 joerg #include "llvm/ADT/DenseSet.h" 15 1.1 joerg #include "llvm/ADT/Optional.h" 16 1.1 joerg #include "llvm/ADT/PointerUnion.h" 17 1.1 joerg #include "llvm/ADT/STLExtras.h" 18 1.1 joerg #include "llvm/ADT/SmallPtrSet.h" 19 1.1 joerg #include "llvm/ADT/SmallString.h" 20 1.1 joerg #include "llvm/ADT/SmallVector.h" 21 1.1 joerg #include "llvm/ADT/StringMap.h" 22 1.1.1.2 joerg #include "llvm/ADT/StringSwitch.h" 23 1.1 joerg #include "llvm/ADT/Twine.h" 24 1.1 joerg #include "llvm/Support/Casting.h" 25 1.1 joerg #include "llvm/TableGen/Error.h" 26 1.1 joerg #include "llvm/TableGen/Record.h" 27 1.1 joerg #include "llvm/TableGen/StringToOffsetTable.h" 28 1.1 joerg #include "llvm/TableGen/TableGenBackend.h" 29 1.1 joerg #include <algorithm> 30 1.1 joerg #include <cctype> 31 1.1 joerg #include <functional> 32 1.1 joerg #include <map> 33 1.1 joerg #include <set> 34 1.1 joerg using namespace llvm; 35 1.1 joerg 36 1.1 joerg //===----------------------------------------------------------------------===// 37 1.1 joerg // Diagnostic category computation code. 38 1.1 joerg //===----------------------------------------------------------------------===// 39 1.1 joerg 40 1.1 joerg namespace { 41 1.1 joerg class DiagGroupParentMap { 42 1.1 joerg RecordKeeper &Records; 43 1.1 joerg std::map<const Record*, std::vector<Record*> > Mapping; 44 1.1 joerg public: 45 1.1 joerg DiagGroupParentMap(RecordKeeper &records) : Records(records) { 46 1.1 joerg std::vector<Record*> DiagGroups 47 1.1 joerg = Records.getAllDerivedDefinitions("DiagGroup"); 48 1.1 joerg for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { 49 1.1 joerg std::vector<Record*> SubGroups = 50 1.1 joerg DiagGroups[i]->getValueAsListOfDefs("SubGroups"); 51 1.1 joerg for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) 52 1.1 joerg Mapping[SubGroups[j]].push_back(DiagGroups[i]); 53 1.1 joerg } 54 1.1 joerg } 55 1.1 joerg 56 1.1 joerg const std::vector<Record*> &getParents(const Record *Group) { 57 1.1 joerg return Mapping[Group]; 58 1.1 joerg } 59 1.1 joerg }; 60 1.1 joerg } // end anonymous namespace. 61 1.1 joerg 62 1.1 joerg static std::string 63 1.1 joerg getCategoryFromDiagGroup(const Record *Group, 64 1.1 joerg DiagGroupParentMap &DiagGroupParents) { 65 1.1 joerg // If the DiagGroup has a category, return it. 66 1.1.1.2 joerg std::string CatName = std::string(Group->getValueAsString("CategoryName")); 67 1.1 joerg if (!CatName.empty()) return CatName; 68 1.1 joerg 69 1.1 joerg // The diag group may the subgroup of one or more other diagnostic groups, 70 1.1 joerg // check these for a category as well. 71 1.1 joerg const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 72 1.1 joerg for (unsigned i = 0, e = Parents.size(); i != e; ++i) { 73 1.1 joerg CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents); 74 1.1 joerg if (!CatName.empty()) return CatName; 75 1.1 joerg } 76 1.1 joerg return ""; 77 1.1 joerg } 78 1.1 joerg 79 1.1 joerg /// getDiagnosticCategory - Return the category that the specified diagnostic 80 1.1 joerg /// lives in. 81 1.1 joerg static std::string getDiagnosticCategory(const Record *R, 82 1.1 joerg DiagGroupParentMap &DiagGroupParents) { 83 1.1 joerg // If the diagnostic is in a group, and that group has a category, use it. 84 1.1 joerg if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) { 85 1.1 joerg // Check the diagnostic's diag group for a category. 86 1.1 joerg std::string CatName = getCategoryFromDiagGroup(Group->getDef(), 87 1.1 joerg DiagGroupParents); 88 1.1 joerg if (!CatName.empty()) return CatName; 89 1.1 joerg } 90 1.1 joerg 91 1.1 joerg // If the diagnostic itself has a category, get it. 92 1.1.1.2 joerg return std::string(R->getValueAsString("CategoryName")); 93 1.1 joerg } 94 1.1 joerg 95 1.1 joerg namespace { 96 1.1 joerg class DiagCategoryIDMap { 97 1.1 joerg RecordKeeper &Records; 98 1.1 joerg StringMap<unsigned> CategoryIDs; 99 1.1 joerg std::vector<std::string> CategoryStrings; 100 1.1 joerg public: 101 1.1 joerg DiagCategoryIDMap(RecordKeeper &records) : Records(records) { 102 1.1 joerg DiagGroupParentMap ParentInfo(Records); 103 1.1 joerg 104 1.1 joerg // The zero'th category is "". 105 1.1 joerg CategoryStrings.push_back(""); 106 1.1 joerg CategoryIDs[""] = 0; 107 1.1 joerg 108 1.1 joerg std::vector<Record*> Diags = 109 1.1 joerg Records.getAllDerivedDefinitions("Diagnostic"); 110 1.1 joerg for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 111 1.1 joerg std::string Category = getDiagnosticCategory(Diags[i], ParentInfo); 112 1.1 joerg if (Category.empty()) continue; // Skip diags with no category. 113 1.1 joerg 114 1.1 joerg unsigned &ID = CategoryIDs[Category]; 115 1.1 joerg if (ID != 0) continue; // Already seen. 116 1.1 joerg 117 1.1 joerg ID = CategoryStrings.size(); 118 1.1 joerg CategoryStrings.push_back(Category); 119 1.1 joerg } 120 1.1 joerg } 121 1.1 joerg 122 1.1 joerg unsigned getID(StringRef CategoryString) { 123 1.1 joerg return CategoryIDs[CategoryString]; 124 1.1 joerg } 125 1.1 joerg 126 1.1 joerg typedef std::vector<std::string>::const_iterator const_iterator; 127 1.1 joerg const_iterator begin() const { return CategoryStrings.begin(); } 128 1.1 joerg const_iterator end() const { return CategoryStrings.end(); } 129 1.1 joerg }; 130 1.1 joerg 131 1.1 joerg struct GroupInfo { 132 1.1 joerg std::vector<const Record*> DiagsInGroup; 133 1.1 joerg std::vector<std::string> SubGroups; 134 1.1 joerg unsigned IDNo; 135 1.1 joerg 136 1.1.1.2 joerg llvm::SmallVector<const Record *, 1> Defs; 137 1.1 joerg 138 1.1.1.2 joerg GroupInfo() : IDNo(0) {} 139 1.1 joerg }; 140 1.1 joerg } // end anonymous namespace. 141 1.1 joerg 142 1.1 joerg static bool beforeThanCompare(const Record *LHS, const Record *RHS) { 143 1.1 joerg assert(!LHS->getLoc().empty() && !RHS->getLoc().empty()); 144 1.1 joerg return 145 1.1 joerg LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer(); 146 1.1 joerg } 147 1.1 joerg 148 1.1 joerg static bool diagGroupBeforeByName(const Record *LHS, const Record *RHS) { 149 1.1 joerg return LHS->getValueAsString("GroupName") < 150 1.1 joerg RHS->getValueAsString("GroupName"); 151 1.1 joerg } 152 1.1 joerg 153 1.1 joerg /// Invert the 1-[0/1] mapping of diags to group into a one to many 154 1.1 joerg /// mapping of groups to diags in the group. 155 1.1 joerg static void groupDiagnostics(const std::vector<Record*> &Diags, 156 1.1 joerg const std::vector<Record*> &DiagGroups, 157 1.1 joerg std::map<std::string, GroupInfo> &DiagsInGroup) { 158 1.1 joerg 159 1.1 joerg for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 160 1.1 joerg const Record *R = Diags[i]; 161 1.1 joerg DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group")); 162 1.1 joerg if (!DI) 163 1.1 joerg continue; 164 1.1 joerg assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" && 165 1.1 joerg "Note can't be in a DiagGroup"); 166 1.1.1.2 joerg std::string GroupName = 167 1.1.1.2 joerg std::string(DI->getDef()->getValueAsString("GroupName")); 168 1.1 joerg DiagsInGroup[GroupName].DiagsInGroup.push_back(R); 169 1.1 joerg } 170 1.1 joerg 171 1.1 joerg // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty 172 1.1 joerg // groups (these are warnings that GCC supports that clang never produces). 173 1.1 joerg for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { 174 1.1 joerg Record *Group = DiagGroups[i]; 175 1.1.1.2 joerg GroupInfo &GI = 176 1.1.1.2 joerg DiagsInGroup[std::string(Group->getValueAsString("GroupName"))]; 177 1.1.1.2 joerg GI.Defs.push_back(Group); 178 1.1 joerg 179 1.1 joerg std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups"); 180 1.1 joerg for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) 181 1.1.1.2 joerg GI.SubGroups.push_back( 182 1.1.1.2 joerg std::string(SubGroups[j]->getValueAsString("GroupName"))); 183 1.1 joerg } 184 1.1 joerg 185 1.1 joerg // Assign unique ID numbers to the groups. 186 1.1 joerg unsigned IDNo = 0; 187 1.1 joerg for (std::map<std::string, GroupInfo>::iterator 188 1.1 joerg I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo) 189 1.1 joerg I->second.IDNo = IDNo; 190 1.1 joerg 191 1.1.1.2 joerg // Warn if the same group is defined more than once (including implicitly). 192 1.1.1.2 joerg for (auto &Group : DiagsInGroup) { 193 1.1.1.2 joerg if (Group.second.Defs.size() == 1 && 194 1.1.1.2 joerg (!Group.second.Defs.front()->isAnonymous() || 195 1.1.1.2 joerg Group.second.DiagsInGroup.size() <= 1)) 196 1.1.1.2 joerg continue; 197 1.1 joerg 198 1.1.1.2 joerg bool First = true; 199 1.1.1.2 joerg for (const Record *Def : Group.second.Defs) { 200 1.1.1.2 joerg // Skip implicit definitions from diagnostics; we'll report those 201 1.1.1.2 joerg // separately below. 202 1.1.1.2 joerg bool IsImplicit = false; 203 1.1.1.2 joerg for (const Record *Diag : Group.second.DiagsInGroup) { 204 1.1.1.2 joerg if (cast<DefInit>(Diag->getValueInit("Group"))->getDef() == Def) { 205 1.1.1.2 joerg IsImplicit = true; 206 1.1.1.2 joerg break; 207 1.1.1.2 joerg } 208 1.1.1.2 joerg } 209 1.1.1.2 joerg if (IsImplicit) 210 1.1.1.2 joerg continue; 211 1.1 joerg 212 1.1.1.2 joerg llvm::SMLoc Loc = Def->getLoc().front(); 213 1.1.1.2 joerg if (First) { 214 1.1.1.2 joerg SrcMgr.PrintMessage(Loc, SourceMgr::DK_Error, 215 1.1.1.2 joerg Twine("group '") + Group.first + 216 1.1.1.2 joerg "' is defined more than once"); 217 1.1.1.2 joerg First = false; 218 1.1.1.2 joerg } else { 219 1.1.1.2 joerg SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note, "also defined here"); 220 1.1 joerg } 221 1.1.1.2 joerg } 222 1.1.1.2 joerg 223 1.1.1.2 joerg for (const Record *Diag : Group.second.DiagsInGroup) { 224 1.1.1.2 joerg if (!cast<DefInit>(Diag->getValueInit("Group"))->getDef()->isAnonymous()) 225 1.1.1.2 joerg continue; 226 1.1.1.2 joerg 227 1.1.1.2 joerg llvm::SMLoc Loc = Diag->getLoc().front(); 228 1.1.1.2 joerg if (First) { 229 1.1.1.2 joerg SrcMgr.PrintMessage(Loc, SourceMgr::DK_Error, 230 1.1.1.2 joerg Twine("group '") + Group.first + 231 1.1.1.2 joerg "' is implicitly defined more than once"); 232 1.1.1.2 joerg First = false; 233 1.1.1.2 joerg } else { 234 1.1.1.2 joerg SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note, 235 1.1.1.2 joerg "also implicitly defined here"); 236 1.1 joerg } 237 1.1 joerg } 238 1.1 joerg } 239 1.1 joerg } 240 1.1 joerg 241 1.1 joerg //===----------------------------------------------------------------------===// 242 1.1 joerg // Infer members of -Wpedantic. 243 1.1 joerg //===----------------------------------------------------------------------===// 244 1.1 joerg 245 1.1 joerg typedef std::vector<const Record *> RecordVec; 246 1.1 joerg typedef llvm::DenseSet<const Record *> RecordSet; 247 1.1 joerg typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet; 248 1.1 joerg 249 1.1 joerg namespace { 250 1.1 joerg class InferPedantic { 251 1.1 joerg typedef llvm::DenseMap<const Record*, 252 1.1 joerg std::pair<unsigned, Optional<unsigned> > > GMap; 253 1.1 joerg 254 1.1 joerg DiagGroupParentMap &DiagGroupParents; 255 1.1 joerg const std::vector<Record*> &Diags; 256 1.1 joerg const std::vector<Record*> DiagGroups; 257 1.1 joerg std::map<std::string, GroupInfo> &DiagsInGroup; 258 1.1 joerg llvm::DenseSet<const Record*> DiagsSet; 259 1.1 joerg GMap GroupCount; 260 1.1 joerg public: 261 1.1 joerg InferPedantic(DiagGroupParentMap &DiagGroupParents, 262 1.1 joerg const std::vector<Record*> &Diags, 263 1.1 joerg const std::vector<Record*> &DiagGroups, 264 1.1 joerg std::map<std::string, GroupInfo> &DiagsInGroup) 265 1.1 joerg : DiagGroupParents(DiagGroupParents), 266 1.1 joerg Diags(Diags), 267 1.1 joerg DiagGroups(DiagGroups), 268 1.1 joerg DiagsInGroup(DiagsInGroup) {} 269 1.1 joerg 270 1.1 joerg /// Compute the set of diagnostics and groups that are immediately 271 1.1 joerg /// in -Wpedantic. 272 1.1 joerg void compute(VecOrSet DiagsInPedantic, 273 1.1 joerg VecOrSet GroupsInPedantic); 274 1.1 joerg 275 1.1 joerg private: 276 1.1 joerg /// Determine whether a group is a subgroup of another group. 277 1.1 joerg bool isSubGroupOfGroup(const Record *Group, 278 1.1 joerg llvm::StringRef RootGroupName); 279 1.1 joerg 280 1.1 joerg /// Determine if the diagnostic is an extension. 281 1.1 joerg bool isExtension(const Record *Diag); 282 1.1 joerg 283 1.1 joerg /// Determine if the diagnostic is off by default. 284 1.1 joerg bool isOffByDefault(const Record *Diag); 285 1.1 joerg 286 1.1 joerg /// Increment the count for a group, and transitively marked 287 1.1 joerg /// parent groups when appropriate. 288 1.1 joerg void markGroup(const Record *Group); 289 1.1 joerg 290 1.1 joerg /// Return true if the diagnostic is in a pedantic group. 291 1.1 joerg bool groupInPedantic(const Record *Group, bool increment = false); 292 1.1 joerg }; 293 1.1 joerg } // end anonymous namespace 294 1.1 joerg 295 1.1 joerg bool InferPedantic::isSubGroupOfGroup(const Record *Group, 296 1.1 joerg llvm::StringRef GName) { 297 1.1.1.2 joerg const std::string &GroupName = 298 1.1.1.2 joerg std::string(Group->getValueAsString("GroupName")); 299 1.1 joerg if (GName == GroupName) 300 1.1 joerg return true; 301 1.1 joerg 302 1.1 joerg const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 303 1.1 joerg for (unsigned i = 0, e = Parents.size(); i != e; ++i) 304 1.1 joerg if (isSubGroupOfGroup(Parents[i], GName)) 305 1.1 joerg return true; 306 1.1 joerg 307 1.1 joerg return false; 308 1.1 joerg } 309 1.1 joerg 310 1.1 joerg /// Determine if the diagnostic is an extension. 311 1.1 joerg bool InferPedantic::isExtension(const Record *Diag) { 312 1.1.1.2 joerg const std::string &ClsName = 313 1.1.1.2 joerg std::string(Diag->getValueAsDef("Class")->getName()); 314 1.1 joerg return ClsName == "CLASS_EXTENSION"; 315 1.1 joerg } 316 1.1 joerg 317 1.1 joerg bool InferPedantic::isOffByDefault(const Record *Diag) { 318 1.1.1.2 joerg const std::string &DefSeverity = std::string( 319 1.1.1.2 joerg Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name")); 320 1.1 joerg return DefSeverity == "Ignored"; 321 1.1 joerg } 322 1.1 joerg 323 1.1 joerg bool InferPedantic::groupInPedantic(const Record *Group, bool increment) { 324 1.1 joerg GMap::mapped_type &V = GroupCount[Group]; 325 1.1 joerg // Lazily compute the threshold value for the group count. 326 1.1 joerg if (!V.second.hasValue()) { 327 1.1.1.2 joerg const GroupInfo &GI = 328 1.1.1.2 joerg DiagsInGroup[std::string(Group->getValueAsString("GroupName"))]; 329 1.1 joerg V.second = GI.SubGroups.size() + GI.DiagsInGroup.size(); 330 1.1 joerg } 331 1.1 joerg 332 1.1 joerg if (increment) 333 1.1 joerg ++V.first; 334 1.1 joerg 335 1.1 joerg // Consider a group in -Wpendatic IFF if has at least one diagnostic 336 1.1 joerg // or subgroup AND all of those diagnostics and subgroups are covered 337 1.1 joerg // by -Wpedantic via our computation. 338 1.1 joerg return V.first != 0 && V.first == V.second.getValue(); 339 1.1 joerg } 340 1.1 joerg 341 1.1 joerg void InferPedantic::markGroup(const Record *Group) { 342 1.1 joerg // If all the diagnostics and subgroups have been marked as being 343 1.1 joerg // covered by -Wpedantic, increment the count of parent groups. Once the 344 1.1 joerg // group's count is equal to the number of subgroups and diagnostics in 345 1.1 joerg // that group, we can safely add this group to -Wpedantic. 346 1.1 joerg if (groupInPedantic(Group, /* increment */ true)) { 347 1.1 joerg const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 348 1.1 joerg for (unsigned i = 0, e = Parents.size(); i != e; ++i) 349 1.1 joerg markGroup(Parents[i]); 350 1.1 joerg } 351 1.1 joerg } 352 1.1 joerg 353 1.1 joerg void InferPedantic::compute(VecOrSet DiagsInPedantic, 354 1.1 joerg VecOrSet GroupsInPedantic) { 355 1.1 joerg // All extensions that are not on by default are implicitly in the 356 1.1 joerg // "pedantic" group. For those that aren't explicitly included in -Wpedantic, 357 1.1 joerg // mark them for consideration to be included in -Wpedantic directly. 358 1.1 joerg for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 359 1.1 joerg Record *R = Diags[i]; 360 1.1 joerg if (isExtension(R) && isOffByDefault(R)) { 361 1.1 joerg DiagsSet.insert(R); 362 1.1 joerg if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) { 363 1.1 joerg const Record *GroupRec = Group->getDef(); 364 1.1 joerg if (!isSubGroupOfGroup(GroupRec, "pedantic")) { 365 1.1 joerg markGroup(GroupRec); 366 1.1 joerg } 367 1.1 joerg } 368 1.1 joerg } 369 1.1 joerg } 370 1.1 joerg 371 1.1 joerg // Compute the set of diagnostics that are directly in -Wpedantic. We 372 1.1 joerg // march through Diags a second time to ensure the results are emitted 373 1.1 joerg // in deterministic order. 374 1.1 joerg for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 375 1.1 joerg Record *R = Diags[i]; 376 1.1 joerg if (!DiagsSet.count(R)) 377 1.1 joerg continue; 378 1.1 joerg // Check if the group is implicitly in -Wpedantic. If so, 379 1.1 joerg // the diagnostic should not be directly included in the -Wpedantic 380 1.1 joerg // diagnostic group. 381 1.1 joerg if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) 382 1.1 joerg if (groupInPedantic(Group->getDef())) 383 1.1 joerg continue; 384 1.1 joerg 385 1.1 joerg // The diagnostic is not included in a group that is (transitively) in 386 1.1 joerg // -Wpedantic. Include it in -Wpedantic directly. 387 1.1 joerg if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>()) 388 1.1 joerg V->push_back(R); 389 1.1 joerg else { 390 1.1 joerg DiagsInPedantic.get<RecordSet*>()->insert(R); 391 1.1 joerg } 392 1.1 joerg } 393 1.1 joerg 394 1.1 joerg if (!GroupsInPedantic) 395 1.1 joerg return; 396 1.1 joerg 397 1.1 joerg // Compute the set of groups that are directly in -Wpedantic. We 398 1.1 joerg // march through the groups to ensure the results are emitted 399 1.1 joerg /// in a deterministc order. 400 1.1 joerg for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) { 401 1.1 joerg Record *Group = DiagGroups[i]; 402 1.1 joerg if (!groupInPedantic(Group)) 403 1.1 joerg continue; 404 1.1 joerg 405 1.1 joerg unsigned ParentsInPedantic = 0; 406 1.1 joerg const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 407 1.1 joerg for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) { 408 1.1 joerg if (groupInPedantic(Parents[j])) 409 1.1 joerg ++ParentsInPedantic; 410 1.1 joerg } 411 1.1 joerg // If all the parents are in -Wpedantic, this means that this diagnostic 412 1.1 joerg // group will be indirectly included by -Wpedantic already. In that 413 1.1 joerg // case, do not add it directly to -Wpedantic. If the group has no 414 1.1 joerg // parents, obviously it should go into -Wpedantic. 415 1.1 joerg if (Parents.size() > 0 && ParentsInPedantic == Parents.size()) 416 1.1 joerg continue; 417 1.1 joerg 418 1.1 joerg if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>()) 419 1.1 joerg V->push_back(Group); 420 1.1 joerg else { 421 1.1 joerg GroupsInPedantic.get<RecordSet*>()->insert(Group); 422 1.1 joerg } 423 1.1 joerg } 424 1.1 joerg } 425 1.1 joerg 426 1.1 joerg namespace { 427 1.1 joerg enum PieceKind { 428 1.1 joerg MultiPieceClass, 429 1.1 joerg TextPieceClass, 430 1.1 joerg PlaceholderPieceClass, 431 1.1 joerg SelectPieceClass, 432 1.1 joerg PluralPieceClass, 433 1.1 joerg DiffPieceClass, 434 1.1 joerg SubstitutionPieceClass, 435 1.1 joerg }; 436 1.1 joerg 437 1.1 joerg enum ModifierType { 438 1.1 joerg MT_Unknown, 439 1.1 joerg MT_Placeholder, 440 1.1 joerg MT_Select, 441 1.1 joerg MT_Sub, 442 1.1 joerg MT_Plural, 443 1.1 joerg MT_Diff, 444 1.1 joerg MT_Ordinal, 445 1.1 joerg MT_S, 446 1.1 joerg MT_Q, 447 1.1 joerg MT_ObjCClass, 448 1.1 joerg MT_ObjCInstance, 449 1.1 joerg }; 450 1.1 joerg 451 1.1 joerg static StringRef getModifierName(ModifierType MT) { 452 1.1 joerg switch (MT) { 453 1.1 joerg case MT_Select: 454 1.1 joerg return "select"; 455 1.1 joerg case MT_Sub: 456 1.1 joerg return "sub"; 457 1.1 joerg case MT_Diff: 458 1.1 joerg return "diff"; 459 1.1 joerg case MT_Plural: 460 1.1 joerg return "plural"; 461 1.1 joerg case MT_Ordinal: 462 1.1 joerg return "ordinal"; 463 1.1 joerg case MT_S: 464 1.1 joerg return "s"; 465 1.1 joerg case MT_Q: 466 1.1 joerg return "q"; 467 1.1 joerg case MT_Placeholder: 468 1.1 joerg return ""; 469 1.1 joerg case MT_ObjCClass: 470 1.1 joerg return "objcclass"; 471 1.1 joerg case MT_ObjCInstance: 472 1.1 joerg return "objcinstance"; 473 1.1 joerg case MT_Unknown: 474 1.1 joerg llvm_unreachable("invalid modifier type"); 475 1.1 joerg } 476 1.1 joerg // Unhandled case 477 1.1 joerg llvm_unreachable("invalid modifier type"); 478 1.1 joerg } 479 1.1 joerg 480 1.1 joerg struct Piece { 481 1.1 joerg // This type and its derived classes are move-only. 482 1.1 joerg Piece(PieceKind Kind) : ClassKind(Kind) {} 483 1.1 joerg Piece(Piece const &O) = delete; 484 1.1 joerg Piece &operator=(Piece const &) = delete; 485 1.1 joerg virtual ~Piece() {} 486 1.1 joerg 487 1.1 joerg PieceKind getPieceClass() const { return ClassKind; } 488 1.1 joerg static bool classof(const Piece *) { return true; } 489 1.1 joerg 490 1.1 joerg private: 491 1.1 joerg PieceKind ClassKind; 492 1.1 joerg }; 493 1.1 joerg 494 1.1 joerg struct MultiPiece : Piece { 495 1.1 joerg MultiPiece() : Piece(MultiPieceClass) {} 496 1.1 joerg MultiPiece(std::vector<Piece *> Pieces) 497 1.1 joerg : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {} 498 1.1 joerg 499 1.1 joerg std::vector<Piece *> Pieces; 500 1.1 joerg 501 1.1 joerg static bool classof(const Piece *P) { 502 1.1 joerg return P->getPieceClass() == MultiPieceClass; 503 1.1 joerg } 504 1.1 joerg }; 505 1.1 joerg 506 1.1 joerg struct TextPiece : Piece { 507 1.1 joerg StringRef Role; 508 1.1 joerg std::string Text; 509 1.1 joerg TextPiece(StringRef Text, StringRef Role = "") 510 1.1 joerg : Piece(TextPieceClass), Role(Role), Text(Text.str()) {} 511 1.1 joerg 512 1.1 joerg static bool classof(const Piece *P) { 513 1.1 joerg return P->getPieceClass() == TextPieceClass; 514 1.1 joerg } 515 1.1 joerg }; 516 1.1 joerg 517 1.1 joerg struct PlaceholderPiece : Piece { 518 1.1 joerg ModifierType Kind; 519 1.1 joerg int Index; 520 1.1 joerg PlaceholderPiece(ModifierType Kind, int Index) 521 1.1 joerg : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {} 522 1.1 joerg 523 1.1 joerg static bool classof(const Piece *P) { 524 1.1 joerg return P->getPieceClass() == PlaceholderPieceClass; 525 1.1 joerg } 526 1.1 joerg }; 527 1.1 joerg 528 1.1 joerg struct SelectPiece : Piece { 529 1.1 joerg protected: 530 1.1 joerg SelectPiece(PieceKind Kind, ModifierType ModKind) 531 1.1 joerg : Piece(Kind), ModKind(ModKind) {} 532 1.1 joerg 533 1.1 joerg public: 534 1.1 joerg SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {} 535 1.1 joerg 536 1.1 joerg ModifierType ModKind; 537 1.1 joerg std::vector<Piece *> Options; 538 1.1.1.2 joerg int Index = 0; 539 1.1 joerg 540 1.1 joerg static bool classof(const Piece *P) { 541 1.1 joerg return P->getPieceClass() == SelectPieceClass || 542 1.1 joerg P->getPieceClass() == PluralPieceClass; 543 1.1 joerg } 544 1.1 joerg }; 545 1.1 joerg 546 1.1 joerg struct PluralPiece : SelectPiece { 547 1.1 joerg PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {} 548 1.1 joerg 549 1.1 joerg std::vector<Piece *> OptionPrefixes; 550 1.1.1.2 joerg int Index = 0; 551 1.1 joerg 552 1.1 joerg static bool classof(const Piece *P) { 553 1.1 joerg return P->getPieceClass() == PluralPieceClass; 554 1.1 joerg } 555 1.1 joerg }; 556 1.1 joerg 557 1.1 joerg struct DiffPiece : Piece { 558 1.1 joerg DiffPiece() : Piece(DiffPieceClass) {} 559 1.1 joerg 560 1.1.1.2 joerg Piece *Parts[4] = {}; 561 1.1 joerg int Indexes[2] = {}; 562 1.1 joerg 563 1.1 joerg static bool classof(const Piece *P) { 564 1.1 joerg return P->getPieceClass() == DiffPieceClass; 565 1.1 joerg } 566 1.1 joerg }; 567 1.1 joerg 568 1.1 joerg struct SubstitutionPiece : Piece { 569 1.1 joerg SubstitutionPiece() : Piece(SubstitutionPieceClass) {} 570 1.1 joerg 571 1.1 joerg std::string Name; 572 1.1 joerg std::vector<int> Modifiers; 573 1.1 joerg 574 1.1 joerg static bool classof(const Piece *P) { 575 1.1 joerg return P->getPieceClass() == SubstitutionPieceClass; 576 1.1 joerg } 577 1.1 joerg }; 578 1.1 joerg 579 1.1 joerg /// Diagnostic text, parsed into pieces. 580 1.1 joerg 581 1.1 joerg 582 1.1 joerg struct DiagnosticTextBuilder { 583 1.1 joerg DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete; 584 1.1 joerg DiagnosticTextBuilder &operator=(DiagnosticTextBuilder const &) = delete; 585 1.1 joerg 586 1.1 joerg DiagnosticTextBuilder(RecordKeeper &Records) { 587 1.1 joerg // Build up the list of substitution records. 588 1.1 joerg for (auto *S : Records.getAllDerivedDefinitions("TextSubstitution")) { 589 1.1 joerg EvaluatingRecordGuard Guard(&EvaluatingRecord, S); 590 1.1 joerg Substitutions.try_emplace( 591 1.1 joerg S->getName(), DiagText(*this, S->getValueAsString("Substitution"))); 592 1.1 joerg } 593 1.1 joerg 594 1.1 joerg // Check that no diagnostic definitions have the same name as a 595 1.1 joerg // substitution. 596 1.1 joerg for (Record *Diag : Records.getAllDerivedDefinitions("Diagnostic")) { 597 1.1 joerg StringRef Name = Diag->getName(); 598 1.1 joerg if (Substitutions.count(Name)) 599 1.1 joerg llvm::PrintFatalError( 600 1.1 joerg Diag->getLoc(), 601 1.1 joerg "Diagnostic '" + Name + 602 1.1 joerg "' has same name as TextSubstitution definition"); 603 1.1 joerg } 604 1.1 joerg } 605 1.1 joerg 606 1.1 joerg std::vector<std::string> buildForDocumentation(StringRef Role, 607 1.1 joerg const Record *R); 608 1.1 joerg std::string buildForDefinition(const Record *R); 609 1.1 joerg 610 1.1 joerg Piece *getSubstitution(SubstitutionPiece *S) const { 611 1.1 joerg auto It = Substitutions.find(S->Name); 612 1.1 joerg if (It == Substitutions.end()) 613 1.1 joerg PrintFatalError("Failed to find substitution with name: " + S->Name); 614 1.1 joerg return It->second.Root; 615 1.1 joerg } 616 1.1 joerg 617 1.1 joerg LLVM_ATTRIBUTE_NORETURN void PrintFatalError(llvm::Twine const &Msg) const { 618 1.1 joerg assert(EvaluatingRecord && "not evaluating a record?"); 619 1.1 joerg llvm::PrintFatalError(EvaluatingRecord->getLoc(), Msg); 620 1.1 joerg } 621 1.1 joerg 622 1.1 joerg private: 623 1.1 joerg struct DiagText { 624 1.1 joerg DiagnosticTextBuilder &Builder; 625 1.1 joerg std::vector<Piece *> AllocatedPieces; 626 1.1 joerg Piece *Root = nullptr; 627 1.1 joerg 628 1.1 joerg template <class T, class... Args> T *New(Args &&... args) { 629 1.1 joerg static_assert(std::is_base_of<Piece, T>::value, "must be piece"); 630 1.1 joerg T *Mem = new T(std::forward<Args>(args)...); 631 1.1 joerg AllocatedPieces.push_back(Mem); 632 1.1 joerg return Mem; 633 1.1 joerg } 634 1.1 joerg 635 1.1 joerg DiagText(DiagnosticTextBuilder &Builder, StringRef Text) 636 1.1.1.2 joerg : Builder(Builder), Root(parseDiagText(Text, StopAt::End)) {} 637 1.1 joerg 638 1.1.1.2 joerg enum class StopAt { 639 1.1.1.2 joerg // Parse until the end of the string. 640 1.1.1.2 joerg End, 641 1.1.1.2 joerg // Additionally stop if we hit a non-nested '|' or '}'. 642 1.1.1.2 joerg PipeOrCloseBrace, 643 1.1.1.2 joerg // Additionally stop if we hit a non-nested '$'. 644 1.1.1.2 joerg Dollar, 645 1.1.1.2 joerg }; 646 1.1.1.2 joerg 647 1.1.1.2 joerg Piece *parseDiagText(StringRef &Text, StopAt Stop); 648 1.1 joerg int parseModifier(StringRef &) const; 649 1.1 joerg 650 1.1 joerg public: 651 1.1 joerg DiagText(DiagText &&O) noexcept 652 1.1 joerg : Builder(O.Builder), AllocatedPieces(std::move(O.AllocatedPieces)), 653 1.1 joerg Root(O.Root) { 654 1.1 joerg O.Root = nullptr; 655 1.1 joerg } 656 1.1 joerg 657 1.1 joerg ~DiagText() { 658 1.1 joerg for (Piece *P : AllocatedPieces) 659 1.1 joerg delete P; 660 1.1 joerg } 661 1.1 joerg }; 662 1.1 joerg 663 1.1 joerg private: 664 1.1 joerg const Record *EvaluatingRecord = nullptr; 665 1.1 joerg struct EvaluatingRecordGuard { 666 1.1 joerg EvaluatingRecordGuard(const Record **Dest, const Record *New) 667 1.1 joerg : Dest(Dest), Old(*Dest) { 668 1.1 joerg *Dest = New; 669 1.1 joerg } 670 1.1 joerg ~EvaluatingRecordGuard() { *Dest = Old; } 671 1.1 joerg const Record **Dest; 672 1.1 joerg const Record *Old; 673 1.1 joerg }; 674 1.1 joerg 675 1.1 joerg StringMap<DiagText> Substitutions; 676 1.1 joerg }; 677 1.1 joerg 678 1.1 joerg template <class Derived> struct DiagTextVisitor { 679 1.1 joerg using ModifierMappingsType = Optional<std::vector<int>>; 680 1.1 joerg 681 1.1 joerg private: 682 1.1 joerg Derived &getDerived() { return static_cast<Derived &>(*this); } 683 1.1 joerg 684 1.1 joerg public: 685 1.1 joerg std::vector<int> 686 1.1 joerg getSubstitutionMappings(SubstitutionPiece *P, 687 1.1 joerg const ModifierMappingsType &Mappings) const { 688 1.1 joerg std::vector<int> NewMappings; 689 1.1 joerg for (int Idx : P->Modifiers) 690 1.1 joerg NewMappings.push_back(mapIndex(Idx, Mappings)); 691 1.1 joerg return NewMappings; 692 1.1 joerg } 693 1.1 joerg 694 1.1 joerg struct SubstitutionContext { 695 1.1 joerg SubstitutionContext(DiagTextVisitor &Visitor, SubstitutionPiece *P) 696 1.1 joerg : Visitor(Visitor) { 697 1.1 joerg Substitution = Visitor.Builder.getSubstitution(P); 698 1.1 joerg OldMappings = std::move(Visitor.ModifierMappings); 699 1.1 joerg std::vector<int> NewMappings = 700 1.1 joerg Visitor.getSubstitutionMappings(P, OldMappings); 701 1.1 joerg Visitor.ModifierMappings = std::move(NewMappings); 702 1.1 joerg } 703 1.1 joerg 704 1.1 joerg ~SubstitutionContext() { 705 1.1 joerg Visitor.ModifierMappings = std::move(OldMappings); 706 1.1 joerg } 707 1.1 joerg 708 1.1 joerg private: 709 1.1 joerg DiagTextVisitor &Visitor; 710 1.1 joerg Optional<std::vector<int>> OldMappings; 711 1.1 joerg 712 1.1 joerg public: 713 1.1 joerg Piece *Substitution; 714 1.1 joerg }; 715 1.1 joerg 716 1.1 joerg public: 717 1.1 joerg DiagTextVisitor(DiagnosticTextBuilder &Builder) : Builder(Builder) {} 718 1.1 joerg 719 1.1 joerg void Visit(Piece *P) { 720 1.1 joerg switch (P->getPieceClass()) { 721 1.1 joerg #define CASE(T) \ 722 1.1 joerg case T##PieceClass: \ 723 1.1 joerg return getDerived().Visit##T(static_cast<T##Piece *>(P)) 724 1.1 joerg CASE(Multi); 725 1.1 joerg CASE(Text); 726 1.1 joerg CASE(Placeholder); 727 1.1 joerg CASE(Select); 728 1.1 joerg CASE(Plural); 729 1.1 joerg CASE(Diff); 730 1.1 joerg CASE(Substitution); 731 1.1 joerg #undef CASE 732 1.1 joerg } 733 1.1 joerg } 734 1.1 joerg 735 1.1 joerg void VisitSubstitution(SubstitutionPiece *P) { 736 1.1 joerg SubstitutionContext Guard(*this, P); 737 1.1 joerg Visit(Guard.Substitution); 738 1.1 joerg } 739 1.1 joerg 740 1.1 joerg int mapIndex(int Idx, 741 1.1 joerg ModifierMappingsType const &ModifierMappings) const { 742 1.1 joerg if (!ModifierMappings) 743 1.1 joerg return Idx; 744 1.1 joerg if (ModifierMappings->size() <= static_cast<unsigned>(Idx)) 745 1.1 joerg Builder.PrintFatalError("Modifier value '" + std::to_string(Idx) + 746 1.1 joerg "' is not valid for this mapping (has " + 747 1.1 joerg std::to_string(ModifierMappings->size()) + 748 1.1 joerg " mappings)"); 749 1.1 joerg return (*ModifierMappings)[Idx]; 750 1.1 joerg } 751 1.1 joerg 752 1.1 joerg int mapIndex(int Idx) const { 753 1.1 joerg return mapIndex(Idx, ModifierMappings); 754 1.1 joerg } 755 1.1 joerg 756 1.1 joerg protected: 757 1.1 joerg DiagnosticTextBuilder &Builder; 758 1.1 joerg ModifierMappingsType ModifierMappings; 759 1.1 joerg }; 760 1.1 joerg 761 1.1 joerg void escapeRST(StringRef Str, std::string &Out) { 762 1.1 joerg for (auto K : Str) { 763 1.1 joerg if (StringRef("`*|_[]\\").count(K)) 764 1.1 joerg Out.push_back('\\'); 765 1.1 joerg Out.push_back(K); 766 1.1 joerg } 767 1.1 joerg } 768 1.1 joerg 769 1.1 joerg template <typename It> void padToSameLength(It Begin, It End) { 770 1.1 joerg size_t Width = 0; 771 1.1 joerg for (It I = Begin; I != End; ++I) 772 1.1 joerg Width = std::max(Width, I->size()); 773 1.1 joerg for (It I = Begin; I != End; ++I) 774 1.1 joerg (*I) += std::string(Width - I->size(), ' '); 775 1.1 joerg } 776 1.1 joerg 777 1.1 joerg template <typename It> void makeTableRows(It Begin, It End) { 778 1.1 joerg if (Begin == End) 779 1.1 joerg return; 780 1.1 joerg padToSameLength(Begin, End); 781 1.1 joerg for (It I = Begin; I != End; ++I) 782 1.1 joerg *I = "|" + *I + "|"; 783 1.1 joerg } 784 1.1 joerg 785 1.1 joerg void makeRowSeparator(std::string &Str) { 786 1.1 joerg for (char &K : Str) 787 1.1 joerg K = (K == '|' ? '+' : '-'); 788 1.1 joerg } 789 1.1 joerg 790 1.1 joerg struct DiagTextDocPrinter : DiagTextVisitor<DiagTextDocPrinter> { 791 1.1 joerg using BaseTy = DiagTextVisitor<DiagTextDocPrinter>; 792 1.1 joerg DiagTextDocPrinter(DiagnosticTextBuilder &Builder, 793 1.1 joerg std::vector<std::string> &RST) 794 1.1 joerg : BaseTy(Builder), RST(RST) {} 795 1.1 joerg 796 1.1 joerg void gatherNodes( 797 1.1 joerg Piece *OrigP, const ModifierMappingsType &CurrentMappings, 798 1.1 joerg std::vector<std::pair<Piece *, ModifierMappingsType>> &Pieces) const { 799 1.1 joerg if (auto *Sub = dyn_cast<SubstitutionPiece>(OrigP)) { 800 1.1 joerg ModifierMappingsType NewMappings = 801 1.1 joerg getSubstitutionMappings(Sub, CurrentMappings); 802 1.1 joerg return gatherNodes(Builder.getSubstitution(Sub), NewMappings, Pieces); 803 1.1 joerg } 804 1.1 joerg if (auto *MD = dyn_cast<MultiPiece>(OrigP)) { 805 1.1 joerg for (Piece *Node : MD->Pieces) 806 1.1 joerg gatherNodes(Node, CurrentMappings, Pieces); 807 1.1 joerg return; 808 1.1 joerg } 809 1.1 joerg Pieces.push_back(std::make_pair(OrigP, CurrentMappings)); 810 1.1 joerg } 811 1.1 joerg 812 1.1 joerg void VisitMulti(MultiPiece *P) { 813 1.1 joerg if (P->Pieces.empty()) { 814 1.1 joerg RST.push_back(""); 815 1.1 joerg return; 816 1.1 joerg } 817 1.1 joerg 818 1.1 joerg if (P->Pieces.size() == 1) 819 1.1 joerg return Visit(P->Pieces[0]); 820 1.1 joerg 821 1.1 joerg // Flatten the list of nodes, replacing any substitution pieces with the 822 1.1 joerg // recursively flattened substituted node. 823 1.1 joerg std::vector<std::pair<Piece *, ModifierMappingsType>> Pieces; 824 1.1 joerg gatherNodes(P, ModifierMappings, Pieces); 825 1.1 joerg 826 1.1 joerg std::string EmptyLinePrefix; 827 1.1 joerg size_t Start = RST.size(); 828 1.1 joerg bool HasMultipleLines = true; 829 1.1 joerg for (const std::pair<Piece *, ModifierMappingsType> &NodePair : Pieces) { 830 1.1 joerg std::vector<std::string> Lines; 831 1.1 joerg DiagTextDocPrinter Visitor{Builder, Lines}; 832 1.1 joerg Visitor.ModifierMappings = NodePair.second; 833 1.1 joerg Visitor.Visit(NodePair.first); 834 1.1 joerg 835 1.1 joerg if (Lines.empty()) 836 1.1 joerg continue; 837 1.1 joerg 838 1.1 joerg // We need a vertical separator if either this or the previous piece is a 839 1.1 joerg // multi-line piece, or this is the last piece. 840 1.1 joerg const char *Separator = (Lines.size() > 1 || HasMultipleLines) ? "|" : ""; 841 1.1 joerg HasMultipleLines = Lines.size() > 1; 842 1.1 joerg 843 1.1 joerg if (Start + Lines.size() > RST.size()) 844 1.1 joerg RST.resize(Start + Lines.size(), EmptyLinePrefix); 845 1.1 joerg 846 1.1 joerg padToSameLength(Lines.begin(), Lines.end()); 847 1.1 joerg for (size_t I = 0; I != Lines.size(); ++I) 848 1.1 joerg RST[Start + I] += Separator + Lines[I]; 849 1.1 joerg std::string Empty(Lines[0].size(), ' '); 850 1.1 joerg for (size_t I = Start + Lines.size(); I != RST.size(); ++I) 851 1.1 joerg RST[I] += Separator + Empty; 852 1.1 joerg EmptyLinePrefix += Separator + Empty; 853 1.1 joerg } 854 1.1 joerg for (size_t I = Start; I != RST.size(); ++I) 855 1.1 joerg RST[I] += "|"; 856 1.1 joerg EmptyLinePrefix += "|"; 857 1.1 joerg 858 1.1 joerg makeRowSeparator(EmptyLinePrefix); 859 1.1 joerg RST.insert(RST.begin() + Start, EmptyLinePrefix); 860 1.1 joerg RST.insert(RST.end(), EmptyLinePrefix); 861 1.1 joerg } 862 1.1 joerg 863 1.1 joerg void VisitText(TextPiece *P) { 864 1.1 joerg RST.push_back(""); 865 1.1 joerg auto &S = RST.back(); 866 1.1 joerg 867 1.1 joerg StringRef T = P->Text; 868 1.1 joerg while (!T.empty() && T.front() == ' ') { 869 1.1 joerg RST.back() += " |nbsp| "; 870 1.1 joerg T = T.drop_front(); 871 1.1 joerg } 872 1.1 joerg 873 1.1 joerg std::string Suffix; 874 1.1 joerg while (!T.empty() && T.back() == ' ') { 875 1.1 joerg Suffix += " |nbsp| "; 876 1.1 joerg T = T.drop_back(); 877 1.1 joerg } 878 1.1 joerg 879 1.1 joerg if (!T.empty()) { 880 1.1 joerg S += ':'; 881 1.1 joerg S += P->Role; 882 1.1 joerg S += ":`"; 883 1.1 joerg escapeRST(T, S); 884 1.1 joerg S += '`'; 885 1.1 joerg } 886 1.1 joerg 887 1.1 joerg S += Suffix; 888 1.1 joerg } 889 1.1 joerg 890 1.1 joerg void VisitPlaceholder(PlaceholderPiece *P) { 891 1.1 joerg RST.push_back(std::string(":placeholder:`") + 892 1.1 joerg char('A' + mapIndex(P->Index)) + "`"); 893 1.1 joerg } 894 1.1 joerg 895 1.1 joerg void VisitSelect(SelectPiece *P) { 896 1.1 joerg std::vector<size_t> SeparatorIndexes; 897 1.1 joerg SeparatorIndexes.push_back(RST.size()); 898 1.1 joerg RST.emplace_back(); 899 1.1 joerg for (auto *O : P->Options) { 900 1.1 joerg Visit(O); 901 1.1 joerg SeparatorIndexes.push_back(RST.size()); 902 1.1 joerg RST.emplace_back(); 903 1.1 joerg } 904 1.1 joerg 905 1.1 joerg makeTableRows(RST.begin() + SeparatorIndexes.front(), 906 1.1 joerg RST.begin() + SeparatorIndexes.back() + 1); 907 1.1 joerg for (size_t I : SeparatorIndexes) 908 1.1 joerg makeRowSeparator(RST[I]); 909 1.1 joerg } 910 1.1 joerg 911 1.1 joerg void VisitPlural(PluralPiece *P) { VisitSelect(P); } 912 1.1 joerg 913 1.1.1.2 joerg void VisitDiff(DiffPiece *P) { 914 1.1.1.2 joerg // Render %diff{a $ b $ c|d}e,f as %select{a %e b %f c|d}. 915 1.1.1.2 joerg PlaceholderPiece E(MT_Placeholder, P->Indexes[0]); 916 1.1.1.2 joerg PlaceholderPiece F(MT_Placeholder, P->Indexes[1]); 917 1.1.1.2 joerg 918 1.1.1.2 joerg MultiPiece FirstOption; 919 1.1.1.2 joerg FirstOption.Pieces.push_back(P->Parts[0]); 920 1.1.1.2 joerg FirstOption.Pieces.push_back(&E); 921 1.1.1.2 joerg FirstOption.Pieces.push_back(P->Parts[1]); 922 1.1.1.2 joerg FirstOption.Pieces.push_back(&F); 923 1.1.1.2 joerg FirstOption.Pieces.push_back(P->Parts[2]); 924 1.1.1.2 joerg 925 1.1.1.2 joerg SelectPiece Select(MT_Diff); 926 1.1.1.2 joerg Select.Options.push_back(&FirstOption); 927 1.1.1.2 joerg Select.Options.push_back(P->Parts[3]); 928 1.1.1.2 joerg 929 1.1.1.2 joerg VisitSelect(&Select); 930 1.1.1.2 joerg } 931 1.1 joerg 932 1.1 joerg std::vector<std::string> &RST; 933 1.1 joerg }; 934 1.1 joerg 935 1.1 joerg struct DiagTextPrinter : DiagTextVisitor<DiagTextPrinter> { 936 1.1 joerg public: 937 1.1 joerg using BaseTy = DiagTextVisitor<DiagTextPrinter>; 938 1.1 joerg DiagTextPrinter(DiagnosticTextBuilder &Builder, std::string &Result) 939 1.1 joerg : BaseTy(Builder), Result(Result) {} 940 1.1 joerg 941 1.1 joerg void VisitMulti(MultiPiece *P) { 942 1.1 joerg for (auto *Child : P->Pieces) 943 1.1 joerg Visit(Child); 944 1.1 joerg } 945 1.1 joerg void VisitText(TextPiece *P) { Result += P->Text; } 946 1.1 joerg void VisitPlaceholder(PlaceholderPiece *P) { 947 1.1 joerg Result += "%"; 948 1.1 joerg Result += getModifierName(P->Kind); 949 1.1 joerg addInt(mapIndex(P->Index)); 950 1.1 joerg } 951 1.1 joerg void VisitSelect(SelectPiece *P) { 952 1.1 joerg Result += "%"; 953 1.1 joerg Result += getModifierName(P->ModKind); 954 1.1 joerg if (P->ModKind == MT_Select) { 955 1.1 joerg Result += "{"; 956 1.1 joerg for (auto *D : P->Options) { 957 1.1 joerg Visit(D); 958 1.1 joerg Result += '|'; 959 1.1 joerg } 960 1.1 joerg if (!P->Options.empty()) 961 1.1 joerg Result.erase(--Result.end()); 962 1.1 joerg Result += '}'; 963 1.1 joerg } 964 1.1 joerg addInt(mapIndex(P->Index)); 965 1.1 joerg } 966 1.1 joerg 967 1.1 joerg void VisitPlural(PluralPiece *P) { 968 1.1 joerg Result += "%plural{"; 969 1.1 joerg assert(P->Options.size() == P->OptionPrefixes.size()); 970 1.1 joerg for (unsigned I = 0, End = P->Options.size(); I < End; ++I) { 971 1.1 joerg if (P->OptionPrefixes[I]) 972 1.1 joerg Visit(P->OptionPrefixes[I]); 973 1.1 joerg Visit(P->Options[I]); 974 1.1 joerg Result += "|"; 975 1.1 joerg } 976 1.1 joerg if (!P->Options.empty()) 977 1.1 joerg Result.erase(--Result.end()); 978 1.1 joerg Result += '}'; 979 1.1 joerg addInt(mapIndex(P->Index)); 980 1.1 joerg } 981 1.1 joerg 982 1.1 joerg void VisitDiff(DiffPiece *P) { 983 1.1 joerg Result += "%diff{"; 984 1.1.1.2 joerg Visit(P->Parts[0]); 985 1.1.1.2 joerg Result += "$"; 986 1.1.1.2 joerg Visit(P->Parts[1]); 987 1.1.1.2 joerg Result += "$"; 988 1.1.1.2 joerg Visit(P->Parts[2]); 989 1.1 joerg Result += "|"; 990 1.1.1.2 joerg Visit(P->Parts[3]); 991 1.1 joerg Result += "}"; 992 1.1 joerg addInt(mapIndex(P->Indexes[0])); 993 1.1 joerg Result += ","; 994 1.1 joerg addInt(mapIndex(P->Indexes[1])); 995 1.1 joerg } 996 1.1 joerg 997 1.1 joerg void addInt(int Val) { Result += std::to_string(Val); } 998 1.1 joerg 999 1.1 joerg std::string &Result; 1000 1.1 joerg }; 1001 1.1 joerg 1002 1.1 joerg int DiagnosticTextBuilder::DiagText::parseModifier(StringRef &Text) const { 1003 1.1 joerg if (Text.empty() || !isdigit(Text[0])) 1004 1.1 joerg Builder.PrintFatalError("expected modifier in diagnostic"); 1005 1.1 joerg int Val = 0; 1006 1.1 joerg do { 1007 1.1 joerg Val *= 10; 1008 1.1 joerg Val += Text[0] - '0'; 1009 1.1 joerg Text = Text.drop_front(); 1010 1.1 joerg } while (!Text.empty() && isdigit(Text[0])); 1011 1.1 joerg return Val; 1012 1.1 joerg } 1013 1.1 joerg 1014 1.1 joerg Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text, 1015 1.1.1.2 joerg StopAt Stop) { 1016 1.1 joerg std::vector<Piece *> Parsed; 1017 1.1 joerg 1018 1.1.1.2 joerg constexpr llvm::StringLiteral StopSets[] = {"%", "%|}", "%|}$"}; 1019 1.1.1.2 joerg llvm::StringRef StopSet = StopSets[static_cast<int>(Stop)]; 1020 1.1.1.2 joerg 1021 1.1 joerg while (!Text.empty()) { 1022 1.1 joerg size_t End = (size_t)-2; 1023 1.1 joerg do 1024 1.1.1.2 joerg End = Text.find_first_of(StopSet, End + 2); 1025 1.1.1.2 joerg while ( 1026 1.1.1.2 joerg End < Text.size() - 1 && Text[End] == '%' && 1027 1.1.1.2 joerg (Text[End + 1] == '%' || Text[End + 1] == '|' || Text[End + 1] == '$')); 1028 1.1 joerg 1029 1.1 joerg if (End) { 1030 1.1 joerg Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext")); 1031 1.1 joerg Text = Text.slice(End, StringRef::npos); 1032 1.1 joerg if (Text.empty()) 1033 1.1 joerg break; 1034 1.1 joerg } 1035 1.1 joerg 1036 1.1.1.2 joerg if (Text[0] == '|' || Text[0] == '}' || Text[0] == '$') 1037 1.1 joerg break; 1038 1.1 joerg 1039 1.1 joerg // Drop the '%'. 1040 1.1 joerg Text = Text.drop_front(); 1041 1.1 joerg 1042 1.1 joerg // Extract the (optional) modifier. 1043 1.1 joerg size_t ModLength = Text.find_first_of("0123456789{"); 1044 1.1 joerg StringRef Modifier = Text.slice(0, ModLength); 1045 1.1 joerg Text = Text.slice(ModLength, StringRef::npos); 1046 1.1 joerg ModifierType ModType = llvm::StringSwitch<ModifierType>{Modifier} 1047 1.1 joerg .Case("select", MT_Select) 1048 1.1 joerg .Case("sub", MT_Sub) 1049 1.1 joerg .Case("diff", MT_Diff) 1050 1.1 joerg .Case("plural", MT_Plural) 1051 1.1 joerg .Case("s", MT_S) 1052 1.1 joerg .Case("ordinal", MT_Ordinal) 1053 1.1 joerg .Case("q", MT_Q) 1054 1.1 joerg .Case("objcclass", MT_ObjCClass) 1055 1.1 joerg .Case("objcinstance", MT_ObjCInstance) 1056 1.1 joerg .Case("", MT_Placeholder) 1057 1.1 joerg .Default(MT_Unknown); 1058 1.1 joerg 1059 1.1.1.2 joerg auto ExpectAndConsume = [&](StringRef Prefix) { 1060 1.1.1.2 joerg if (!Text.consume_front(Prefix)) 1061 1.1.1.2 joerg Builder.PrintFatalError("expected '" + Prefix + "' while parsing %" + 1062 1.1.1.2 joerg Modifier); 1063 1.1.1.2 joerg }; 1064 1.1.1.2 joerg 1065 1.1 joerg switch (ModType) { 1066 1.1 joerg case MT_Unknown: 1067 1.1 joerg Builder.PrintFatalError("Unknown modifier type: " + Modifier); 1068 1.1 joerg case MT_Select: { 1069 1.1 joerg SelectPiece *Select = New<SelectPiece>(MT_Select); 1070 1.1 joerg do { 1071 1.1 joerg Text = Text.drop_front(); // '{' or '|' 1072 1.1.1.2 joerg Select->Options.push_back( 1073 1.1.1.2 joerg parseDiagText(Text, StopAt::PipeOrCloseBrace)); 1074 1.1 joerg assert(!Text.empty() && "malformed %select"); 1075 1.1 joerg } while (Text.front() == '|'); 1076 1.1.1.2 joerg ExpectAndConsume("}"); 1077 1.1 joerg Select->Index = parseModifier(Text); 1078 1.1 joerg Parsed.push_back(Select); 1079 1.1 joerg continue; 1080 1.1 joerg } 1081 1.1 joerg case MT_Plural: { 1082 1.1 joerg PluralPiece *Plural = New<PluralPiece>(); 1083 1.1 joerg do { 1084 1.1 joerg Text = Text.drop_front(); // '{' or '|' 1085 1.1 joerg size_t End = Text.find_first_of(":"); 1086 1.1 joerg if (End == StringRef::npos) 1087 1.1 joerg Builder.PrintFatalError("expected ':' while parsing %plural"); 1088 1.1 joerg ++End; 1089 1.1 joerg assert(!Text.empty()); 1090 1.1 joerg Plural->OptionPrefixes.push_back( 1091 1.1 joerg New<TextPiece>(Text.slice(0, End), "diagtext")); 1092 1.1 joerg Text = Text.slice(End, StringRef::npos); 1093 1.1.1.2 joerg Plural->Options.push_back( 1094 1.1.1.2 joerg parseDiagText(Text, StopAt::PipeOrCloseBrace)); 1095 1.1.1.2 joerg assert(!Text.empty() && "malformed %plural"); 1096 1.1 joerg } while (Text.front() == '|'); 1097 1.1.1.2 joerg ExpectAndConsume("}"); 1098 1.1 joerg Plural->Index = parseModifier(Text); 1099 1.1 joerg Parsed.push_back(Plural); 1100 1.1 joerg continue; 1101 1.1 joerg } 1102 1.1 joerg case MT_Sub: { 1103 1.1 joerg SubstitutionPiece *Sub = New<SubstitutionPiece>(); 1104 1.1.1.2 joerg ExpectAndConsume("{"); 1105 1.1 joerg size_t NameSize = Text.find_first_of('}'); 1106 1.1 joerg assert(NameSize != size_t(-1) && "failed to find the end of the name"); 1107 1.1 joerg assert(NameSize != 0 && "empty name?"); 1108 1.1 joerg Sub->Name = Text.substr(0, NameSize).str(); 1109 1.1 joerg Text = Text.drop_front(NameSize); 1110 1.1.1.2 joerg ExpectAndConsume("}"); 1111 1.1 joerg if (!Text.empty()) { 1112 1.1 joerg while (true) { 1113 1.1 joerg if (!isdigit(Text[0])) 1114 1.1 joerg break; 1115 1.1 joerg Sub->Modifiers.push_back(parseModifier(Text)); 1116 1.1 joerg if (Text.empty() || Text[0] != ',') 1117 1.1 joerg break; 1118 1.1 joerg Text = Text.drop_front(); // ',' 1119 1.1 joerg assert(!Text.empty() && isdigit(Text[0]) && 1120 1.1 joerg "expected another modifier"); 1121 1.1 joerg } 1122 1.1 joerg } 1123 1.1 joerg Parsed.push_back(Sub); 1124 1.1 joerg continue; 1125 1.1 joerg } 1126 1.1 joerg case MT_Diff: { 1127 1.1 joerg DiffPiece *Diff = New<DiffPiece>(); 1128 1.1.1.2 joerg ExpectAndConsume("{"); 1129 1.1.1.2 joerg Diff->Parts[0] = parseDiagText(Text, StopAt::Dollar); 1130 1.1.1.2 joerg ExpectAndConsume("$"); 1131 1.1.1.2 joerg Diff->Parts[1] = parseDiagText(Text, StopAt::Dollar); 1132 1.1.1.2 joerg ExpectAndConsume("$"); 1133 1.1.1.2 joerg Diff->Parts[2] = parseDiagText(Text, StopAt::PipeOrCloseBrace); 1134 1.1.1.2 joerg ExpectAndConsume("|"); 1135 1.1.1.2 joerg Diff->Parts[3] = parseDiagText(Text, StopAt::PipeOrCloseBrace); 1136 1.1.1.2 joerg ExpectAndConsume("}"); 1137 1.1 joerg Diff->Indexes[0] = parseModifier(Text); 1138 1.1.1.2 joerg ExpectAndConsume(","); 1139 1.1 joerg Diff->Indexes[1] = parseModifier(Text); 1140 1.1 joerg Parsed.push_back(Diff); 1141 1.1 joerg continue; 1142 1.1 joerg } 1143 1.1 joerg case MT_S: { 1144 1.1 joerg SelectPiece *Select = New<SelectPiece>(ModType); 1145 1.1 joerg Select->Options.push_back(New<TextPiece>("")); 1146 1.1 joerg Select->Options.push_back(New<TextPiece>("s", "diagtext")); 1147 1.1 joerg Select->Index = parseModifier(Text); 1148 1.1 joerg Parsed.push_back(Select); 1149 1.1 joerg continue; 1150 1.1 joerg } 1151 1.1 joerg case MT_Q: 1152 1.1 joerg case MT_Placeholder: 1153 1.1 joerg case MT_ObjCClass: 1154 1.1 joerg case MT_ObjCInstance: 1155 1.1 joerg case MT_Ordinal: { 1156 1.1 joerg Parsed.push_back(New<PlaceholderPiece>(ModType, parseModifier(Text))); 1157 1.1 joerg continue; 1158 1.1 joerg } 1159 1.1 joerg } 1160 1.1 joerg } 1161 1.1 joerg 1162 1.1 joerg return New<MultiPiece>(Parsed); 1163 1.1 joerg } 1164 1.1 joerg 1165 1.1 joerg std::vector<std::string> 1166 1.1 joerg DiagnosticTextBuilder::buildForDocumentation(StringRef Severity, 1167 1.1 joerg const Record *R) { 1168 1.1 joerg EvaluatingRecordGuard Guard(&EvaluatingRecord, R); 1169 1.1 joerg StringRef Text = R->getValueAsString("Text"); 1170 1.1 joerg 1171 1.1 joerg DiagText D(*this, Text); 1172 1.1 joerg TextPiece *Prefix = D.New<TextPiece>(Severity, Severity); 1173 1.1 joerg Prefix->Text += ": "; 1174 1.1 joerg auto *MP = dyn_cast<MultiPiece>(D.Root); 1175 1.1 joerg if (!MP) { 1176 1.1 joerg MP = D.New<MultiPiece>(); 1177 1.1 joerg MP->Pieces.push_back(D.Root); 1178 1.1 joerg D.Root = MP; 1179 1.1 joerg } 1180 1.1 joerg MP->Pieces.insert(MP->Pieces.begin(), Prefix); 1181 1.1 joerg std::vector<std::string> Result; 1182 1.1 joerg DiagTextDocPrinter{*this, Result}.Visit(D.Root); 1183 1.1 joerg return Result; 1184 1.1 joerg } 1185 1.1 joerg 1186 1.1 joerg std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) { 1187 1.1 joerg EvaluatingRecordGuard Guard(&EvaluatingRecord, R); 1188 1.1 joerg StringRef Text = R->getValueAsString("Text"); 1189 1.1 joerg DiagText D(*this, Text); 1190 1.1 joerg std::string Result; 1191 1.1 joerg DiagTextPrinter{*this, Result}.Visit(D.Root); 1192 1.1 joerg return Result; 1193 1.1 joerg } 1194 1.1 joerg 1195 1.1 joerg } // namespace 1196 1.1 joerg 1197 1.1 joerg //===----------------------------------------------------------------------===// 1198 1.1 joerg // Warning Tables (.inc file) generation. 1199 1.1 joerg //===----------------------------------------------------------------------===// 1200 1.1 joerg 1201 1.1 joerg static bool isError(const Record &Diag) { 1202 1.1.1.2 joerg const std::string &ClsName = 1203 1.1.1.2 joerg std::string(Diag.getValueAsDef("Class")->getName()); 1204 1.1 joerg return ClsName == "CLASS_ERROR"; 1205 1.1 joerg } 1206 1.1 joerg 1207 1.1 joerg static bool isRemark(const Record &Diag) { 1208 1.1.1.2 joerg const std::string &ClsName = 1209 1.1.1.2 joerg std::string(Diag.getValueAsDef("Class")->getName()); 1210 1.1 joerg return ClsName == "CLASS_REMARK"; 1211 1.1 joerg } 1212 1.1 joerg 1213 1.1 joerg 1214 1.1 joerg /// ClangDiagsDefsEmitter - The top-level class emits .def files containing 1215 1.1 joerg /// declarations of Clang diagnostics. 1216 1.1 joerg void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, 1217 1.1 joerg const std::string &Component) { 1218 1.1 joerg // Write the #if guard 1219 1.1 joerg if (!Component.empty()) { 1220 1.1 joerg std::string ComponentName = StringRef(Component).upper(); 1221 1.1 joerg OS << "#ifdef " << ComponentName << "START\n"; 1222 1.1 joerg OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName 1223 1.1 joerg << ",\n"; 1224 1.1 joerg OS << "#undef " << ComponentName << "START\n"; 1225 1.1 joerg OS << "#endif\n\n"; 1226 1.1 joerg } 1227 1.1 joerg 1228 1.1 joerg DiagnosticTextBuilder DiagTextBuilder(Records); 1229 1.1 joerg 1230 1.1 joerg std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic"); 1231 1.1 joerg 1232 1.1 joerg std::vector<Record*> DiagGroups 1233 1.1 joerg = Records.getAllDerivedDefinitions("DiagGroup"); 1234 1.1 joerg 1235 1.1 joerg std::map<std::string, GroupInfo> DiagsInGroup; 1236 1.1 joerg groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 1237 1.1 joerg 1238 1.1 joerg DiagCategoryIDMap CategoryIDs(Records); 1239 1.1 joerg DiagGroupParentMap DGParentMap(Records); 1240 1.1 joerg 1241 1.1 joerg // Compute the set of diagnostics that are in -Wpedantic. 1242 1.1 joerg RecordSet DiagsInPedantic; 1243 1.1 joerg InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 1244 1.1 joerg inferPedantic.compute(&DiagsInPedantic, (RecordVec*)nullptr); 1245 1.1 joerg 1246 1.1 joerg for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 1247 1.1 joerg const Record &R = *Diags[i]; 1248 1.1 joerg 1249 1.1 joerg // Check if this is an error that is accidentally in a warning 1250 1.1 joerg // group. 1251 1.1 joerg if (isError(R)) { 1252 1.1 joerg if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) { 1253 1.1 joerg const Record *GroupRec = Group->getDef(); 1254 1.1.1.2 joerg const std::string &GroupName = 1255 1.1.1.2 joerg std::string(GroupRec->getValueAsString("GroupName")); 1256 1.1 joerg PrintFatalError(R.getLoc(), "Error " + R.getName() + 1257 1.1 joerg " cannot be in a warning group [" + GroupName + "]"); 1258 1.1 joerg } 1259 1.1 joerg } 1260 1.1 joerg 1261 1.1 joerg // Check that all remarks have an associated diagnostic group. 1262 1.1 joerg if (isRemark(R)) { 1263 1.1 joerg if (!isa<DefInit>(R.getValueInit("Group"))) { 1264 1.1 joerg PrintFatalError(R.getLoc(), "Error " + R.getName() + 1265 1.1 joerg " not in any diagnostic group"); 1266 1.1 joerg } 1267 1.1 joerg } 1268 1.1 joerg 1269 1.1 joerg // Filter by component. 1270 1.1 joerg if (!Component.empty() && Component != R.getValueAsString("Component")) 1271 1.1 joerg continue; 1272 1.1 joerg 1273 1.1 joerg OS << "DIAG(" << R.getName() << ", "; 1274 1.1 joerg OS << R.getValueAsDef("Class")->getName(); 1275 1.1 joerg OS << ", (unsigned)diag::Severity::" 1276 1.1 joerg << R.getValueAsDef("DefaultSeverity")->getValueAsString("Name"); 1277 1.1 joerg 1278 1.1 joerg // Description string. 1279 1.1 joerg OS << ", \""; 1280 1.1 joerg OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"'; 1281 1.1 joerg 1282 1.1 joerg // Warning associated with the diagnostic. This is stored as an index into 1283 1.1 joerg // the alphabetically sorted warning table. 1284 1.1 joerg if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) { 1285 1.1.1.2 joerg std::map<std::string, GroupInfo>::iterator I = DiagsInGroup.find( 1286 1.1.1.2 joerg std::string(DI->getDef()->getValueAsString("GroupName"))); 1287 1.1 joerg assert(I != DiagsInGroup.end()); 1288 1.1 joerg OS << ", " << I->second.IDNo; 1289 1.1 joerg } else if (DiagsInPedantic.count(&R)) { 1290 1.1 joerg std::map<std::string, GroupInfo>::iterator I = 1291 1.1 joerg DiagsInGroup.find("pedantic"); 1292 1.1 joerg assert(I != DiagsInGroup.end() && "pedantic group not defined"); 1293 1.1 joerg OS << ", " << I->second.IDNo; 1294 1.1 joerg } else { 1295 1.1 joerg OS << ", 0"; 1296 1.1 joerg } 1297 1.1 joerg 1298 1.1 joerg // SFINAE response. 1299 1.1 joerg OS << ", " << R.getValueAsDef("SFINAE")->getName(); 1300 1.1 joerg 1301 1.1 joerg // Default warning has no Werror bit. 1302 1.1 joerg if (R.getValueAsBit("WarningNoWerror")) 1303 1.1 joerg OS << ", true"; 1304 1.1 joerg else 1305 1.1 joerg OS << ", false"; 1306 1.1 joerg 1307 1.1 joerg if (R.getValueAsBit("ShowInSystemHeader")) 1308 1.1 joerg OS << ", true"; 1309 1.1 joerg else 1310 1.1 joerg OS << ", false"; 1311 1.1 joerg 1312 1.1.1.2 joerg if (R.getValueAsBit("Deferrable")) 1313 1.1.1.2 joerg OS << ", true"; 1314 1.1.1.2 joerg else 1315 1.1.1.2 joerg OS << ", false"; 1316 1.1.1.2 joerg 1317 1.1 joerg // Category number. 1318 1.1 joerg OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap)); 1319 1.1 joerg OS << ")\n"; 1320 1.1 joerg } 1321 1.1 joerg } 1322 1.1 joerg 1323 1.1 joerg //===----------------------------------------------------------------------===// 1324 1.1 joerg // Warning Group Tables generation 1325 1.1 joerg //===----------------------------------------------------------------------===// 1326 1.1 joerg 1327 1.1 joerg static std::string getDiagCategoryEnum(llvm::StringRef name) { 1328 1.1 joerg if (name.empty()) 1329 1.1 joerg return "DiagCat_None"; 1330 1.1 joerg SmallString<256> enumName = llvm::StringRef("DiagCat_"); 1331 1.1 joerg for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I) 1332 1.1 joerg enumName += isalnum(*I) ? *I : '_'; 1333 1.1.1.2 joerg return std::string(enumName.str()); 1334 1.1 joerg } 1335 1.1 joerg 1336 1.1 joerg /// Emit the array of diagnostic subgroups. 1337 1.1 joerg /// 1338 1.1 joerg /// The array of diagnostic subgroups contains for each group a list of its 1339 1.1 joerg /// subgroups. The individual lists are separated by '-1'. Groups with no 1340 1.1 joerg /// subgroups are skipped. 1341 1.1 joerg /// 1342 1.1 joerg /// \code 1343 1.1 joerg /// static const int16_t DiagSubGroups[] = { 1344 1.1 joerg /// /* Empty */ -1, 1345 1.1 joerg /// /* DiagSubGroup0 */ 142, -1, 1346 1.1 joerg /// /* DiagSubGroup13 */ 265, 322, 399, -1 1347 1.1 joerg /// } 1348 1.1 joerg /// \endcode 1349 1.1 joerg /// 1350 1.1 joerg static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup, 1351 1.1 joerg RecordVec &GroupsInPedantic, raw_ostream &OS) { 1352 1.1 joerg OS << "static const int16_t DiagSubGroups[] = {\n" 1353 1.1 joerg << " /* Empty */ -1,\n"; 1354 1.1 joerg for (auto const &I : DiagsInGroup) { 1355 1.1 joerg const bool IsPedantic = I.first == "pedantic"; 1356 1.1 joerg 1357 1.1 joerg const std::vector<std::string> &SubGroups = I.second.SubGroups; 1358 1.1 joerg if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) { 1359 1.1 joerg OS << " /* DiagSubGroup" << I.second.IDNo << " */ "; 1360 1.1 joerg for (auto const &SubGroup : SubGroups) { 1361 1.1 joerg std::map<std::string, GroupInfo>::const_iterator RI = 1362 1.1 joerg DiagsInGroup.find(SubGroup); 1363 1.1 joerg assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 1364 1.1 joerg OS << RI->second.IDNo << ", "; 1365 1.1 joerg } 1366 1.1 joerg // Emit the groups implicitly in "pedantic". 1367 1.1 joerg if (IsPedantic) { 1368 1.1 joerg for (auto const &Group : GroupsInPedantic) { 1369 1.1.1.2 joerg const std::string &GroupName = 1370 1.1.1.2 joerg std::string(Group->getValueAsString("GroupName")); 1371 1.1 joerg std::map<std::string, GroupInfo>::const_iterator RI = 1372 1.1 joerg DiagsInGroup.find(GroupName); 1373 1.1 joerg assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 1374 1.1 joerg OS << RI->second.IDNo << ", "; 1375 1.1 joerg } 1376 1.1 joerg } 1377 1.1 joerg 1378 1.1 joerg OS << "-1,\n"; 1379 1.1 joerg } 1380 1.1 joerg } 1381 1.1 joerg OS << "};\n\n"; 1382 1.1 joerg } 1383 1.1 joerg 1384 1.1 joerg /// Emit the list of diagnostic arrays. 1385 1.1 joerg /// 1386 1.1 joerg /// This data structure is a large array that contains itself arrays of varying 1387 1.1 joerg /// size. Each array represents a list of diagnostics. The different arrays are 1388 1.1 joerg /// separated by the value '-1'. 1389 1.1 joerg /// 1390 1.1 joerg /// \code 1391 1.1 joerg /// static const int16_t DiagArrays[] = { 1392 1.1 joerg /// /* Empty */ -1, 1393 1.1 joerg /// /* DiagArray1 */ diag::warn_pragma_message, 1394 1.1 joerg /// -1, 1395 1.1 joerg /// /* DiagArray2 */ diag::warn_abs_too_small, 1396 1.1 joerg /// diag::warn_unsigned_abs, 1397 1.1 joerg /// diag::warn_wrong_absolute_value_type, 1398 1.1 joerg /// -1 1399 1.1 joerg /// }; 1400 1.1 joerg /// \endcode 1401 1.1 joerg /// 1402 1.1 joerg static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup, 1403 1.1 joerg RecordVec &DiagsInPedantic, raw_ostream &OS) { 1404 1.1 joerg OS << "static const int16_t DiagArrays[] = {\n" 1405 1.1 joerg << " /* Empty */ -1,\n"; 1406 1.1 joerg for (auto const &I : DiagsInGroup) { 1407 1.1 joerg const bool IsPedantic = I.first == "pedantic"; 1408 1.1 joerg 1409 1.1 joerg const std::vector<const Record *> &V = I.second.DiagsInGroup; 1410 1.1 joerg if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) { 1411 1.1 joerg OS << " /* DiagArray" << I.second.IDNo << " */ "; 1412 1.1 joerg for (auto *Record : V) 1413 1.1 joerg OS << "diag::" << Record->getName() << ", "; 1414 1.1 joerg // Emit the diagnostics implicitly in "pedantic". 1415 1.1 joerg if (IsPedantic) { 1416 1.1 joerg for (auto const &Diag : DiagsInPedantic) 1417 1.1 joerg OS << "diag::" << Diag->getName() << ", "; 1418 1.1 joerg } 1419 1.1 joerg OS << "-1,\n"; 1420 1.1 joerg } 1421 1.1 joerg } 1422 1.1 joerg OS << "};\n\n"; 1423 1.1 joerg } 1424 1.1 joerg 1425 1.1 joerg /// Emit a list of group names. 1426 1.1 joerg /// 1427 1.1 joerg /// This creates a long string which by itself contains a list of pascal style 1428 1.1 joerg /// strings, which consist of a length byte directly followed by the string. 1429 1.1 joerg /// 1430 1.1 joerg /// \code 1431 1.1 joerg /// static const char DiagGroupNames[] = { 1432 1.1 joerg /// \000\020#pragma-messages\t#warnings\020CFString-literal" 1433 1.1 joerg /// }; 1434 1.1 joerg /// \endcode 1435 1.1 joerg static void emitDiagGroupNames(StringToOffsetTable &GroupNames, 1436 1.1 joerg raw_ostream &OS) { 1437 1.1 joerg OS << "static const char DiagGroupNames[] = {\n"; 1438 1.1 joerg GroupNames.EmitString(OS); 1439 1.1 joerg OS << "};\n\n"; 1440 1.1 joerg } 1441 1.1 joerg 1442 1.1 joerg /// Emit diagnostic arrays and related data structures. 1443 1.1 joerg /// 1444 1.1 joerg /// This creates the actual diagnostic array, an array of diagnostic subgroups 1445 1.1 joerg /// and an array of subgroup names. 1446 1.1 joerg /// 1447 1.1 joerg /// \code 1448 1.1 joerg /// #ifdef GET_DIAG_ARRAYS 1449 1.1 joerg /// static const int16_t DiagArrays[]; 1450 1.1 joerg /// static const int16_t DiagSubGroups[]; 1451 1.1 joerg /// static const char DiagGroupNames[]; 1452 1.1 joerg /// #endif 1453 1.1 joerg /// \endcode 1454 1.1 joerg static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup, 1455 1.1 joerg RecordVec &DiagsInPedantic, 1456 1.1 joerg RecordVec &GroupsInPedantic, 1457 1.1 joerg StringToOffsetTable &GroupNames, 1458 1.1 joerg raw_ostream &OS) { 1459 1.1 joerg OS << "\n#ifdef GET_DIAG_ARRAYS\n"; 1460 1.1 joerg emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS); 1461 1.1 joerg emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS); 1462 1.1 joerg emitDiagGroupNames(GroupNames, OS); 1463 1.1 joerg OS << "#endif // GET_DIAG_ARRAYS\n\n"; 1464 1.1 joerg } 1465 1.1 joerg 1466 1.1 joerg /// Emit diagnostic table. 1467 1.1 joerg /// 1468 1.1 joerg /// The table is sorted by the name of the diagnostic group. Each element 1469 1.1 joerg /// consists of the name of the diagnostic group (given as offset in the 1470 1.1 joerg /// group name table), a reference to a list of diagnostics (optional) and a 1471 1.1 joerg /// reference to a set of subgroups (optional). 1472 1.1 joerg /// 1473 1.1 joerg /// \code 1474 1.1 joerg /// #ifdef GET_DIAG_TABLE 1475 1.1 joerg /// {/* abi */ 159, /* DiagArray11 */ 19, /* Empty */ 0}, 1476 1.1 joerg /// {/* aggregate-return */ 180, /* Empty */ 0, /* Empty */ 0}, 1477 1.1 joerg /// {/* all */ 197, /* Empty */ 0, /* DiagSubGroup13 */ 3}, 1478 1.1 joerg /// {/* deprecated */ 1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */ 9}, 1479 1.1 joerg /// #endif 1480 1.1 joerg /// \endcode 1481 1.1 joerg static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup, 1482 1.1 joerg RecordVec &DiagsInPedantic, 1483 1.1 joerg RecordVec &GroupsInPedantic, 1484 1.1 joerg StringToOffsetTable &GroupNames, raw_ostream &OS) { 1485 1.1 joerg unsigned MaxLen = 0; 1486 1.1 joerg 1487 1.1 joerg for (auto const &I: DiagsInGroup) 1488 1.1 joerg MaxLen = std::max(MaxLen, (unsigned)I.first.size()); 1489 1.1 joerg 1490 1.1 joerg OS << "\n#ifdef GET_DIAG_TABLE\n"; 1491 1.1 joerg unsigned SubGroupIndex = 1, DiagArrayIndex = 1; 1492 1.1 joerg for (auto const &I: DiagsInGroup) { 1493 1.1 joerg // Group option string. 1494 1.1 joerg OS << " { /* "; 1495 1.1 joerg if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz" 1496 1.1 joerg "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 1497 1.1 joerg "0123456789!@#$%^*-+=:?") != 1498 1.1 joerg std::string::npos) 1499 1.1 joerg PrintFatalError("Invalid character in diagnostic group '" + I.first + 1500 1.1 joerg "'"); 1501 1.1 joerg OS << I.first << " */ " << std::string(MaxLen - I.first.size(), ' '); 1502 1.1 joerg // Store a pascal-style length byte at the beginning of the string. 1503 1.1 joerg std::string Name = char(I.first.size()) + I.first; 1504 1.1 joerg OS << GroupNames.GetOrAddStringOffset(Name, false) << ", "; 1505 1.1 joerg 1506 1.1 joerg // Special handling for 'pedantic'. 1507 1.1 joerg const bool IsPedantic = I.first == "pedantic"; 1508 1.1 joerg 1509 1.1 joerg // Diagnostics in the group. 1510 1.1 joerg const std::vector<const Record *> &V = I.second.DiagsInGroup; 1511 1.1 joerg const bool hasDiags = 1512 1.1 joerg !V.empty() || (IsPedantic && !DiagsInPedantic.empty()); 1513 1.1 joerg if (hasDiags) { 1514 1.1 joerg OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex 1515 1.1 joerg << ", "; 1516 1.1 joerg if (IsPedantic) 1517 1.1 joerg DiagArrayIndex += DiagsInPedantic.size(); 1518 1.1 joerg DiagArrayIndex += V.size() + 1; 1519 1.1 joerg } else { 1520 1.1 joerg OS << "/* Empty */ 0, "; 1521 1.1 joerg } 1522 1.1 joerg 1523 1.1 joerg // Subgroups. 1524 1.1 joerg const std::vector<std::string> &SubGroups = I.second.SubGroups; 1525 1.1 joerg const bool hasSubGroups = 1526 1.1 joerg !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty()); 1527 1.1 joerg if (hasSubGroups) { 1528 1.1 joerg OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex; 1529 1.1 joerg if (IsPedantic) 1530 1.1 joerg SubGroupIndex += GroupsInPedantic.size(); 1531 1.1 joerg SubGroupIndex += SubGroups.size() + 1; 1532 1.1 joerg } else { 1533 1.1 joerg OS << "/* Empty */ 0"; 1534 1.1 joerg } 1535 1.1 joerg 1536 1.1 joerg OS << " },\n"; 1537 1.1 joerg } 1538 1.1 joerg OS << "#endif // GET_DIAG_TABLE\n\n"; 1539 1.1 joerg } 1540 1.1 joerg 1541 1.1 joerg /// Emit the table of diagnostic categories. 1542 1.1 joerg /// 1543 1.1 joerg /// The table has the form of macro calls that have two parameters. The 1544 1.1 joerg /// category's name as well as an enum that represents the category. The 1545 1.1 joerg /// table can be used by defining the macro 'CATEGORY' and including this 1546 1.1 joerg /// table right after. 1547 1.1 joerg /// 1548 1.1 joerg /// \code 1549 1.1 joerg /// #ifdef GET_CATEGORY_TABLE 1550 1.1 joerg /// CATEGORY("Semantic Issue", DiagCat_Semantic_Issue) 1551 1.1 joerg /// CATEGORY("Lambda Issue", DiagCat_Lambda_Issue) 1552 1.1 joerg /// #endif 1553 1.1 joerg /// \endcode 1554 1.1 joerg static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) { 1555 1.1 joerg DiagCategoryIDMap CategoriesByID(Records); 1556 1.1 joerg OS << "\n#ifdef GET_CATEGORY_TABLE\n"; 1557 1.1 joerg for (auto const &C : CategoriesByID) 1558 1.1 joerg OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n"; 1559 1.1 joerg OS << "#endif // GET_CATEGORY_TABLE\n\n"; 1560 1.1 joerg } 1561 1.1 joerg 1562 1.1 joerg void clang::EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { 1563 1.1 joerg // Compute a mapping from a DiagGroup to all of its parents. 1564 1.1 joerg DiagGroupParentMap DGParentMap(Records); 1565 1.1 joerg 1566 1.1 joerg std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic"); 1567 1.1 joerg 1568 1.1 joerg std::vector<Record *> DiagGroups = 1569 1.1 joerg Records.getAllDerivedDefinitions("DiagGroup"); 1570 1.1 joerg 1571 1.1 joerg std::map<std::string, GroupInfo> DiagsInGroup; 1572 1.1 joerg groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 1573 1.1 joerg 1574 1.1 joerg // All extensions are implicitly in the "pedantic" group. Record the 1575 1.1 joerg // implicit set of groups in the "pedantic" group, and use this information 1576 1.1 joerg // later when emitting the group information for Pedantic. 1577 1.1 joerg RecordVec DiagsInPedantic; 1578 1.1 joerg RecordVec GroupsInPedantic; 1579 1.1 joerg InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 1580 1.1 joerg inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic); 1581 1.1 joerg 1582 1.1 joerg StringToOffsetTable GroupNames; 1583 1.1 joerg for (std::map<std::string, GroupInfo>::const_iterator 1584 1.1 joerg I = DiagsInGroup.begin(), 1585 1.1 joerg E = DiagsInGroup.end(); 1586 1.1 joerg I != E; ++I) { 1587 1.1 joerg // Store a pascal-style length byte at the beginning of the string. 1588 1.1 joerg std::string Name = char(I->first.size()) + I->first; 1589 1.1 joerg GroupNames.GetOrAddStringOffset(Name, false); 1590 1.1 joerg } 1591 1.1 joerg 1592 1.1 joerg emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames, 1593 1.1 joerg OS); 1594 1.1 joerg emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames, 1595 1.1 joerg OS); 1596 1.1 joerg emitCategoryTable(Records, OS); 1597 1.1 joerg } 1598 1.1 joerg 1599 1.1 joerg //===----------------------------------------------------------------------===// 1600 1.1 joerg // Diagnostic name index generation 1601 1.1 joerg //===----------------------------------------------------------------------===// 1602 1.1 joerg 1603 1.1 joerg namespace { 1604 1.1 joerg struct RecordIndexElement 1605 1.1 joerg { 1606 1.1 joerg RecordIndexElement() {} 1607 1.1.1.2 joerg explicit RecordIndexElement(Record const &R) 1608 1.1.1.2 joerg : Name(std::string(R.getName())) {} 1609 1.1 joerg 1610 1.1 joerg std::string Name; 1611 1.1 joerg }; 1612 1.1 joerg } // end anonymous namespace. 1613 1.1 joerg 1614 1.1 joerg void clang::EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) { 1615 1.1 joerg const std::vector<Record*> &Diags = 1616 1.1 joerg Records.getAllDerivedDefinitions("Diagnostic"); 1617 1.1 joerg 1618 1.1 joerg std::vector<RecordIndexElement> Index; 1619 1.1 joerg Index.reserve(Diags.size()); 1620 1.1 joerg for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 1621 1.1 joerg const Record &R = *(Diags[i]); 1622 1.1 joerg Index.push_back(RecordIndexElement(R)); 1623 1.1 joerg } 1624 1.1 joerg 1625 1.1 joerg llvm::sort(Index, 1626 1.1 joerg [](const RecordIndexElement &Lhs, const RecordIndexElement &Rhs) { 1627 1.1 joerg return Lhs.Name < Rhs.Name; 1628 1.1 joerg }); 1629 1.1 joerg 1630 1.1 joerg for (unsigned i = 0, e = Index.size(); i != e; ++i) { 1631 1.1 joerg const RecordIndexElement &R = Index[i]; 1632 1.1 joerg 1633 1.1 joerg OS << "DIAG_NAME_INDEX(" << R.Name << ")\n"; 1634 1.1 joerg } 1635 1.1 joerg } 1636 1.1 joerg 1637 1.1 joerg //===----------------------------------------------------------------------===// 1638 1.1 joerg // Diagnostic documentation generation 1639 1.1 joerg //===----------------------------------------------------------------------===// 1640 1.1 joerg 1641 1.1 joerg namespace docs { 1642 1.1 joerg namespace { 1643 1.1 joerg 1644 1.1 joerg bool isRemarkGroup(const Record *DiagGroup, 1645 1.1 joerg const std::map<std::string, GroupInfo> &DiagsInGroup) { 1646 1.1 joerg bool AnyRemarks = false, AnyNonRemarks = false; 1647 1.1 joerg 1648 1.1 joerg std::function<void(StringRef)> Visit = [&](StringRef GroupName) { 1649 1.1.1.2 joerg auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second; 1650 1.1 joerg for (const Record *Diag : GroupInfo.DiagsInGroup) 1651 1.1 joerg (isRemark(*Diag) ? AnyRemarks : AnyNonRemarks) = true; 1652 1.1 joerg for (const auto &Name : GroupInfo.SubGroups) 1653 1.1 joerg Visit(Name); 1654 1.1 joerg }; 1655 1.1 joerg Visit(DiagGroup->getValueAsString("GroupName")); 1656 1.1 joerg 1657 1.1 joerg if (AnyRemarks && AnyNonRemarks) 1658 1.1 joerg PrintFatalError( 1659 1.1 joerg DiagGroup->getLoc(), 1660 1.1 joerg "Diagnostic group contains both remark and non-remark diagnostics"); 1661 1.1 joerg return AnyRemarks; 1662 1.1 joerg } 1663 1.1 joerg 1664 1.1 joerg std::string getDefaultSeverity(const Record *Diag) { 1665 1.1.1.2 joerg return std::string( 1666 1.1.1.2 joerg Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name")); 1667 1.1 joerg } 1668 1.1 joerg 1669 1.1 joerg std::set<std::string> 1670 1.1 joerg getDefaultSeverities(const Record *DiagGroup, 1671 1.1 joerg const std::map<std::string, GroupInfo> &DiagsInGroup) { 1672 1.1 joerg std::set<std::string> States; 1673 1.1 joerg 1674 1.1 joerg std::function<void(StringRef)> Visit = [&](StringRef GroupName) { 1675 1.1.1.2 joerg auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second; 1676 1.1 joerg for (const Record *Diag : GroupInfo.DiagsInGroup) 1677 1.1 joerg States.insert(getDefaultSeverity(Diag)); 1678 1.1 joerg for (const auto &Name : GroupInfo.SubGroups) 1679 1.1 joerg Visit(Name); 1680 1.1 joerg }; 1681 1.1 joerg Visit(DiagGroup->getValueAsString("GroupName")); 1682 1.1 joerg return States; 1683 1.1 joerg } 1684 1.1 joerg 1685 1.1 joerg void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') { 1686 1.1 joerg OS << Str << "\n" << std::string(Str.size(), Kind) << "\n"; 1687 1.1 joerg } 1688 1.1 joerg 1689 1.1 joerg void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R, 1690 1.1 joerg StringRef Role, raw_ostream &OS) { 1691 1.1 joerg StringRef Text = R->getValueAsString("Text"); 1692 1.1 joerg if (Text == "%0") 1693 1.1 joerg OS << "The text of this diagnostic is not controlled by Clang.\n\n"; 1694 1.1 joerg else { 1695 1.1 joerg std::vector<std::string> Out = Builder.buildForDocumentation(Role, R); 1696 1.1 joerg for (auto &Line : Out) 1697 1.1 joerg OS << Line << "\n"; 1698 1.1 joerg OS << "\n"; 1699 1.1 joerg } 1700 1.1 joerg } 1701 1.1 joerg 1702 1.1 joerg } // namespace 1703 1.1 joerg } // namespace docs 1704 1.1 joerg 1705 1.1 joerg void clang::EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) { 1706 1.1 joerg using namespace docs; 1707 1.1 joerg 1708 1.1 joerg // Get the documentation introduction paragraph. 1709 1.1 joerg const Record *Documentation = Records.getDef("GlobalDocumentation"); 1710 1.1 joerg if (!Documentation) { 1711 1.1 joerg PrintFatalError("The Documentation top-level definition is missing, " 1712 1.1 joerg "no documentation will be generated."); 1713 1.1 joerg return; 1714 1.1 joerg } 1715 1.1 joerg 1716 1.1 joerg OS << Documentation->getValueAsString("Intro") << "\n"; 1717 1.1 joerg 1718 1.1 joerg DiagnosticTextBuilder Builder(Records); 1719 1.1 joerg 1720 1.1 joerg std::vector<Record*> Diags = 1721 1.1 joerg Records.getAllDerivedDefinitions("Diagnostic"); 1722 1.1 joerg 1723 1.1 joerg std::vector<Record*> DiagGroups = 1724 1.1 joerg Records.getAllDerivedDefinitions("DiagGroup"); 1725 1.1 joerg llvm::sort(DiagGroups, diagGroupBeforeByName); 1726 1.1 joerg 1727 1.1 joerg DiagGroupParentMap DGParentMap(Records); 1728 1.1 joerg 1729 1.1 joerg std::map<std::string, GroupInfo> DiagsInGroup; 1730 1.1 joerg groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 1731 1.1 joerg 1732 1.1 joerg // Compute the set of diagnostics that are in -Wpedantic. 1733 1.1 joerg { 1734 1.1 joerg RecordSet DiagsInPedanticSet; 1735 1.1 joerg RecordSet GroupsInPedanticSet; 1736 1.1 joerg InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 1737 1.1 joerg inferPedantic.compute(&DiagsInPedanticSet, &GroupsInPedanticSet); 1738 1.1 joerg auto &PedDiags = DiagsInGroup["pedantic"]; 1739 1.1 joerg // Put the diagnostics into a deterministic order. 1740 1.1 joerg RecordVec DiagsInPedantic(DiagsInPedanticSet.begin(), 1741 1.1 joerg DiagsInPedanticSet.end()); 1742 1.1 joerg RecordVec GroupsInPedantic(GroupsInPedanticSet.begin(), 1743 1.1 joerg GroupsInPedanticSet.end()); 1744 1.1 joerg llvm::sort(DiagsInPedantic, beforeThanCompare); 1745 1.1 joerg llvm::sort(GroupsInPedantic, beforeThanCompare); 1746 1.1 joerg PedDiags.DiagsInGroup.insert(PedDiags.DiagsInGroup.end(), 1747 1.1 joerg DiagsInPedantic.begin(), 1748 1.1 joerg DiagsInPedantic.end()); 1749 1.1 joerg for (auto *Group : GroupsInPedantic) 1750 1.1.1.2 joerg PedDiags.SubGroups.push_back( 1751 1.1.1.2 joerg std::string(Group->getValueAsString("GroupName"))); 1752 1.1 joerg } 1753 1.1 joerg 1754 1.1 joerg // FIXME: Write diagnostic categories and link to diagnostic groups in each. 1755 1.1 joerg 1756 1.1 joerg // Write out the diagnostic groups. 1757 1.1 joerg for (const Record *G : DiagGroups) { 1758 1.1 joerg bool IsRemarkGroup = isRemarkGroup(G, DiagsInGroup); 1759 1.1.1.2 joerg auto &GroupInfo = 1760 1.1.1.2 joerg DiagsInGroup[std::string(G->getValueAsString("GroupName"))]; 1761 1.1 joerg bool IsSynonym = GroupInfo.DiagsInGroup.empty() && 1762 1.1 joerg GroupInfo.SubGroups.size() == 1; 1763 1.1 joerg 1764 1.1 joerg writeHeader(((IsRemarkGroup ? "-R" : "-W") + 1765 1.1 joerg G->getValueAsString("GroupName")).str(), 1766 1.1 joerg OS); 1767 1.1 joerg 1768 1.1 joerg if (!IsSynonym) { 1769 1.1 joerg // FIXME: Ideally, all the diagnostics in a group should have the same 1770 1.1 joerg // default state, but that is not currently the case. 1771 1.1 joerg auto DefaultSeverities = getDefaultSeverities(G, DiagsInGroup); 1772 1.1 joerg if (!DefaultSeverities.empty() && !DefaultSeverities.count("Ignored")) { 1773 1.1 joerg bool AnyNonErrors = DefaultSeverities.count("Warning") || 1774 1.1 joerg DefaultSeverities.count("Remark"); 1775 1.1 joerg if (!AnyNonErrors) 1776 1.1 joerg OS << "This diagnostic is an error by default, but the flag ``-Wno-" 1777 1.1 joerg << G->getValueAsString("GroupName") << "`` can be used to disable " 1778 1.1 joerg << "the error.\n\n"; 1779 1.1 joerg else 1780 1.1 joerg OS << "This diagnostic is enabled by default.\n\n"; 1781 1.1 joerg } else if (DefaultSeverities.size() > 1) { 1782 1.1 joerg OS << "Some of the diagnostics controlled by this flag are enabled " 1783 1.1 joerg << "by default.\n\n"; 1784 1.1 joerg } 1785 1.1 joerg } 1786 1.1 joerg 1787 1.1 joerg if (!GroupInfo.SubGroups.empty()) { 1788 1.1 joerg if (IsSynonym) 1789 1.1 joerg OS << "Synonym for "; 1790 1.1 joerg else if (GroupInfo.DiagsInGroup.empty()) 1791 1.1 joerg OS << "Controls "; 1792 1.1 joerg else 1793 1.1 joerg OS << "Also controls "; 1794 1.1 joerg 1795 1.1 joerg bool First = true; 1796 1.1 joerg llvm::sort(GroupInfo.SubGroups); 1797 1.1 joerg for (const auto &Name : GroupInfo.SubGroups) { 1798 1.1 joerg if (!First) OS << ", "; 1799 1.1 joerg OS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_"; 1800 1.1 joerg First = false; 1801 1.1 joerg } 1802 1.1 joerg OS << ".\n\n"; 1803 1.1 joerg } 1804 1.1 joerg 1805 1.1 joerg if (!GroupInfo.DiagsInGroup.empty()) { 1806 1.1 joerg OS << "**Diagnostic text:**\n\n"; 1807 1.1 joerg for (const Record *D : GroupInfo.DiagsInGroup) { 1808 1.1 joerg auto Severity = getDefaultSeverity(D); 1809 1.1 joerg Severity[0] = tolower(Severity[0]); 1810 1.1 joerg if (Severity == "ignored") 1811 1.1 joerg Severity = IsRemarkGroup ? "remark" : "warning"; 1812 1.1 joerg 1813 1.1 joerg writeDiagnosticText(Builder, D, Severity, OS); 1814 1.1 joerg } 1815 1.1 joerg } 1816 1.1 joerg 1817 1.1 joerg auto Doc = G->getValueAsString("Documentation"); 1818 1.1 joerg if (!Doc.empty()) 1819 1.1 joerg OS << Doc; 1820 1.1 joerg else if (GroupInfo.SubGroups.empty() && GroupInfo.DiagsInGroup.empty()) 1821 1.1 joerg OS << "This diagnostic flag exists for GCC compatibility, and has no " 1822 1.1 joerg "effect in Clang.\n"; 1823 1.1 joerg OS << "\n"; 1824 1.1 joerg } 1825 1.1 joerg } 1826