1 //=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // These tablegen backends emit Clang diagnostics tables.
12 //===----------------------------------------------------------------------===//
14 #include "ClangDiagnosticsEmitter.h"
16 #include "llvm/Support/Debug.h"
17 #include "llvm/Support/Compiler.h"
18 #include "llvm/ADT/DenseSet.h"
19 #include "llvm/ADT/StringExtras.h"
20 #include "llvm/ADT/StringMap.h"
21 #include "llvm/ADT/VectorExtras.h"
26 //===----------------------------------------------------------------------===//
27 // Diagnostic category computation code.
28 //===----------------------------------------------------------------------===//
31 class DiagGroupParentMap
{
32 RecordKeeper
&Records
;
33 std::map
<const Record
*, std::vector
<Record
*> > Mapping
;
35 DiagGroupParentMap(RecordKeeper
&records
) : Records(records
) {
36 std::vector
<Record
*> DiagGroups
37 = Records
.getAllDerivedDefinitions("DiagGroup");
38 for (unsigned i
= 0, e
= DiagGroups
.size(); i
!= e
; ++i
) {
39 std::vector
<Record
*> SubGroups
=
40 DiagGroups
[i
]->getValueAsListOfDefs("SubGroups");
41 for (unsigned j
= 0, e
= SubGroups
.size(); j
!= e
; ++j
)
42 Mapping
[SubGroups
[j
]].push_back(DiagGroups
[i
]);
46 const std::vector
<Record
*> &getParents(const Record
*Group
) {
47 return Mapping
[Group
];
50 } // end anonymous namespace.
54 getCategoryFromDiagGroup(const Record
*Group
,
55 DiagGroupParentMap
&DiagGroupParents
) {
56 // If the DiagGroup has a category, return it.
57 std::string CatName
= Group
->getValueAsString("CategoryName");
58 if (!CatName
.empty()) return CatName
;
60 // The diag group may the subgroup of one or more other diagnostic groups,
61 // check these for a category as well.
62 const std::vector
<Record
*> &Parents
= DiagGroupParents
.getParents(Group
);
63 for (unsigned i
= 0, e
= Parents
.size(); i
!= e
; ++i
) {
64 CatName
= getCategoryFromDiagGroup(Parents
[i
], DiagGroupParents
);
65 if (!CatName
.empty()) return CatName
;
70 /// getDiagnosticCategory - Return the category that the specified diagnostic
72 static std::string
getDiagnosticCategory(const Record
*R
,
73 DiagGroupParentMap
&DiagGroupParents
) {
74 // If the diagnostic is in a group, and that group has a category, use it.
75 if (DefInit
*Group
= dynamic_cast<DefInit
*>(R
->getValueInit("Group"))) {
76 // Check the diagnostic's diag group for a category.
77 std::string CatName
= getCategoryFromDiagGroup(Group
->getDef(),
79 if (!CatName
.empty()) return CatName
;
82 // If the diagnostic itself has a category, get it.
83 return R
->getValueAsString("CategoryName");
87 class DiagCategoryIDMap
{
88 RecordKeeper
&Records
;
89 StringMap
<unsigned> CategoryIDs
;
90 std::vector
<std::string
> CategoryStrings
;
92 DiagCategoryIDMap(RecordKeeper
&records
) : Records(records
) {
93 DiagGroupParentMap
ParentInfo(Records
);
95 // The zero'th category is "".
96 CategoryStrings
.push_back("");
99 std::vector
<Record
*> Diags
=
100 Records
.getAllDerivedDefinitions("Diagnostic");
101 for (unsigned i
= 0, e
= Diags
.size(); i
!= e
; ++i
) {
102 std::string Category
= getDiagnosticCategory(Diags
[i
], ParentInfo
);
103 if (Category
.empty()) continue; // Skip diags with no category.
105 unsigned &ID
= CategoryIDs
[Category
];
106 if (ID
!= 0) continue; // Already seen.
108 ID
= CategoryStrings
.size();
109 CategoryStrings
.push_back(Category
);
113 unsigned getID(StringRef CategoryString
) {
114 return CategoryIDs
[CategoryString
];
117 typedef std::vector
<std::string
>::iterator iterator
;
118 iterator
begin() { return CategoryStrings
.begin(); }
119 iterator
end() { return CategoryStrings
.end(); }
121 } // end anonymous namespace.
125 //===----------------------------------------------------------------------===//
126 // Warning Tables (.inc file) generation.
127 //===----------------------------------------------------------------------===//
129 void ClangDiagsDefsEmitter::run(raw_ostream
&OS
) {
130 // Write the #if guard
131 if (!Component
.empty()) {
132 std::string ComponentName
= UppercaseString(Component
);
133 OS
<< "#ifdef " << ComponentName
<< "START\n";
134 OS
<< "__" << ComponentName
<< "START = DIAG_START_" << ComponentName
136 OS
<< "#undef " << ComponentName
<< "START\n";
140 const std::vector
<Record
*> &Diags
=
141 Records
.getAllDerivedDefinitions("Diagnostic");
143 DiagCategoryIDMap
CategoryIDs(Records
);
144 DiagGroupParentMap
DGParentMap(Records
);
146 for (unsigned i
= 0, e
= Diags
.size(); i
!= e
; ++i
) {
147 const Record
&R
= *Diags
[i
];
148 // Filter by component.
149 if (!Component
.empty() && Component
!= R
.getValueAsString("Component"))
152 OS
<< "DIAG(" << R
.getName() << ", ";
153 OS
<< R
.getValueAsDef("Class")->getName();
154 OS
<< ", diag::" << R
.getValueAsDef("DefaultMapping")->getName();
156 // Description string.
158 OS
.write_escaped(R
.getValueAsString("Text")) << '"';
160 // Warning associated with the diagnostic.
161 if (DefInit
*DI
= dynamic_cast<DefInit
*>(R
.getValueInit("Group"))) {
163 OS
.write_escaped(DI
->getDef()->getValueAsString("GroupName")) << '"';
169 if (R
.getValueAsBit("SFINAE"))
174 // Access control bit
175 if (R
.getValueAsBit("AccessControl"))
181 OS
<< ", " << CategoryIDs
.getID(getDiagnosticCategory(&R
, DGParentMap
));
186 //===----------------------------------------------------------------------===//
187 // Warning Group Tables generation
188 //===----------------------------------------------------------------------===//
192 std::vector
<const Record
*> DiagsInGroup
;
193 std::vector
<std::string
> SubGroups
;
196 } // end anonymous namespace.
198 void ClangDiagGroupsEmitter::run(raw_ostream
&OS
) {
199 // Compute a mapping from a DiagGroup to all of its parents.
200 DiagGroupParentMap
DGParentMap(Records
);
202 // Invert the 1-[0/1] mapping of diags to group into a one to many mapping of
203 // groups to diags in the group.
204 std::map
<std::string
, GroupInfo
> DiagsInGroup
;
206 std::vector
<Record
*> Diags
=
207 Records
.getAllDerivedDefinitions("Diagnostic");
208 for (unsigned i
= 0, e
= Diags
.size(); i
!= e
; ++i
) {
209 const Record
*R
= Diags
[i
];
210 DefInit
*DI
= dynamic_cast<DefInit
*>(R
->getValueInit("Group"));
211 if (DI
== 0) continue;
212 std::string GroupName
= DI
->getDef()->getValueAsString("GroupName");
213 DiagsInGroup
[GroupName
].DiagsInGroup
.push_back(R
);
216 // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
217 // groups (these are warnings that GCC supports that clang never produces).
218 std::vector
<Record
*> DiagGroups
219 = Records
.getAllDerivedDefinitions("DiagGroup");
220 for (unsigned i
= 0, e
= DiagGroups
.size(); i
!= e
; ++i
) {
221 Record
*Group
= DiagGroups
[i
];
222 GroupInfo
&GI
= DiagsInGroup
[Group
->getValueAsString("GroupName")];
224 std::vector
<Record
*> SubGroups
= Group
->getValueAsListOfDefs("SubGroups");
225 for (unsigned j
= 0, e
= SubGroups
.size(); j
!= e
; ++j
)
226 GI
.SubGroups
.push_back(SubGroups
[j
]->getValueAsString("GroupName"));
229 // Assign unique ID numbers to the groups.
231 for (std::map
<std::string
, GroupInfo
>::iterator
232 I
= DiagsInGroup
.begin(), E
= DiagsInGroup
.end(); I
!= E
; ++I
, ++IDNo
)
233 I
->second
.IDNo
= IDNo
;
235 // Walk through the groups emitting an array for each diagnostic of the diags
236 // that are mapped to.
237 OS
<< "\n#ifdef GET_DIAG_ARRAYS\n";
239 for (std::map
<std::string
, GroupInfo
>::iterator
240 I
= DiagsInGroup
.begin(), E
= DiagsInGroup
.end(); I
!= E
; ++I
) {
241 MaxLen
= std::max(MaxLen
, (unsigned)I
->first
.size());
243 std::vector
<const Record
*> &V
= I
->second
.DiagsInGroup
;
245 OS
<< "static const short DiagArray" << I
->second
.IDNo
<< "[] = { ";
246 for (unsigned i
= 0, e
= V
.size(); i
!= e
; ++i
)
247 OS
<< "diag::" << V
[i
]->getName() << ", ";
251 const std::vector
<std::string
> &SubGroups
= I
->second
.SubGroups
;
252 if (!SubGroups
.empty()) {
253 OS
<< "static const short DiagSubGroup" << I
->second
.IDNo
<< "[] = { ";
254 for (unsigned i
= 0, e
= SubGroups
.size(); i
!= e
; ++i
) {
255 std::map
<std::string
, GroupInfo
>::iterator RI
=
256 DiagsInGroup
.find(SubGroups
[i
]);
257 assert(RI
!= DiagsInGroup
.end() && "Referenced without existing?");
258 OS
<< RI
->second
.IDNo
<< ", ";
263 OS
<< "#endif // GET_DIAG_ARRAYS\n\n";
265 // Emit the table now.
266 OS
<< "\n#ifdef GET_DIAG_TABLE\n";
267 for (std::map
<std::string
, GroupInfo
>::iterator
268 I
= DiagsInGroup
.begin(), E
= DiagsInGroup
.end(); I
!= E
; ++I
) {
269 // Group option string.
271 OS
.write_escaped(I
->first
) << "\","
272 << std::string(MaxLen
-I
->first
.size()+1, ' ');
274 // Diagnostics in the group.
275 if (I
->second
.DiagsInGroup
.empty())
278 OS
<< "DiagArray" << I
->second
.IDNo
<< ", ";
281 if (I
->second
.SubGroups
.empty())
284 OS
<< "DiagSubGroup" << I
->second
.IDNo
;
287 OS
<< "#endif // GET_DIAG_TABLE\n\n";
289 // Emit the category table next.
290 DiagCategoryIDMap
CategoriesByID(Records
);
291 OS
<< "\n#ifdef GET_CATEGORY_TABLE\n";
292 for (DiagCategoryIDMap::iterator I
= CategoriesByID
.begin(),
293 E
= CategoriesByID
.end(); I
!= E
; ++I
)
294 OS
<< "CATEGORY(\"" << *I
<< "\")\n";
295 OS
<< "#endif // GET_CATEGORY_TABLE\n\n";