r208136 - tblgen: Modularize the diagnostic emitter

Tobias Grosser tobias at grosser.es
Tue May 6 15:06:56 PDT 2014


Author: grosser
Date: Tue May  6 17:06:56 2014
New Revision: 208136

URL: http://llvm.org/viewvc/llvm-project?rev=208136&view=rev
Log:
tblgen: Modularize the diagnostic emitter

Replace a large monolitic function, with per-table functions which all nicely
fit on my screen. I also added documentation to each function that describes
what kind of tables are generated and which information is contained and
switched to range based for loops. Finally, I run clang-format over the moved
code.

I spent a significant amount of time to understand this code when reasoning
about possible extensions to the diagnostic interface to support 'remark'
diagnostics. This change will definitely help such an implementation, but
already by itself it will save other people a lot of time when trying to
understand this functionality.

Even though the patch touches the full function, it is mostly mechanical. No
functional change intended. The generated tblgen files are identical.

Modified:
    cfe/trunk/utils/TableGen/ClangDiagnosticsEmitter.cpp

Modified: cfe/trunk/utils/TableGen/ClangDiagnosticsEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangDiagnosticsEmitter.cpp?rev=208136&r1=208135&r2=208136&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangDiagnosticsEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangDiagnosticsEmitter.cpp Tue May  6 17:06:56 2014
@@ -594,76 +594,42 @@ static std::string getDiagCategoryEnum(l
   return enumName.str();
 }
 
-namespace clang {
-void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
-  // Compute a mapping from a DiagGroup to all of its parents.
-  DiagGroupParentMap DGParentMap(Records);
-
-  std::vector<Record*> Diags =
-    Records.getAllDerivedDefinitions("Diagnostic");
-
-  std::vector<Record*> DiagGroups
-    = Records.getAllDerivedDefinitions("DiagGroup");
-
-  std::map<std::string, GroupInfo> DiagsInGroup;
-  groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
-
-  // All extensions are implicitly in the "pedantic" group.  Record the
-  // implicit set of groups in the "pedantic" group, and use this information
-  // later when emitting the group information for Pedantic.
-  RecordVec DiagsInPedantic;
-  RecordVec GroupsInPedantic;
-  InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
-  inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
-
-  // Walk through the groups emitting an array for each diagnostic of the diags
-  // that are mapped to.
-  OS << "\n#ifdef GET_DIAG_ARRAYS\n";
-  unsigned MaxLen = 0;
-  OS << "static const int16_t DiagArrays[] = {\n"
-     << "  /* Empty */ -1,\n";
-  for (std::map<std::string, GroupInfo>::const_iterator
-       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
-    MaxLen = std::max(MaxLen, (unsigned)I->first.size());
-    const bool IsPedantic = I->first == "pedantic";
-
-    const std::vector<const Record*> &V = I->second.DiagsInGroup;
-    if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
-      OS << "  /* DiagArray" << I->second.IDNo << " */ ";
-      for (unsigned i = 0, e = V.size(); i != e; ++i)
-        OS << "diag::" << V[i]->getName() << ", ";
-      // Emit the diagnostics implicitly in "pedantic".
-      if (IsPedantic) {
-        for (unsigned i = 0, e = DiagsInPedantic.size(); i != e; ++i)
-          OS << "diag::" << DiagsInPedantic[i]->getName() << ", ";
-      }
-      OS << "-1,\n";
-    }
-  }
-  OS << "};\n\n";
-
+/// \brief Emit the array of diagnostic subgroups.
+///
+/// The array of diagnostic subgroups contains for each group a list of its
+/// subgroups. The individual lists are separated by '-1'. Groups with no
+/// subgroups are skipped.
+///
+/// \code
+///   static const int16_t DiagSubGroups[] = {
+///     /* Empty */ -1,
+///     /* DiagSubGroup0 */ 142, -1,
+///     /* DiagSubGroup13 */ 265, 322, 399, -1
+///   }
+/// \endcode
+///
+static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup,
+                              RecordVec &GroupsInPedantic, raw_ostream &OS) {
   OS << "static const int16_t DiagSubGroups[] = {\n"
      << "  /* Empty */ -1,\n";
-  for (std::map<std::string, GroupInfo>::const_iterator
-       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
-    const bool IsPedantic = I->first == "pedantic";
+  for (auto const &I : DiagsInGroup) {
+    const bool IsPedantic = I.first == "pedantic";
 
-    const std::vector<std::string> &SubGroups = I->second.SubGroups;
+    const std::vector<std::string> &SubGroups = I.second.SubGroups;
     if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
-      OS << "  /* DiagSubGroup" << I->second.IDNo << " */ ";
-      for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) {
+      OS << "  /* DiagSubGroup" << I.second.IDNo << " */ ";
+      for (auto const &SubGroup : SubGroups) {
         std::map<std::string, GroupInfo>::const_iterator RI =
-          DiagsInGroup.find(SubGroups[i]);
+            DiagsInGroup.find(SubGroup);
         assert(RI != DiagsInGroup.end() && "Referenced without existing?");
         OS << RI->second.IDNo << ", ";
       }
       // Emit the groups implicitly in "pedantic".
       if (IsPedantic) {
-        for (unsigned i = 0, e = GroupsInPedantic.size(); i != e; ++i) {
-          const std::string &GroupName =
-            GroupsInPedantic[i]->getValueAsString("GroupName");
+        for (auto const &Group : GroupsInPedantic) {
+          const std::string &GroupName = Group->getValueAsString("GroupName");
           std::map<std::string, GroupInfo>::const_iterator RI =
-            DiagsInGroup.find(GroupName);
+              DiagsInGroup.find(GroupName);
           assert(RI != DiagsInGroup.end() && "Referenced without existing?");
           OS << RI->second.IDNo << ", ";
         }
@@ -673,48 +639,140 @@ void EmitClangDiagGroups(RecordKeeper &R
     }
   }
   OS << "};\n\n";
+}
 
-  StringToOffsetTable GroupNames;
-  for (std::map<std::string, GroupInfo>::const_iterator
-         I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
-    // Store a pascal-style length byte at the beginning of the string.
-    std::string Name = char(I->first.size()) + I->first;
-    GroupNames.GetOrAddStringOffset(Name, false);
+/// \brief Emit the list of diagnostic arrays.
+///
+/// This data structure is a large array that contains itself arrays of varying
+/// size. Each array represents a list of diagnostics. The different arrays are
+/// separated by the value '-1'.
+///
+/// \code
+///   static const int16_t DiagArrays[] = {
+///     /* Empty */ -1,
+///     /* DiagArray1 */ diag::warn_pragma_message,
+///                      -1,
+///     /* DiagArray2 */ diag::warn_abs_too_small,
+///                      diag::warn_unsigned_abs,
+///                      diag::warn_wrong_absolute_value_type,
+///                      -1
+///   };
+/// \endcode
+///
+static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
+                           RecordVec &DiagsInPedantic, raw_ostream &OS) {
+  OS << "static const int16_t DiagArrays[] = {\n"
+     << "  /* Empty */ -1,\n";
+  for (auto const &I : DiagsInGroup) {
+    const bool IsPedantic = I.first == "pedantic";
+
+    const std::vector<const Record *> &V = I.second.DiagsInGroup;
+    if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
+      OS << "  /* DiagArray" << I.second.IDNo << " */ ";
+      for (auto *Record : V)
+        OS << "diag::" << Record->getName() << ", ";
+      // Emit the diagnostics implicitly in "pedantic".
+      if (IsPedantic) {
+        for (auto const &Diag : DiagsInPedantic)
+          OS << "diag::" << Diag->getName() << ", ";
+      }
+      OS << "-1,\n";
+    }
   }
+  OS << "};\n\n";
+}
 
+/// \brief Emit a list of group names.
+///
+/// This creates a long string which by itself contains a list of pascal style
+/// strings, which consist of a length byte directly followed by the string.
+///
+/// \code
+///   static const char DiagGroupNames[] = {
+///     \000\020#pragma-messages\t#warnings\020CFString-literal"
+///   };
+/// \endcode
+static void emitDiagGroupNames(StringToOffsetTable &GroupNames,
+                               raw_ostream &OS) {
   OS << "static const char DiagGroupNames[] = {\n";
   GroupNames.EmitString(OS);
   OS << "};\n\n";
+}
 
+/// \brief Emit diagnostic arrays and related data structures.
+///
+/// This creates the actual diagnostic array, an array of diagnostic subgroups
+/// and an array of subgroup names.
+///
+/// \code
+///  #ifdef GET_DIAG_ARRAYS
+///     static const int16_t DiagArrays[];
+///     static const int16_t DiagSubGroups[];
+///     static const char DiagGroupNames[];
+///  #endif
+///  \endcode
+static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
+                              RecordVec &DiagsInPedantic,
+                              RecordVec &GroupsInPedantic,
+                              StringToOffsetTable &GroupNames,
+                              raw_ostream &OS) {
+  OS << "\n#ifdef GET_DIAG_ARRAYS\n";
+  emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS);
+  emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS);
+  emitDiagGroupNames(GroupNames, OS);
   OS << "#endif // GET_DIAG_ARRAYS\n\n";
+}
+
+/// \brief Emit diagnostic table.
+///
+/// The table is sorted by the name of the diagnostic group. Each element
+/// consists of the name of the diagnostic group (given as offset in the
+/// group name table), a reference to a list of diagnostics (optional) and a
+/// reference to a set of subgroups (optional).
+///
+/// \code
+/// #ifdef GET_DIAG_TABLE
+///  {/* abi */              159, /* DiagArray11 */ 19, /* Empty */          0},
+///  {/* aggregate-return */ 180, /* Empty */        0, /* Empty */          0},
+///  {/* all */              197, /* Empty */        0, /* DiagSubGroup13 */ 3},
+///  {/* deprecated */       1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */  9},
+/// #endif
+/// \endcode
+static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup,
+                          RecordVec &DiagsInPedantic,
+                          RecordVec &GroupsInPedantic,
+                          StringToOffsetTable &GroupNames, raw_ostream &OS) {
+  unsigned MaxLen = 0;
+
+  for (auto const &I: DiagsInGroup)
+    MaxLen = std::max(MaxLen, (unsigned)I.first.size());
 
-  // Emit the table now.
   OS << "\n#ifdef GET_DIAG_TABLE\n";
   unsigned SubGroupIndex = 1, DiagArrayIndex = 1;
-  for (std::map<std::string, GroupInfo>::const_iterator
-       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
+  for (auto const &I: DiagsInGroup) {
     // Group option string.
     OS << "  { /* ";
-    if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
+    if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
                                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                                   "0123456789!@#$%^*-+=:?")!=std::string::npos)
-      PrintFatalError("Invalid character in diagnostic group '" +
-                      I->first + "'");
-    OS << I->first << " */ " << std::string(MaxLen-I->first.size(), ' ');
+                                   "0123456789!@#$%^*-+=:?") !=
+        std::string::npos)
+      PrintFatalError("Invalid character in diagnostic group '" + I.first +
+                      "'");
+    OS << I.first << " */ " << std::string(MaxLen - I.first.size(), ' ');
     // Store a pascal-style length byte at the beginning of the string.
-    std::string Name = char(I->first.size()) + I->first;
+    std::string Name = char(I.first.size()) + I.first;
     OS << GroupNames.GetOrAddStringOffset(Name, false) << ", ";
 
     // Special handling for 'pedantic'.
-    const bool IsPedantic = I->first == "pedantic";
+    const bool IsPedantic = I.first == "pedantic";
 
     // Diagnostics in the group.
-    const std::vector<const Record*> &V = I->second.DiagsInGroup;
-    const bool hasDiags = !V.empty() ||
-                          (IsPedantic && !DiagsInPedantic.empty());
+    const std::vector<const Record *> &V = I.second.DiagsInGroup;
+    const bool hasDiags =
+        !V.empty() || (IsPedantic && !DiagsInPedantic.empty());
     if (hasDiags) {
-      OS << "/* DiagArray" << I->second.IDNo << " */ "
-         << DiagArrayIndex << ", ";
+      OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex
+         << ", ";
       if (IsPedantic)
         DiagArrayIndex += DiagsInPedantic.size();
       DiagArrayIndex += V.size() + 1;
@@ -723,29 +781,81 @@ void EmitClangDiagGroups(RecordKeeper &R
     }
 
     // Subgroups.
-    const std::vector<std::string> &SubGroups = I->second.SubGroups;
-    const bool hasSubGroups = !SubGroups.empty() ||
-                              (IsPedantic && !GroupsInPedantic.empty());
+    const std::vector<std::string> &SubGroups = I.second.SubGroups;
+    const bool hasSubGroups =
+        !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty());
     if (hasSubGroups) {
-      OS << "/* DiagSubGroup" << I->second.IDNo << " */ " << SubGroupIndex;
+      OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex;
       if (IsPedantic)
         SubGroupIndex += GroupsInPedantic.size();
       SubGroupIndex += SubGroups.size() + 1;
     } else {
       OS << "/* Empty */         0";
     }
+
     OS << " },\n";
   }
   OS << "#endif // GET_DIAG_TABLE\n\n";
+}
 
-  // Emit the category table next.
+/// \brief Emit the table of diagnostic categories.
+///
+/// The table has the form of macro calls that have two parameters. The
+/// category's name as well as an enum that represents the category. The
+/// table can be used by defining the macro 'CATEGORY' and including this
+/// table right after.
+///
+/// \code
+/// #ifdef GET_CATEGORY_TABLE
+///   CATEGORY("Semantic Issue", DiagCat_Semantic_Issue)
+///   CATEGORY("Lambda Issue", DiagCat_Lambda_Issue)
+/// #endif
+/// \endcode
+static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) {
   DiagCategoryIDMap CategoriesByID(Records);
   OS << "\n#ifdef GET_CATEGORY_TABLE\n";
-  for (DiagCategoryIDMap::const_iterator I = CategoriesByID.begin(),
-       E = CategoriesByID.end(); I != E; ++I)
-    OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n";
+  for (auto const &C : CategoriesByID)
+    OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n";
   OS << "#endif // GET_CATEGORY_TABLE\n\n";
 }
+
+namespace clang {
+void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
+  // Compute a mapping from a DiagGroup to all of its parents.
+  DiagGroupParentMap DGParentMap(Records);
+
+  std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
+
+  std::vector<Record *> DiagGroups =
+      Records.getAllDerivedDefinitions("DiagGroup");
+
+  std::map<std::string, GroupInfo> DiagsInGroup;
+  groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
+
+  // All extensions are implicitly in the "pedantic" group.  Record the
+  // implicit set of groups in the "pedantic" group, and use this information
+  // later when emitting the group information for Pedantic.
+  RecordVec DiagsInPedantic;
+  RecordVec GroupsInPedantic;
+  InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
+  inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
+
+  StringToOffsetTable GroupNames;
+  for (std::map<std::string, GroupInfo>::const_iterator
+           I = DiagsInGroup.begin(),
+           E = DiagsInGroup.end();
+       I != E; ++I) {
+    // Store a pascal-style length byte at the beginning of the string.
+    std::string Name = char(I->first.size()) + I->first;
+    GroupNames.GetOrAddStringOffset(Name, false);
+  }
+
+  emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
+                    OS);
+  emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
+                OS);
+  emitCategoryTable(Records, OS);
+}
 } // end namespace clang
 
 //===----------------------------------------------------------------------===//





More information about the cfe-commits mailing list