1226586Sdim//=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*- 2226586Sdim// 3226586Sdim// The LLVM Compiler Infrastructure 4226586Sdim// 5226586Sdim// This file is distributed under the University of Illinois Open Source 6226586Sdim// License. See LICENSE.TXT for details. 7226586Sdim// 8226586Sdim//===----------------------------------------------------------------------===// 9226586Sdim// 10226586Sdim// These tablegen backends emit Clang diagnostics tables. 11226586Sdim// 12226586Sdim//===----------------------------------------------------------------------===// 13226586Sdim 14249423Sdim#include "llvm/ADT/DenseSet.h" 15249423Sdim#include "llvm/ADT/Optional.h" 16239462Sdim#include "llvm/ADT/PointerUnion.h" 17249423Sdim#include "llvm/ADT/SetVector.h" 18249423Sdim#include "llvm/ADT/SmallPtrSet.h" 19239462Sdim#include "llvm/ADT/SmallString.h" 20249423Sdim#include "llvm/ADT/SmallVector.h" 21226586Sdim#include "llvm/ADT/StringMap.h" 22249423Sdim#include "llvm/ADT/Twine.h" 23239462Sdim#include "llvm/Support/Compiler.h" 24239462Sdim#include "llvm/Support/Debug.h" 25243830Sdim#include "llvm/TableGen/Error.h" 26239462Sdim#include "llvm/TableGen/Record.h" 27263508Sdim#include "llvm/TableGen/StringToOffsetTable.h" 28239462Sdim#include "llvm/TableGen/TableGenBackend.h" 29226586Sdim#include <algorithm> 30239462Sdim#include <cctype> 31226586Sdim#include <functional> 32239462Sdim#include <map> 33234353Sdim#include <set> 34226586Sdimusing namespace llvm; 35226586Sdim 36226586Sdim//===----------------------------------------------------------------------===// 37226586Sdim// Diagnostic category computation code. 38226586Sdim//===----------------------------------------------------------------------===// 39226586Sdim 40226586Sdimnamespace { 41226586Sdimclass DiagGroupParentMap { 42226586Sdim RecordKeeper &Records; 43226586Sdim std::map<const Record*, std::vector<Record*> > Mapping; 44226586Sdimpublic: 45226586Sdim DiagGroupParentMap(RecordKeeper &records) : Records(records) { 46226586Sdim std::vector<Record*> DiagGroups 47226586Sdim = Records.getAllDerivedDefinitions("DiagGroup"); 48226586Sdim for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { 49226586Sdim std::vector<Record*> SubGroups = 50226586Sdim DiagGroups[i]->getValueAsListOfDefs("SubGroups"); 51226586Sdim for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) 52226586Sdim Mapping[SubGroups[j]].push_back(DiagGroups[i]); 53226586Sdim } 54226586Sdim } 55263508Sdim 56226586Sdim const std::vector<Record*> &getParents(const Record *Group) { 57226586Sdim return Mapping[Group]; 58226586Sdim } 59226586Sdim}; 60226586Sdim} // end anonymous namespace. 61226586Sdim 62226586Sdimstatic std::string 63226586SdimgetCategoryFromDiagGroup(const Record *Group, 64226586Sdim DiagGroupParentMap &DiagGroupParents) { 65226586Sdim // If the DiagGroup has a category, return it. 66226586Sdim std::string CatName = Group->getValueAsString("CategoryName"); 67226586Sdim if (!CatName.empty()) return CatName; 68263508Sdim 69226586Sdim // The diag group may the subgroup of one or more other diagnostic groups, 70226586Sdim // check these for a category as well. 71226586Sdim const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 72226586Sdim for (unsigned i = 0, e = Parents.size(); i != e; ++i) { 73226586Sdim CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents); 74226586Sdim if (!CatName.empty()) return CatName; 75226586Sdim } 76226586Sdim return ""; 77226586Sdim} 78226586Sdim 79226586Sdim/// getDiagnosticCategory - Return the category that the specified diagnostic 80226586Sdim/// lives in. 81226586Sdimstatic std::string getDiagnosticCategory(const Record *R, 82226586Sdim DiagGroupParentMap &DiagGroupParents) { 83226586Sdim // If the diagnostic is in a group, and that group has a category, use it. 84243830Sdim if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) { 85226586Sdim // Check the diagnostic's diag group for a category. 86226586Sdim std::string CatName = getCategoryFromDiagGroup(Group->getDef(), 87226586Sdim DiagGroupParents); 88226586Sdim if (!CatName.empty()) return CatName; 89226586Sdim } 90239462Sdim 91226586Sdim // If the diagnostic itself has a category, get it. 92226586Sdim return R->getValueAsString("CategoryName"); 93226586Sdim} 94226586Sdim 95226586Sdimnamespace { 96226586Sdim class DiagCategoryIDMap { 97226586Sdim RecordKeeper &Records; 98226586Sdim StringMap<unsigned> CategoryIDs; 99226586Sdim std::vector<std::string> CategoryStrings; 100226586Sdim public: 101226586Sdim DiagCategoryIDMap(RecordKeeper &records) : Records(records) { 102226586Sdim DiagGroupParentMap ParentInfo(Records); 103263508Sdim 104226586Sdim // The zero'th category is "". 105226586Sdim CategoryStrings.push_back(""); 106226586Sdim CategoryIDs[""] = 0; 107263508Sdim 108226586Sdim std::vector<Record*> Diags = 109226586Sdim Records.getAllDerivedDefinitions("Diagnostic"); 110226586Sdim for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 111226586Sdim std::string Category = getDiagnosticCategory(Diags[i], ParentInfo); 112226586Sdim if (Category.empty()) continue; // Skip diags with no category. 113263508Sdim 114226586Sdim unsigned &ID = CategoryIDs[Category]; 115226586Sdim if (ID != 0) continue; // Already seen. 116263508Sdim 117226586Sdim ID = CategoryStrings.size(); 118226586Sdim CategoryStrings.push_back(Category); 119226586Sdim } 120226586Sdim } 121263508Sdim 122226586Sdim unsigned getID(StringRef CategoryString) { 123226586Sdim return CategoryIDs[CategoryString]; 124226586Sdim } 125263508Sdim 126263508Sdim typedef std::vector<std::string>::const_iterator const_iterator; 127263508Sdim const_iterator begin() const { return CategoryStrings.begin(); } 128263508Sdim const_iterator end() const { return CategoryStrings.end(); } 129226586Sdim }; 130234353Sdim 131234353Sdim struct GroupInfo { 132234353Sdim std::vector<const Record*> DiagsInGroup; 133234353Sdim std::vector<std::string> SubGroups; 134234353Sdim unsigned IDNo; 135249423Sdim 136249423Sdim const Record *ExplicitDef; 137249423Sdim 138249423Sdim GroupInfo() : ExplicitDef(0) {} 139234353Sdim }; 140226586Sdim} // end anonymous namespace. 141226586Sdim 142249423Sdimstatic bool beforeThanCompare(const Record *LHS, const Record *RHS) { 143249423Sdim assert(!LHS->getLoc().empty() && !RHS->getLoc().empty()); 144249423Sdim return 145249423Sdim LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer(); 146249423Sdim} 147249423Sdim 148249423Sdimstatic bool beforeThanCompareGroups(const GroupInfo *LHS, const GroupInfo *RHS){ 149249423Sdim assert(!LHS->DiagsInGroup.empty() && !RHS->DiagsInGroup.empty()); 150249423Sdim return beforeThanCompare(LHS->DiagsInGroup.front(), 151249423Sdim RHS->DiagsInGroup.front()); 152249423Sdim} 153249423Sdim 154249423Sdimstatic SMRange findSuperClassRange(const Record *R, StringRef SuperName) { 155249423Sdim ArrayRef<Record *> Supers = R->getSuperClasses(); 156249423Sdim 157249423Sdim for (size_t i = 0, e = Supers.size(); i < e; ++i) 158249423Sdim if (Supers[i]->getName() == SuperName) 159249423Sdim return R->getSuperClassRanges()[i]; 160249423Sdim 161249423Sdim return SMRange(); 162249423Sdim} 163249423Sdim 164234353Sdim/// \brief Invert the 1-[0/1] mapping of diags to group into a one to many 165234353Sdim/// mapping of groups to diags in the group. 166234353Sdimstatic void groupDiagnostics(const std::vector<Record*> &Diags, 167234353Sdim const std::vector<Record*> &DiagGroups, 168234353Sdim std::map<std::string, GroupInfo> &DiagsInGroup) { 169249423Sdim 170234353Sdim for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 171234353Sdim const Record *R = Diags[i]; 172243830Sdim DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group")); 173234353Sdim if (DI == 0) continue; 174239462Sdim assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" && 175239462Sdim "Note can't be in a DiagGroup"); 176234353Sdim std::string GroupName = DI->getDef()->getValueAsString("GroupName"); 177234353Sdim DiagsInGroup[GroupName].DiagsInGroup.push_back(R); 178234353Sdim } 179249423Sdim 180249423Sdim typedef SmallPtrSet<GroupInfo *, 16> GroupSetTy; 181249423Sdim GroupSetTy ImplicitGroups; 182249423Sdim 183234353Sdim // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty 184234353Sdim // groups (these are warnings that GCC supports that clang never produces). 185234353Sdim for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { 186234353Sdim Record *Group = DiagGroups[i]; 187234353Sdim GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; 188249423Sdim if (Group->isAnonymous()) { 189249423Sdim if (GI.DiagsInGroup.size() > 1) 190249423Sdim ImplicitGroups.insert(&GI); 191249423Sdim } else { 192249423Sdim if (GI.ExplicitDef) 193249423Sdim assert(GI.ExplicitDef == Group); 194249423Sdim else 195249423Sdim GI.ExplicitDef = Group; 196249423Sdim } 197249423Sdim 198234353Sdim std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups"); 199234353Sdim for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) 200234353Sdim GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName")); 201234353Sdim } 202263508Sdim 203234353Sdim // Assign unique ID numbers to the groups. 204234353Sdim unsigned IDNo = 0; 205234353Sdim for (std::map<std::string, GroupInfo>::iterator 206234353Sdim I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo) 207234353Sdim I->second.IDNo = IDNo; 208249423Sdim 209249423Sdim // Sort the implicit groups, so we can warn about them deterministically. 210249423Sdim SmallVector<GroupInfo *, 16> SortedGroups(ImplicitGroups.begin(), 211249423Sdim ImplicitGroups.end()); 212249423Sdim for (SmallVectorImpl<GroupInfo *>::iterator I = SortedGroups.begin(), 213249423Sdim E = SortedGroups.end(); 214249423Sdim I != E; ++I) { 215249423Sdim MutableArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup; 216249423Sdim std::sort(GroupDiags.begin(), GroupDiags.end(), beforeThanCompare); 217249423Sdim } 218249423Sdim std::sort(SortedGroups.begin(), SortedGroups.end(), beforeThanCompareGroups); 219249423Sdim 220249423Sdim // Warn about the same group being used anonymously in multiple places. 221249423Sdim for (SmallVectorImpl<GroupInfo *>::const_iterator I = SortedGroups.begin(), 222249423Sdim E = SortedGroups.end(); 223249423Sdim I != E; ++I) { 224249423Sdim ArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup; 225249423Sdim 226249423Sdim if ((*I)->ExplicitDef) { 227249423Sdim std::string Name = (*I)->ExplicitDef->getValueAsString("GroupName"); 228249423Sdim for (ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(), 229249423Sdim DE = GroupDiags.end(); 230249423Sdim DI != DE; ++DI) { 231249423Sdim const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); 232249423Sdim const Record *NextDiagGroup = GroupInit->getDef(); 233249423Sdim if (NextDiagGroup == (*I)->ExplicitDef) 234249423Sdim continue; 235249423Sdim 236249423Sdim SMRange InGroupRange = findSuperClassRange(*DI, "InGroup"); 237249423Sdim SmallString<64> Replacement; 238249423Sdim if (InGroupRange.isValid()) { 239249423Sdim Replacement += "InGroup<"; 240249423Sdim Replacement += (*I)->ExplicitDef->getName(); 241249423Sdim Replacement += ">"; 242249423Sdim } 243249423Sdim SMFixIt FixIt(InGroupRange, Replacement.str()); 244249423Sdim 245249423Sdim SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(), 246249423Sdim SourceMgr::DK_Error, 247249423Sdim Twine("group '") + Name + 248249423Sdim "' is referred to anonymously", 249251662Sdim None, 250249423Sdim InGroupRange.isValid() ? FixIt 251249423Sdim : ArrayRef<SMFixIt>()); 252249423Sdim SrcMgr.PrintMessage((*I)->ExplicitDef->getLoc().front(), 253249423Sdim SourceMgr::DK_Note, "group defined here"); 254249423Sdim } 255249423Sdim } else { 256249423Sdim // If there's no existing named group, we should just warn once and use 257249423Sdim // notes to list all the other cases. 258249423Sdim ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(), 259249423Sdim DE = GroupDiags.end(); 260249423Sdim assert(DI != DE && "We only care about groups with multiple uses!"); 261249423Sdim 262249423Sdim const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); 263249423Sdim const Record *NextDiagGroup = GroupInit->getDef(); 264249423Sdim std::string Name = NextDiagGroup->getValueAsString("GroupName"); 265249423Sdim 266249423Sdim SMRange InGroupRange = findSuperClassRange(*DI, "InGroup"); 267249423Sdim SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(), 268249423Sdim SourceMgr::DK_Error, 269249423Sdim Twine("group '") + Name + 270249423Sdim "' is referred to anonymously", 271249423Sdim InGroupRange); 272249423Sdim 273249423Sdim for (++DI; DI != DE; ++DI) { 274249423Sdim GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); 275249423Sdim InGroupRange = findSuperClassRange(*DI, "InGroup"); 276249423Sdim SrcMgr.PrintMessage(GroupInit->getDef()->getLoc().front(), 277249423Sdim SourceMgr::DK_Note, "also referenced here", 278249423Sdim InGroupRange); 279249423Sdim } 280249423Sdim } 281249423Sdim } 282234353Sdim} 283226586Sdim 284226586Sdim//===----------------------------------------------------------------------===// 285239462Sdim// Infer members of -Wpedantic. 286239462Sdim//===----------------------------------------------------------------------===// 287239462Sdim 288239462Sdimtypedef std::vector<const Record *> RecordVec; 289239462Sdimtypedef llvm::DenseSet<const Record *> RecordSet; 290239462Sdimtypedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet; 291239462Sdim 292239462Sdimnamespace { 293239462Sdimclass InferPedantic { 294239462Sdim typedef llvm::DenseMap<const Record*, 295249423Sdim std::pair<unsigned, Optional<unsigned> > > GMap; 296239462Sdim 297239462Sdim DiagGroupParentMap &DiagGroupParents; 298239462Sdim const std::vector<Record*> &Diags; 299239462Sdim const std::vector<Record*> DiagGroups; 300239462Sdim std::map<std::string, GroupInfo> &DiagsInGroup; 301239462Sdim llvm::DenseSet<const Record*> DiagsSet; 302239462Sdim GMap GroupCount; 303239462Sdimpublic: 304239462Sdim InferPedantic(DiagGroupParentMap &DiagGroupParents, 305239462Sdim const std::vector<Record*> &Diags, 306239462Sdim const std::vector<Record*> &DiagGroups, 307239462Sdim std::map<std::string, GroupInfo> &DiagsInGroup) 308239462Sdim : DiagGroupParents(DiagGroupParents), 309239462Sdim Diags(Diags), 310239462Sdim DiagGroups(DiagGroups), 311239462Sdim DiagsInGroup(DiagsInGroup) {} 312239462Sdim 313239462Sdim /// Compute the set of diagnostics and groups that are immediately 314239462Sdim /// in -Wpedantic. 315239462Sdim void compute(VecOrSet DiagsInPedantic, 316239462Sdim VecOrSet GroupsInPedantic); 317239462Sdim 318239462Sdimprivate: 319239462Sdim /// Determine whether a group is a subgroup of another group. 320239462Sdim bool isSubGroupOfGroup(const Record *Group, 321239462Sdim llvm::StringRef RootGroupName); 322239462Sdim 323239462Sdim /// Determine if the diagnostic is an extension. 324239462Sdim bool isExtension(const Record *Diag); 325239462Sdim 326239462Sdim /// Determine if the diagnostic is off by default. 327239462Sdim bool isOffByDefault(const Record *Diag); 328239462Sdim 329239462Sdim /// Increment the count for a group, and transitively marked 330239462Sdim /// parent groups when appropriate. 331239462Sdim void markGroup(const Record *Group); 332239462Sdim 333239462Sdim /// Return true if the diagnostic is in a pedantic group. 334239462Sdim bool groupInPedantic(const Record *Group, bool increment = false); 335239462Sdim}; 336239462Sdim} // end anonymous namespace 337239462Sdim 338239462Sdimbool InferPedantic::isSubGroupOfGroup(const Record *Group, 339239462Sdim llvm::StringRef GName) { 340239462Sdim 341239462Sdim const std::string &GroupName = Group->getValueAsString("GroupName"); 342239462Sdim if (GName == GroupName) 343239462Sdim return true; 344239462Sdim 345239462Sdim const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 346239462Sdim for (unsigned i = 0, e = Parents.size(); i != e; ++i) 347239462Sdim if (isSubGroupOfGroup(Parents[i], GName)) 348239462Sdim return true; 349239462Sdim 350239462Sdim return false; 351239462Sdim} 352239462Sdim 353239462Sdim/// Determine if the diagnostic is an extension. 354239462Sdimbool InferPedantic::isExtension(const Record *Diag) { 355239462Sdim const std::string &ClsName = Diag->getValueAsDef("Class")->getName(); 356239462Sdim return ClsName == "CLASS_EXTENSION"; 357239462Sdim} 358239462Sdim 359239462Sdimbool InferPedantic::isOffByDefault(const Record *Diag) { 360239462Sdim const std::string &DefMap = Diag->getValueAsDef("DefaultMapping")->getName(); 361239462Sdim return DefMap == "MAP_IGNORE"; 362239462Sdim} 363239462Sdim 364239462Sdimbool InferPedantic::groupInPedantic(const Record *Group, bool increment) { 365239462Sdim GMap::mapped_type &V = GroupCount[Group]; 366239462Sdim // Lazily compute the threshold value for the group count. 367239462Sdim if (!V.second.hasValue()) { 368239462Sdim const GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; 369239462Sdim V.second = GI.SubGroups.size() + GI.DiagsInGroup.size(); 370239462Sdim } 371239462Sdim 372239462Sdim if (increment) 373239462Sdim ++V.first; 374239462Sdim 375239462Sdim // Consider a group in -Wpendatic IFF if has at least one diagnostic 376239462Sdim // or subgroup AND all of those diagnostics and subgroups are covered 377239462Sdim // by -Wpedantic via our computation. 378239462Sdim return V.first != 0 && V.first == V.second.getValue(); 379239462Sdim} 380239462Sdim 381239462Sdimvoid InferPedantic::markGroup(const Record *Group) { 382239462Sdim // If all the diagnostics and subgroups have been marked as being 383239462Sdim // covered by -Wpedantic, increment the count of parent groups. Once the 384239462Sdim // group's count is equal to the number of subgroups and diagnostics in 385239462Sdim // that group, we can safely add this group to -Wpedantic. 386239462Sdim if (groupInPedantic(Group, /* increment */ true)) { 387239462Sdim const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 388239462Sdim for (unsigned i = 0, e = Parents.size(); i != e; ++i) 389239462Sdim markGroup(Parents[i]); 390239462Sdim } 391239462Sdim} 392239462Sdim 393239462Sdimvoid InferPedantic::compute(VecOrSet DiagsInPedantic, 394239462Sdim VecOrSet GroupsInPedantic) { 395239462Sdim // All extensions that are not on by default are implicitly in the 396239462Sdim // "pedantic" group. For those that aren't explicitly included in -Wpedantic, 397239462Sdim // mark them for consideration to be included in -Wpedantic directly. 398239462Sdim for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 399239462Sdim Record *R = Diags[i]; 400239462Sdim if (isExtension(R) && isOffByDefault(R)) { 401239462Sdim DiagsSet.insert(R); 402243830Sdim if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) { 403239462Sdim const Record *GroupRec = Group->getDef(); 404239462Sdim if (!isSubGroupOfGroup(GroupRec, "pedantic")) { 405239462Sdim markGroup(GroupRec); 406239462Sdim } 407239462Sdim } 408239462Sdim } 409239462Sdim } 410239462Sdim 411239462Sdim // Compute the set of diagnostics that are directly in -Wpedantic. We 412239462Sdim // march through Diags a second time to ensure the results are emitted 413239462Sdim // in deterministic order. 414239462Sdim for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 415239462Sdim Record *R = Diags[i]; 416239462Sdim if (!DiagsSet.count(R)) 417239462Sdim continue; 418239462Sdim // Check if the group is implicitly in -Wpedantic. If so, 419239462Sdim // the diagnostic should not be directly included in the -Wpedantic 420239462Sdim // diagnostic group. 421243830Sdim if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) 422239462Sdim if (groupInPedantic(Group->getDef())) 423239462Sdim continue; 424239462Sdim 425239462Sdim // The diagnostic is not included in a group that is (transitively) in 426239462Sdim // -Wpedantic. Include it in -Wpedantic directly. 427239462Sdim if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>()) 428239462Sdim V->push_back(R); 429239462Sdim else { 430239462Sdim DiagsInPedantic.get<RecordSet*>()->insert(R); 431239462Sdim } 432239462Sdim } 433239462Sdim 434239462Sdim if (!GroupsInPedantic) 435239462Sdim return; 436239462Sdim 437239462Sdim // Compute the set of groups that are directly in -Wpedantic. We 438239462Sdim // march through the groups to ensure the results are emitted 439239462Sdim /// in a deterministc order. 440239462Sdim for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) { 441239462Sdim Record *Group = DiagGroups[i]; 442239462Sdim if (!groupInPedantic(Group)) 443239462Sdim continue; 444239462Sdim 445239462Sdim unsigned ParentsInPedantic = 0; 446239462Sdim const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 447239462Sdim for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) { 448239462Sdim if (groupInPedantic(Parents[j])) 449239462Sdim ++ParentsInPedantic; 450239462Sdim } 451239462Sdim // If all the parents are in -Wpedantic, this means that this diagnostic 452239462Sdim // group will be indirectly included by -Wpedantic already. In that 453239462Sdim // case, do not add it directly to -Wpedantic. If the group has no 454239462Sdim // parents, obviously it should go into -Wpedantic. 455239462Sdim if (Parents.size() > 0 && ParentsInPedantic == Parents.size()) 456239462Sdim continue; 457239462Sdim 458239462Sdim if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>()) 459239462Sdim V->push_back(Group); 460239462Sdim else { 461239462Sdim GroupsInPedantic.get<RecordSet*>()->insert(Group); 462239462Sdim } 463239462Sdim } 464239462Sdim} 465239462Sdim 466239462Sdim//===----------------------------------------------------------------------===// 467226586Sdim// Warning Tables (.inc file) generation. 468226586Sdim//===----------------------------------------------------------------------===// 469226586Sdim 470239462Sdimstatic bool isError(const Record &Diag) { 471239462Sdim const std::string &ClsName = Diag.getValueAsDef("Class")->getName(); 472239462Sdim return ClsName == "CLASS_ERROR"; 473239462Sdim} 474239462Sdim 475239462Sdim/// ClangDiagsDefsEmitter - The top-level class emits .def files containing 476239462Sdim/// declarations of Clang diagnostics. 477239462Sdimnamespace clang { 478239462Sdimvoid EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, 479239462Sdim const std::string &Component) { 480226586Sdim // Write the #if guard 481226586Sdim if (!Component.empty()) { 482234353Sdim std::string ComponentName = StringRef(Component).upper(); 483226586Sdim OS << "#ifdef " << ComponentName << "START\n"; 484226586Sdim OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName 485226586Sdim << ",\n"; 486226586Sdim OS << "#undef " << ComponentName << "START\n"; 487226586Sdim OS << "#endif\n\n"; 488226586Sdim } 489226586Sdim 490226586Sdim const std::vector<Record*> &Diags = 491226586Sdim Records.getAllDerivedDefinitions("Diagnostic"); 492234353Sdim 493234353Sdim std::vector<Record*> DiagGroups 494234353Sdim = Records.getAllDerivedDefinitions("DiagGroup"); 495234353Sdim 496234353Sdim std::map<std::string, GroupInfo> DiagsInGroup; 497234353Sdim groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 498234353Sdim 499226586Sdim DiagCategoryIDMap CategoryIDs(Records); 500226586Sdim DiagGroupParentMap DGParentMap(Records); 501226586Sdim 502239462Sdim // Compute the set of diagnostics that are in -Wpedantic. 503239462Sdim RecordSet DiagsInPedantic; 504239462Sdim InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 505239462Sdim inferPedantic.compute(&DiagsInPedantic, (RecordVec*)0); 506239462Sdim 507226586Sdim for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 508226586Sdim const Record &R = *Diags[i]; 509263508Sdim 510239462Sdim // Check if this is an error that is accidentally in a warning 511239462Sdim // group. 512239462Sdim if (isError(R)) { 513243830Sdim if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) { 514239462Sdim const Record *GroupRec = Group->getDef(); 515239462Sdim const std::string &GroupName = GroupRec->getValueAsString("GroupName"); 516243830Sdim PrintFatalError(R.getLoc(), "Error " + R.getName() + 517243830Sdim " cannot be in a warning group [" + GroupName + "]"); 518239462Sdim } 519239462Sdim } 520239462Sdim 521226586Sdim // Filter by component. 522226586Sdim if (!Component.empty() && Component != R.getValueAsString("Component")) 523226586Sdim continue; 524226586Sdim 525226586Sdim OS << "DIAG(" << R.getName() << ", "; 526226586Sdim OS << R.getValueAsDef("Class")->getName(); 527226586Sdim OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName(); 528263508Sdim 529226586Sdim // Description string. 530226586Sdim OS << ", \""; 531226586Sdim OS.write_escaped(R.getValueAsString("Text")) << '"'; 532263508Sdim 533234353Sdim // Warning associated with the diagnostic. This is stored as an index into 534234353Sdim // the alphabetically sorted warning table. 535243830Sdim if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) { 536234353Sdim std::map<std::string, GroupInfo>::iterator I = 537234353Sdim DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName")); 538234353Sdim assert(I != DiagsInGroup.end()); 539234353Sdim OS << ", " << I->second.IDNo; 540239462Sdim } else if (DiagsInPedantic.count(&R)) { 541239462Sdim std::map<std::string, GroupInfo>::iterator I = 542239462Sdim DiagsInGroup.find("pedantic"); 543239462Sdim assert(I != DiagsInGroup.end() && "pedantic group not defined"); 544239462Sdim OS << ", " << I->second.IDNo; 545226586Sdim } else { 546234353Sdim OS << ", 0"; 547226586Sdim } 548226586Sdim 549263508Sdim // SFINAE response. 550263508Sdim OS << ", " << R.getValueAsDef("SFINAE")->getName(); 551263508Sdim 552263508Sdim // Default warning has no Werror bit. 553263508Sdim if (R.getValueAsBit("WarningNoWerror")) 554226586Sdim OS << ", true"; 555226586Sdim else 556226586Sdim OS << ", false"; 557226586Sdim 558263508Sdim // Default warning show in system header bit. 559263508Sdim if (R.getValueAsBit("WarningShowInSystemHeader")) 560226586Sdim OS << ", true"; 561226586Sdim else 562226586Sdim OS << ", false"; 563226586Sdim 564226586Sdim // Category number. 565226586Sdim OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap)); 566226586Sdim OS << ")\n"; 567226586Sdim } 568226586Sdim} 569239462Sdim} // end namespace clang 570226586Sdim 571226586Sdim//===----------------------------------------------------------------------===// 572226586Sdim// Warning Group Tables generation 573226586Sdim//===----------------------------------------------------------------------===// 574226586Sdim 575226586Sdimstatic std::string getDiagCategoryEnum(llvm::StringRef name) { 576226586Sdim if (name.empty()) 577226586Sdim return "DiagCat_None"; 578234353Sdim SmallString<256> enumName = llvm::StringRef("DiagCat_"); 579226586Sdim for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I) 580226586Sdim enumName += isalnum(*I) ? *I : '_'; 581226586Sdim return enumName.str(); 582226586Sdim} 583263508Sdim 584239462Sdimnamespace clang { 585239462Sdimvoid EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { 586226586Sdim // Compute a mapping from a DiagGroup to all of its parents. 587226586Sdim DiagGroupParentMap DGParentMap(Records); 588239462Sdim 589226586Sdim std::vector<Record*> Diags = 590226586Sdim Records.getAllDerivedDefinitions("Diagnostic"); 591263508Sdim 592226586Sdim std::vector<Record*> DiagGroups 593226586Sdim = Records.getAllDerivedDefinitions("DiagGroup"); 594234353Sdim 595234353Sdim std::map<std::string, GroupInfo> DiagsInGroup; 596234353Sdim groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 597239462Sdim 598239462Sdim // All extensions are implicitly in the "pedantic" group. Record the 599239462Sdim // implicit set of groups in the "pedantic" group, and use this information 600239462Sdim // later when emitting the group information for Pedantic. 601239462Sdim RecordVec DiagsInPedantic; 602239462Sdim RecordVec GroupsInPedantic; 603239462Sdim InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 604239462Sdim inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic); 605239462Sdim 606226586Sdim // Walk through the groups emitting an array for each diagnostic of the diags 607226586Sdim // that are mapped to. 608226586Sdim OS << "\n#ifdef GET_DIAG_ARRAYS\n"; 609226586Sdim unsigned MaxLen = 0; 610263508Sdim OS << "static const int16_t DiagArrays[] = {\n" 611263508Sdim << " /* Empty */ -1,\n"; 612263508Sdim for (std::map<std::string, GroupInfo>::const_iterator 613226586Sdim I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { 614226586Sdim MaxLen = std::max(MaxLen, (unsigned)I->first.size()); 615239462Sdim const bool IsPedantic = I->first == "pedantic"; 616239462Sdim 617263508Sdim const std::vector<const Record*> &V = I->second.DiagsInGroup; 618239462Sdim if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) { 619263508Sdim OS << " /* DiagArray" << I->second.IDNo << " */ "; 620226586Sdim for (unsigned i = 0, e = V.size(); i != e; ++i) 621226586Sdim OS << "diag::" << V[i]->getName() << ", "; 622239462Sdim // Emit the diagnostics implicitly in "pedantic". 623239462Sdim if (IsPedantic) { 624239462Sdim for (unsigned i = 0, e = DiagsInPedantic.size(); i != e; ++i) 625239462Sdim OS << "diag::" << DiagsInPedantic[i]->getName() << ", "; 626239462Sdim } 627263508Sdim OS << "-1,\n"; 628226586Sdim } 629263508Sdim } 630263508Sdim OS << "};\n\n"; 631263508Sdim 632263508Sdim OS << "static const int16_t DiagSubGroups[] = {\n" 633263508Sdim << " /* Empty */ -1,\n"; 634263508Sdim for (std::map<std::string, GroupInfo>::const_iterator 635263508Sdim I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { 636263508Sdim const bool IsPedantic = I->first == "pedantic"; 637263508Sdim 638226586Sdim const std::vector<std::string> &SubGroups = I->second.SubGroups; 639239462Sdim if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) { 640263508Sdim OS << " /* DiagSubGroup" << I->second.IDNo << " */ "; 641226586Sdim for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) { 642263508Sdim std::map<std::string, GroupInfo>::const_iterator RI = 643226586Sdim DiagsInGroup.find(SubGroups[i]); 644226586Sdim assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 645226586Sdim OS << RI->second.IDNo << ", "; 646226586Sdim } 647239462Sdim // Emit the groups implicitly in "pedantic". 648239462Sdim if (IsPedantic) { 649239462Sdim for (unsigned i = 0, e = GroupsInPedantic.size(); i != e; ++i) { 650239462Sdim const std::string &GroupName = 651239462Sdim GroupsInPedantic[i]->getValueAsString("GroupName"); 652263508Sdim std::map<std::string, GroupInfo>::const_iterator RI = 653239462Sdim DiagsInGroup.find(GroupName); 654239462Sdim assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 655239462Sdim OS << RI->second.IDNo << ", "; 656239462Sdim } 657239462Sdim } 658239462Sdim 659263508Sdim OS << "-1,\n"; 660226586Sdim } 661226586Sdim } 662263508Sdim OS << "};\n\n"; 663263508Sdim 664263508Sdim StringToOffsetTable GroupNames; 665263508Sdim for (std::map<std::string, GroupInfo>::const_iterator 666263508Sdim I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { 667263508Sdim // Store a pascal-style length byte at the beginning of the string. 668263508Sdim std::string Name = char(I->first.size()) + I->first; 669263508Sdim GroupNames.GetOrAddStringOffset(Name, false); 670263508Sdim } 671263508Sdim 672263508Sdim OS << "static const char DiagGroupNames[] = {\n"; 673263508Sdim GroupNames.EmitString(OS); 674263508Sdim OS << "};\n\n"; 675263508Sdim 676226586Sdim OS << "#endif // GET_DIAG_ARRAYS\n\n"; 677263508Sdim 678226586Sdim // Emit the table now. 679226586Sdim OS << "\n#ifdef GET_DIAG_TABLE\n"; 680263508Sdim unsigned SubGroupIndex = 1, DiagArrayIndex = 1; 681263508Sdim for (std::map<std::string, GroupInfo>::const_iterator 682226586Sdim I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { 683226586Sdim // Group option string. 684263508Sdim OS << " { /* "; 685234353Sdim if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz" 686234353Sdim "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 687234353Sdim "0123456789!@#$%^*-+=:?")!=std::string::npos) 688243830Sdim PrintFatalError("Invalid character in diagnostic group '" + 689243830Sdim I->first + "'"); 690263508Sdim OS << I->first << " */ " << std::string(MaxLen-I->first.size(), ' '); 691263508Sdim // Store a pascal-style length byte at the beginning of the string. 692263508Sdim std::string Name = char(I->first.size()) + I->first; 693263508Sdim OS << GroupNames.GetOrAddStringOffset(Name, false) << ", "; 694239462Sdim 695239462Sdim // Special handling for 'pedantic'. 696239462Sdim const bool IsPedantic = I->first == "pedantic"; 697239462Sdim 698226586Sdim // Diagnostics in the group. 699263508Sdim const std::vector<const Record*> &V = I->second.DiagsInGroup; 700263508Sdim const bool hasDiags = !V.empty() || 701239462Sdim (IsPedantic && !DiagsInPedantic.empty()); 702263508Sdim if (hasDiags) { 703263508Sdim OS << "/* DiagArray" << I->second.IDNo << " */ " 704263508Sdim << DiagArrayIndex << ", "; 705263508Sdim if (IsPedantic) 706263508Sdim DiagArrayIndex += DiagsInPedantic.size(); 707263508Sdim DiagArrayIndex += V.size() + 1; 708263508Sdim } else { 709263508Sdim OS << "/* Empty */ 0, "; 710263508Sdim } 711263508Sdim 712226586Sdim // Subgroups. 713263508Sdim const std::vector<std::string> &SubGroups = I->second.SubGroups; 714263508Sdim const bool hasSubGroups = !SubGroups.empty() || 715239462Sdim (IsPedantic && !GroupsInPedantic.empty()); 716263508Sdim if (hasSubGroups) { 717263508Sdim OS << "/* DiagSubGroup" << I->second.IDNo << " */ " << SubGroupIndex; 718263508Sdim if (IsPedantic) 719263508Sdim SubGroupIndex += GroupsInPedantic.size(); 720263508Sdim SubGroupIndex += SubGroups.size() + 1; 721263508Sdim } else { 722263508Sdim OS << "/* Empty */ 0"; 723263508Sdim } 724226586Sdim OS << " },\n"; 725226586Sdim } 726226586Sdim OS << "#endif // GET_DIAG_TABLE\n\n"; 727263508Sdim 728226586Sdim // Emit the category table next. 729226586Sdim DiagCategoryIDMap CategoriesByID(Records); 730226586Sdim OS << "\n#ifdef GET_CATEGORY_TABLE\n"; 731263508Sdim for (DiagCategoryIDMap::const_iterator I = CategoriesByID.begin(), 732226586Sdim E = CategoriesByID.end(); I != E; ++I) 733226586Sdim OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n"; 734226586Sdim OS << "#endif // GET_CATEGORY_TABLE\n\n"; 735226586Sdim} 736239462Sdim} // end namespace clang 737226586Sdim 738226586Sdim//===----------------------------------------------------------------------===// 739226586Sdim// Diagnostic name index generation 740226586Sdim//===----------------------------------------------------------------------===// 741226586Sdim 742226586Sdimnamespace { 743226586Sdimstruct RecordIndexElement 744226586Sdim{ 745226586Sdim RecordIndexElement() {} 746226586Sdim explicit RecordIndexElement(Record const &R): 747226586Sdim Name(R.getName()) {} 748263508Sdim 749226586Sdim std::string Name; 750226586Sdim}; 751226586Sdim 752226586Sdimstruct RecordIndexElementSorter : 753226586Sdim public std::binary_function<RecordIndexElement, RecordIndexElement, bool> { 754263508Sdim 755226586Sdim bool operator()(RecordIndexElement const &Lhs, 756226586Sdim RecordIndexElement const &Rhs) const { 757226586Sdim return Lhs.Name < Rhs.Name; 758226586Sdim } 759263508Sdim 760226586Sdim}; 761226586Sdim 762226586Sdim} // end anonymous namespace. 763226586Sdim 764239462Sdimnamespace clang { 765239462Sdimvoid EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) { 766226586Sdim const std::vector<Record*> &Diags = 767226586Sdim Records.getAllDerivedDefinitions("Diagnostic"); 768263508Sdim 769226586Sdim std::vector<RecordIndexElement> Index; 770226586Sdim Index.reserve(Diags.size()); 771226586Sdim for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 772263508Sdim const Record &R = *(Diags[i]); 773226586Sdim Index.push_back(RecordIndexElement(R)); 774226586Sdim } 775263508Sdim 776226586Sdim std::sort(Index.begin(), Index.end(), RecordIndexElementSorter()); 777263508Sdim 778226586Sdim for (unsigned i = 0, e = Index.size(); i != e; ++i) { 779226586Sdim const RecordIndexElement &R = Index[i]; 780263508Sdim 781226586Sdim OS << "DIAG_NAME_INDEX(" << R.Name << ")\n"; 782226586Sdim } 783226586Sdim} 784239462Sdim} // end namespace clang 785