diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp index 27b16544ce1..d0e813bc273 100644 --- a/utils/TableGen/ClangDiagnosticsEmitter.cpp +++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -17,11 +17,108 @@ #include "llvm/Support/Compiler.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/VectorExtras.h" #include #include using namespace llvm; +//===----------------------------------------------------------------------===// +// Diagnostic category computation code. +//===----------------------------------------------------------------------===// + +namespace { +class DiagGroupParentMap { + std::map > Mapping; +public: + DiagGroupParentMap() { + std::vector DiagGroups + = Records.getAllDerivedDefinitions("DiagGroup"); + for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { + std::vector SubGroups = + DiagGroups[i]->getValueAsListOfDefs("SubGroups"); + for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) + Mapping[SubGroups[j]].push_back(DiagGroups[i]); + } + } + + const std::vector &getParents(const Record *Group) { + return Mapping[Group]; + } +}; +} // end anonymous namespace. + + +static std::string +getCategoryFromDiagGroup(const Record *Group, + DiagGroupParentMap &DiagGroupParents) { + // If the DiagGroup has a category, return it. + std::string CatName = Group->getValueAsString("CategoryName"); + if (!CatName.empty()) return CatName; + + // The diag group may the subgroup of one or more other diagnostic groups, + // check these for a category as well. + const std::vector &Parents = DiagGroupParents.getParents(Group); + for (unsigned i = 0, e = Parents.size(); i != e; ++i) { + CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents); + if (!CatName.empty()) return CatName; + } + return ""; +} + +/// getDiagnosticCategory - Return the category that the specified diagnostic +/// lives in. +static std::string getDiagnosticCategory(const Record *R, + DiagGroupParentMap &DiagGroupParents) { + // If the diagnostic itself has a category, get it. + std::string CatName = R->getValueAsString("CategoryName"); + if (!CatName.empty()) return CatName; + + DefInit *Group = dynamic_cast(R->getValueInit("Group")); + if (Group == 0) return ""; + + // Check the diagnostic's diag group for a category. + return getCategoryFromDiagGroup(Group->getDef(), DiagGroupParents); +} + +namespace { + class DiagCategoryIDMap { + StringMap CategoryIDs; + std::vector CategoryStrings; + public: + DiagCategoryIDMap() { + DiagGroupParentMap ParentInfo; + + // The zero'th category is "". + CategoryStrings.push_back(""); + CategoryIDs[""] = 0; + + std::vector Diags = + Records.getAllDerivedDefinitions("Diagnostic"); + for (unsigned i = 0, e = Diags.size(); i != e; ++i) { + std::string Category = getDiagnosticCategory(Diags[i], ParentInfo); + if (Category.empty()) continue; // Skip diags with no category. + + unsigned &ID = CategoryIDs[Category]; + if (ID != 0) continue; // Already seen. + + ID = CategoryStrings.size(); + CategoryStrings.push_back(Category); + } + } + + unsigned getID(StringRef CategoryString) { + return CategoryIDs[CategoryString]; + } + + typedef std::vector::iterator iterator; + iterator begin() { return CategoryStrings.begin(); } + iterator end() { return CategoryStrings.end(); } + }; +} // end anonymous namespace. + + + //===----------------------------------------------------------------------===// // Warning Tables (.inc file) generation. //===----------------------------------------------------------------------===// @@ -40,6 +137,9 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) { const std::vector &Diags = Records.getAllDerivedDefinitions("Diagnostic"); + DiagCategoryIDMap CategoryIDs; + DiagGroupParentMap DGParentMap; + for (unsigned i = 0, e = Diags.size(); i != e; ++i) { const Record &R = *Diags[i]; // Filter by component. @@ -67,6 +167,9 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) { OS << ", true"; else OS << ", false"; + + // Category number. + OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap)); OS << ")\n"; } } @@ -82,6 +185,9 @@ struct GroupInfo { }; void ClangDiagGroupsEmitter::run(raw_ostream &OS) { + // Compute a mapping from a DiagGroup to all of its parents. + DiagGroupParentMap DGParentMap; + // Invert the 1-[0/1] mapping of diags to group into a one to many mapping of // groups to diags in the group. std::map DiagsInGroup; @@ -98,9 +204,10 @@ void ClangDiagGroupsEmitter::run(raw_ostream &OS) { // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty // groups (these are warnings that GCC supports that clang never produces). - Diags = Records.getAllDerivedDefinitions("DiagGroup"); - for (unsigned i = 0, e = Diags.size(); i != e; ++i) { - Record *Group = Diags[i]; + std::vector DiagGroups + = Records.getAllDerivedDefinitions("DiagGroup"); + for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { + Record *Group = DiagGroups[i]; GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; std::vector SubGroups = Group->getValueAsListOfDefs("SubGroups"); @@ -167,4 +274,12 @@ void ClangDiagGroupsEmitter::run(raw_ostream &OS) { OS << " },\n"; } OS << "#endif // GET_DIAG_TABLE\n\n"; + + // Emit the category table next. + DiagCategoryIDMap CategoriesByID; + OS << "\n#ifdef GET_CATEGORY_TABLE\n"; + for (DiagCategoryIDMap::iterator I = CategoriesByID.begin(), + E = CategoriesByID.end(); I != E; ++I) + OS << "CATEGORY(\"" << *I << "\")\n"; + OS << "#endif // GET_CATEGORY_TABLE\n\n"; }