summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorTobias Grosser <tobias@grosser.es>2014-05-06 22:06:56 +0000
committerTobias Grosser <tobias@grosser.es>2014-05-06 22:06:56 +0000
commitf65fb7ca9e242149db4cfc235491e65fab933237 (patch)
tree7a4fd785793830c56abcf529a93e1d6ad2c447a9 /utils
parentafafe70f43dbb614f336ccbede1c4bbb132ec658 (diff)
downloadclang-f65fb7ca9e242149db4cfc235491e65fab933237.tar.gz
clang-f65fb7ca9e242149db4cfc235491e65fab933237.tar.bz2
clang-f65fb7ca9e242149db4cfc235491e65fab933237.tar.xz
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@208136 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils')
-rw-r--r--utils/TableGen/ClangDiagnosticsEmitter.cpp286
1 files changed, 198 insertions, 88 deletions
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp
index 40af9f6000..58472a9765 100644
--- a/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -594,76 +594,42 @@ static std::string getDiagCategoryEnum(llvm::StringRef name) {
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 &Records, raw_ostream &OS) {
}
}
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 &Records, raw_ostream &OS) {
}
// 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
//===----------------------------------------------------------------------===//