ClangDiagnosticsEmitter.cpp revision 1.1 1 1.1 joerg //=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
2 1.1 joerg //
3 1.1 joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 1.1 joerg // See https://llvm.org/LICENSE.txt for license information.
5 1.1 joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 1.1 joerg //
7 1.1 joerg //===----------------------------------------------------------------------===//
8 1.1 joerg //
9 1.1 joerg // These tablegen backends emit Clang diagnostics tables.
10 1.1 joerg //
11 1.1 joerg //===----------------------------------------------------------------------===//
12 1.1 joerg
13 1.1 joerg #include "TableGenBackends.h"
14 1.1 joerg #include "llvm/ADT/DenseSet.h"
15 1.1 joerg #include "llvm/ADT/Optional.h"
16 1.1 joerg #include "llvm/ADT/PointerUnion.h"
17 1.1 joerg #include "llvm/ADT/STLExtras.h"
18 1.1 joerg #include "llvm/ADT/SmallPtrSet.h"
19 1.1 joerg #include "llvm/ADT/SmallString.h"
20 1.1 joerg #include "llvm/ADT/SmallVector.h"
21 1.1 joerg #include "llvm/ADT/StringMap.h"
22 1.1 joerg #include "llvm/ADT/Twine.h"
23 1.1 joerg #include "llvm/Support/Casting.h"
24 1.1 joerg #include "llvm/TableGen/Error.h"
25 1.1 joerg #include "llvm/TableGen/Record.h"
26 1.1 joerg #include "llvm/TableGen/StringToOffsetTable.h"
27 1.1 joerg #include "llvm/TableGen/TableGenBackend.h"
28 1.1 joerg #include <algorithm>
29 1.1 joerg #include <cctype>
30 1.1 joerg #include <functional>
31 1.1 joerg #include <map>
32 1.1 joerg #include <set>
33 1.1 joerg using namespace llvm;
34 1.1 joerg
35 1.1 joerg //===----------------------------------------------------------------------===//
36 1.1 joerg // Diagnostic category computation code.
37 1.1 joerg //===----------------------------------------------------------------------===//
38 1.1 joerg
39 1.1 joerg namespace {
40 1.1 joerg class DiagGroupParentMap {
41 1.1 joerg RecordKeeper &Records;
42 1.1 joerg std::map<const Record*, std::vector<Record*> > Mapping;
43 1.1 joerg public:
44 1.1 joerg DiagGroupParentMap(RecordKeeper &records) : Records(records) {
45 1.1 joerg std::vector<Record*> DiagGroups
46 1.1 joerg = Records.getAllDerivedDefinitions("DiagGroup");
47 1.1 joerg for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
48 1.1 joerg std::vector<Record*> SubGroups =
49 1.1 joerg DiagGroups[i]->getValueAsListOfDefs("SubGroups");
50 1.1 joerg for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
51 1.1 joerg Mapping[SubGroups[j]].push_back(DiagGroups[i]);
52 1.1 joerg }
53 1.1 joerg }
54 1.1 joerg
55 1.1 joerg const std::vector<Record*> &getParents(const Record *Group) {
56 1.1 joerg return Mapping[Group];
57 1.1 joerg }
58 1.1 joerg };
59 1.1 joerg } // end anonymous namespace.
60 1.1 joerg
61 1.1 joerg static std::string
62 1.1 joerg getCategoryFromDiagGroup(const Record *Group,
63 1.1 joerg DiagGroupParentMap &DiagGroupParents) {
64 1.1 joerg // If the DiagGroup has a category, return it.
65 1.1 joerg std::string CatName = Group->getValueAsString("CategoryName");
66 1.1 joerg if (!CatName.empty()) return CatName;
67 1.1 joerg
68 1.1 joerg // The diag group may the subgroup of one or more other diagnostic groups,
69 1.1 joerg // check these for a category as well.
70 1.1 joerg const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
71 1.1 joerg for (unsigned i = 0, e = Parents.size(); i != e; ++i) {
72 1.1 joerg CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents);
73 1.1 joerg if (!CatName.empty()) return CatName;
74 1.1 joerg }
75 1.1 joerg return "";
76 1.1 joerg }
77 1.1 joerg
78 1.1 joerg /// getDiagnosticCategory - Return the category that the specified diagnostic
79 1.1 joerg /// lives in.
80 1.1 joerg static std::string getDiagnosticCategory(const Record *R,
81 1.1 joerg DiagGroupParentMap &DiagGroupParents) {
82 1.1 joerg // If the diagnostic is in a group, and that group has a category, use it.
83 1.1 joerg if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
84 1.1 joerg // Check the diagnostic's diag group for a category.
85 1.1 joerg std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
86 1.1 joerg DiagGroupParents);
87 1.1 joerg if (!CatName.empty()) return CatName;
88 1.1 joerg }
89 1.1 joerg
90 1.1 joerg // If the diagnostic itself has a category, get it.
91 1.1 joerg return R->getValueAsString("CategoryName");
92 1.1 joerg }
93 1.1 joerg
94 1.1 joerg namespace {
95 1.1 joerg class DiagCategoryIDMap {
96 1.1 joerg RecordKeeper &Records;
97 1.1 joerg StringMap<unsigned> CategoryIDs;
98 1.1 joerg std::vector<std::string> CategoryStrings;
99 1.1 joerg public:
100 1.1 joerg DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
101 1.1 joerg DiagGroupParentMap ParentInfo(Records);
102 1.1 joerg
103 1.1 joerg // The zero'th category is "".
104 1.1 joerg CategoryStrings.push_back("");
105 1.1 joerg CategoryIDs[""] = 0;
106 1.1 joerg
107 1.1 joerg std::vector<Record*> Diags =
108 1.1 joerg Records.getAllDerivedDefinitions("Diagnostic");
109 1.1 joerg for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
110 1.1 joerg std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
111 1.1 joerg if (Category.empty()) continue; // Skip diags with no category.
112 1.1 joerg
113 1.1 joerg unsigned &ID = CategoryIDs[Category];
114 1.1 joerg if (ID != 0) continue; // Already seen.
115 1.1 joerg
116 1.1 joerg ID = CategoryStrings.size();
117 1.1 joerg CategoryStrings.push_back(Category);
118 1.1 joerg }
119 1.1 joerg }
120 1.1 joerg
121 1.1 joerg unsigned getID(StringRef CategoryString) {
122 1.1 joerg return CategoryIDs[CategoryString];
123 1.1 joerg }
124 1.1 joerg
125 1.1 joerg typedef std::vector<std::string>::const_iterator const_iterator;
126 1.1 joerg const_iterator begin() const { return CategoryStrings.begin(); }
127 1.1 joerg const_iterator end() const { return CategoryStrings.end(); }
128 1.1 joerg };
129 1.1 joerg
130 1.1 joerg struct GroupInfo {
131 1.1 joerg std::vector<const Record*> DiagsInGroup;
132 1.1 joerg std::vector<std::string> SubGroups;
133 1.1 joerg unsigned IDNo;
134 1.1 joerg
135 1.1 joerg const Record *ExplicitDef;
136 1.1 joerg
137 1.1 joerg GroupInfo() : ExplicitDef(nullptr) {}
138 1.1 joerg };
139 1.1 joerg } // end anonymous namespace.
140 1.1 joerg
141 1.1 joerg static bool beforeThanCompare(const Record *LHS, const Record *RHS) {
142 1.1 joerg assert(!LHS->getLoc().empty() && !RHS->getLoc().empty());
143 1.1 joerg return
144 1.1 joerg LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer();
145 1.1 joerg }
146 1.1 joerg
147 1.1 joerg static bool diagGroupBeforeByName(const Record *LHS, const Record *RHS) {
148 1.1 joerg return LHS->getValueAsString("GroupName") <
149 1.1 joerg RHS->getValueAsString("GroupName");
150 1.1 joerg }
151 1.1 joerg
152 1.1 joerg static bool beforeThanCompareGroups(const GroupInfo *LHS, const GroupInfo *RHS){
153 1.1 joerg assert(!LHS->DiagsInGroup.empty() && !RHS->DiagsInGroup.empty());
154 1.1 joerg return beforeThanCompare(LHS->DiagsInGroup.front(),
155 1.1 joerg RHS->DiagsInGroup.front());
156 1.1 joerg }
157 1.1 joerg
158 1.1 joerg /// Invert the 1-[0/1] mapping of diags to group into a one to many
159 1.1 joerg /// mapping of groups to diags in the group.
160 1.1 joerg static void groupDiagnostics(const std::vector<Record*> &Diags,
161 1.1 joerg const std::vector<Record*> &DiagGroups,
162 1.1 joerg std::map<std::string, GroupInfo> &DiagsInGroup) {
163 1.1 joerg
164 1.1 joerg for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
165 1.1 joerg const Record *R = Diags[i];
166 1.1 joerg DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
167 1.1 joerg if (!DI)
168 1.1 joerg continue;
169 1.1 joerg assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
170 1.1 joerg "Note can't be in a DiagGroup");
171 1.1 joerg std::string GroupName = DI->getDef()->getValueAsString("GroupName");
172 1.1 joerg DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
173 1.1 joerg }
174 1.1 joerg
175 1.1 joerg typedef SmallPtrSet<GroupInfo *, 16> GroupSetTy;
176 1.1 joerg GroupSetTy ImplicitGroups;
177 1.1 joerg
178 1.1 joerg // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
179 1.1 joerg // groups (these are warnings that GCC supports that clang never produces).
180 1.1 joerg for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
181 1.1 joerg Record *Group = DiagGroups[i];
182 1.1 joerg GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
183 1.1 joerg if (Group->isAnonymous()) {
184 1.1 joerg if (GI.DiagsInGroup.size() > 1)
185 1.1 joerg ImplicitGroups.insert(&GI);
186 1.1 joerg } else {
187 1.1 joerg if (GI.ExplicitDef)
188 1.1 joerg assert(GI.ExplicitDef == Group);
189 1.1 joerg else
190 1.1 joerg GI.ExplicitDef = Group;
191 1.1 joerg }
192 1.1 joerg
193 1.1 joerg std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
194 1.1 joerg for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
195 1.1 joerg GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName"));
196 1.1 joerg }
197 1.1 joerg
198 1.1 joerg // Assign unique ID numbers to the groups.
199 1.1 joerg unsigned IDNo = 0;
200 1.1 joerg for (std::map<std::string, GroupInfo>::iterator
201 1.1 joerg I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
202 1.1 joerg I->second.IDNo = IDNo;
203 1.1 joerg
204 1.1 joerg // Sort the implicit groups, so we can warn about them deterministically.
205 1.1 joerg SmallVector<GroupInfo *, 16> SortedGroups(ImplicitGroups.begin(),
206 1.1 joerg ImplicitGroups.end());
207 1.1 joerg for (SmallVectorImpl<GroupInfo *>::iterator I = SortedGroups.begin(),
208 1.1 joerg E = SortedGroups.end();
209 1.1 joerg I != E; ++I) {
210 1.1 joerg MutableArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
211 1.1 joerg llvm::sort(GroupDiags, beforeThanCompare);
212 1.1 joerg }
213 1.1 joerg llvm::sort(SortedGroups, beforeThanCompareGroups);
214 1.1 joerg
215 1.1 joerg // Warn about the same group being used anonymously in multiple places.
216 1.1 joerg for (SmallVectorImpl<GroupInfo *>::const_iterator I = SortedGroups.begin(),
217 1.1 joerg E = SortedGroups.end();
218 1.1 joerg I != E; ++I) {
219 1.1 joerg ArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
220 1.1 joerg
221 1.1 joerg if ((*I)->ExplicitDef) {
222 1.1 joerg std::string Name = (*I)->ExplicitDef->getValueAsString("GroupName");
223 1.1 joerg for (ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(),
224 1.1 joerg DE = GroupDiags.end();
225 1.1 joerg DI != DE; ++DI) {
226 1.1 joerg const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
227 1.1 joerg const Record *NextDiagGroup = GroupInit->getDef();
228 1.1 joerg if (NextDiagGroup == (*I)->ExplicitDef)
229 1.1 joerg continue;
230 1.1 joerg
231 1.1 joerg SrcMgr.PrintMessage((*DI)->getLoc().front(),
232 1.1 joerg SourceMgr::DK_Error,
233 1.1 joerg Twine("group '") + Name +
234 1.1 joerg "' is referred to anonymously");
235 1.1 joerg SrcMgr.PrintMessage((*I)->ExplicitDef->getLoc().front(),
236 1.1 joerg SourceMgr::DK_Note, "group defined here");
237 1.1 joerg }
238 1.1 joerg } else {
239 1.1 joerg // If there's no existing named group, we should just warn once and use
240 1.1 joerg // notes to list all the other cases.
241 1.1 joerg ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(),
242 1.1 joerg DE = GroupDiags.end();
243 1.1 joerg assert(DI != DE && "We only care about groups with multiple uses!");
244 1.1 joerg
245 1.1 joerg const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
246 1.1 joerg const Record *NextDiagGroup = GroupInit->getDef();
247 1.1 joerg std::string Name = NextDiagGroup->getValueAsString("GroupName");
248 1.1 joerg
249 1.1 joerg SrcMgr.PrintMessage((*DI)->getLoc().front(),
250 1.1 joerg SourceMgr::DK_Error,
251 1.1 joerg Twine("group '") + Name +
252 1.1 joerg "' is referred to anonymously");
253 1.1 joerg
254 1.1 joerg for (++DI; DI != DE; ++DI) {
255 1.1 joerg SrcMgr.PrintMessage((*DI)->getLoc().front(),
256 1.1 joerg SourceMgr::DK_Note, "also referenced here");
257 1.1 joerg }
258 1.1 joerg }
259 1.1 joerg }
260 1.1 joerg }
261 1.1 joerg
262 1.1 joerg //===----------------------------------------------------------------------===//
263 1.1 joerg // Infer members of -Wpedantic.
264 1.1 joerg //===----------------------------------------------------------------------===//
265 1.1 joerg
266 1.1 joerg typedef std::vector<const Record *> RecordVec;
267 1.1 joerg typedef llvm::DenseSet<const Record *> RecordSet;
268 1.1 joerg typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet;
269 1.1 joerg
270 1.1 joerg namespace {
271 1.1 joerg class InferPedantic {
272 1.1 joerg typedef llvm::DenseMap<const Record*,
273 1.1 joerg std::pair<unsigned, Optional<unsigned> > > GMap;
274 1.1 joerg
275 1.1 joerg DiagGroupParentMap &DiagGroupParents;
276 1.1 joerg const std::vector<Record*> &Diags;
277 1.1 joerg const std::vector<Record*> DiagGroups;
278 1.1 joerg std::map<std::string, GroupInfo> &DiagsInGroup;
279 1.1 joerg llvm::DenseSet<const Record*> DiagsSet;
280 1.1 joerg GMap GroupCount;
281 1.1 joerg public:
282 1.1 joerg InferPedantic(DiagGroupParentMap &DiagGroupParents,
283 1.1 joerg const std::vector<Record*> &Diags,
284 1.1 joerg const std::vector<Record*> &DiagGroups,
285 1.1 joerg std::map<std::string, GroupInfo> &DiagsInGroup)
286 1.1 joerg : DiagGroupParents(DiagGroupParents),
287 1.1 joerg Diags(Diags),
288 1.1 joerg DiagGroups(DiagGroups),
289 1.1 joerg DiagsInGroup(DiagsInGroup) {}
290 1.1 joerg
291 1.1 joerg /// Compute the set of diagnostics and groups that are immediately
292 1.1 joerg /// in -Wpedantic.
293 1.1 joerg void compute(VecOrSet DiagsInPedantic,
294 1.1 joerg VecOrSet GroupsInPedantic);
295 1.1 joerg
296 1.1 joerg private:
297 1.1 joerg /// Determine whether a group is a subgroup of another group.
298 1.1 joerg bool isSubGroupOfGroup(const Record *Group,
299 1.1 joerg llvm::StringRef RootGroupName);
300 1.1 joerg
301 1.1 joerg /// Determine if the diagnostic is an extension.
302 1.1 joerg bool isExtension(const Record *Diag);
303 1.1 joerg
304 1.1 joerg /// Determine if the diagnostic is off by default.
305 1.1 joerg bool isOffByDefault(const Record *Diag);
306 1.1 joerg
307 1.1 joerg /// Increment the count for a group, and transitively marked
308 1.1 joerg /// parent groups when appropriate.
309 1.1 joerg void markGroup(const Record *Group);
310 1.1 joerg
311 1.1 joerg /// Return true if the diagnostic is in a pedantic group.
312 1.1 joerg bool groupInPedantic(const Record *Group, bool increment = false);
313 1.1 joerg };
314 1.1 joerg } // end anonymous namespace
315 1.1 joerg
316 1.1 joerg bool InferPedantic::isSubGroupOfGroup(const Record *Group,
317 1.1 joerg llvm::StringRef GName) {
318 1.1 joerg
319 1.1 joerg const std::string &GroupName = Group->getValueAsString("GroupName");
320 1.1 joerg if (GName == GroupName)
321 1.1 joerg return true;
322 1.1 joerg
323 1.1 joerg const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
324 1.1 joerg for (unsigned i = 0, e = Parents.size(); i != e; ++i)
325 1.1 joerg if (isSubGroupOfGroup(Parents[i], GName))
326 1.1 joerg return true;
327 1.1 joerg
328 1.1 joerg return false;
329 1.1 joerg }
330 1.1 joerg
331 1.1 joerg /// Determine if the diagnostic is an extension.
332 1.1 joerg bool InferPedantic::isExtension(const Record *Diag) {
333 1.1 joerg const std::string &ClsName = Diag->getValueAsDef("Class")->getName();
334 1.1 joerg return ClsName == "CLASS_EXTENSION";
335 1.1 joerg }
336 1.1 joerg
337 1.1 joerg bool InferPedantic::isOffByDefault(const Record *Diag) {
338 1.1 joerg const std::string &DefSeverity =
339 1.1 joerg Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name");
340 1.1 joerg return DefSeverity == "Ignored";
341 1.1 joerg }
342 1.1 joerg
343 1.1 joerg bool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
344 1.1 joerg GMap::mapped_type &V = GroupCount[Group];
345 1.1 joerg // Lazily compute the threshold value for the group count.
346 1.1 joerg if (!V.second.hasValue()) {
347 1.1 joerg const GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
348 1.1 joerg V.second = GI.SubGroups.size() + GI.DiagsInGroup.size();
349 1.1 joerg }
350 1.1 joerg
351 1.1 joerg if (increment)
352 1.1 joerg ++V.first;
353 1.1 joerg
354 1.1 joerg // Consider a group in -Wpendatic IFF if has at least one diagnostic
355 1.1 joerg // or subgroup AND all of those diagnostics and subgroups are covered
356 1.1 joerg // by -Wpedantic via our computation.
357 1.1 joerg return V.first != 0 && V.first == V.second.getValue();
358 1.1 joerg }
359 1.1 joerg
360 1.1 joerg void InferPedantic::markGroup(const Record *Group) {
361 1.1 joerg // If all the diagnostics and subgroups have been marked as being
362 1.1 joerg // covered by -Wpedantic, increment the count of parent groups. Once the
363 1.1 joerg // group's count is equal to the number of subgroups and diagnostics in
364 1.1 joerg // that group, we can safely add this group to -Wpedantic.
365 1.1 joerg if (groupInPedantic(Group, /* increment */ true)) {
366 1.1 joerg const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
367 1.1 joerg for (unsigned i = 0, e = Parents.size(); i != e; ++i)
368 1.1 joerg markGroup(Parents[i]);
369 1.1 joerg }
370 1.1 joerg }
371 1.1 joerg
372 1.1 joerg void InferPedantic::compute(VecOrSet DiagsInPedantic,
373 1.1 joerg VecOrSet GroupsInPedantic) {
374 1.1 joerg // All extensions that are not on by default are implicitly in the
375 1.1 joerg // "pedantic" group. For those that aren't explicitly included in -Wpedantic,
376 1.1 joerg // mark them for consideration to be included in -Wpedantic directly.
377 1.1 joerg for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
378 1.1 joerg Record *R = Diags[i];
379 1.1 joerg if (isExtension(R) && isOffByDefault(R)) {
380 1.1 joerg DiagsSet.insert(R);
381 1.1 joerg if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
382 1.1 joerg const Record *GroupRec = Group->getDef();
383 1.1 joerg if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
384 1.1 joerg markGroup(GroupRec);
385 1.1 joerg }
386 1.1 joerg }
387 1.1 joerg }
388 1.1 joerg }
389 1.1 joerg
390 1.1 joerg // Compute the set of diagnostics that are directly in -Wpedantic. We
391 1.1 joerg // march through Diags a second time to ensure the results are emitted
392 1.1 joerg // in deterministic order.
393 1.1 joerg for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
394 1.1 joerg Record *R = Diags[i];
395 1.1 joerg if (!DiagsSet.count(R))
396 1.1 joerg continue;
397 1.1 joerg // Check if the group is implicitly in -Wpedantic. If so,
398 1.1 joerg // the diagnostic should not be directly included in the -Wpedantic
399 1.1 joerg // diagnostic group.
400 1.1 joerg if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group")))
401 1.1 joerg if (groupInPedantic(Group->getDef()))
402 1.1 joerg continue;
403 1.1 joerg
404 1.1 joerg // The diagnostic is not included in a group that is (transitively) in
405 1.1 joerg // -Wpedantic. Include it in -Wpedantic directly.
406 1.1 joerg if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>())
407 1.1 joerg V->push_back(R);
408 1.1 joerg else {
409 1.1 joerg DiagsInPedantic.get<RecordSet*>()->insert(R);
410 1.1 joerg }
411 1.1 joerg }
412 1.1 joerg
413 1.1 joerg if (!GroupsInPedantic)
414 1.1 joerg return;
415 1.1 joerg
416 1.1 joerg // Compute the set of groups that are directly in -Wpedantic. We
417 1.1 joerg // march through the groups to ensure the results are emitted
418 1.1 joerg /// in a deterministc order.
419 1.1 joerg for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) {
420 1.1 joerg Record *Group = DiagGroups[i];
421 1.1 joerg if (!groupInPedantic(Group))
422 1.1 joerg continue;
423 1.1 joerg
424 1.1 joerg unsigned ParentsInPedantic = 0;
425 1.1 joerg const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
426 1.1 joerg for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) {
427 1.1 joerg if (groupInPedantic(Parents[j]))
428 1.1 joerg ++ParentsInPedantic;
429 1.1 joerg }
430 1.1 joerg // If all the parents are in -Wpedantic, this means that this diagnostic
431 1.1 joerg // group will be indirectly included by -Wpedantic already. In that
432 1.1 joerg // case, do not add it directly to -Wpedantic. If the group has no
433 1.1 joerg // parents, obviously it should go into -Wpedantic.
434 1.1 joerg if (Parents.size() > 0 && ParentsInPedantic == Parents.size())
435 1.1 joerg continue;
436 1.1 joerg
437 1.1 joerg if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
438 1.1 joerg V->push_back(Group);
439 1.1 joerg else {
440 1.1 joerg GroupsInPedantic.get<RecordSet*>()->insert(Group);
441 1.1 joerg }
442 1.1 joerg }
443 1.1 joerg }
444 1.1 joerg
445 1.1 joerg namespace {
446 1.1 joerg enum PieceKind {
447 1.1 joerg MultiPieceClass,
448 1.1 joerg TextPieceClass,
449 1.1 joerg PlaceholderPieceClass,
450 1.1 joerg SelectPieceClass,
451 1.1 joerg PluralPieceClass,
452 1.1 joerg DiffPieceClass,
453 1.1 joerg SubstitutionPieceClass,
454 1.1 joerg };
455 1.1 joerg
456 1.1 joerg enum ModifierType {
457 1.1 joerg MT_Unknown,
458 1.1 joerg MT_Placeholder,
459 1.1 joerg MT_Select,
460 1.1 joerg MT_Sub,
461 1.1 joerg MT_Plural,
462 1.1 joerg MT_Diff,
463 1.1 joerg MT_Ordinal,
464 1.1 joerg MT_S,
465 1.1 joerg MT_Q,
466 1.1 joerg MT_ObjCClass,
467 1.1 joerg MT_ObjCInstance,
468 1.1 joerg };
469 1.1 joerg
470 1.1 joerg static StringRef getModifierName(ModifierType MT) {
471 1.1 joerg switch (MT) {
472 1.1 joerg case MT_Select:
473 1.1 joerg return "select";
474 1.1 joerg case MT_Sub:
475 1.1 joerg return "sub";
476 1.1 joerg case MT_Diff:
477 1.1 joerg return "diff";
478 1.1 joerg case MT_Plural:
479 1.1 joerg return "plural";
480 1.1 joerg case MT_Ordinal:
481 1.1 joerg return "ordinal";
482 1.1 joerg case MT_S:
483 1.1 joerg return "s";
484 1.1 joerg case MT_Q:
485 1.1 joerg return "q";
486 1.1 joerg case MT_Placeholder:
487 1.1 joerg return "";
488 1.1 joerg case MT_ObjCClass:
489 1.1 joerg return "objcclass";
490 1.1 joerg case MT_ObjCInstance:
491 1.1 joerg return "objcinstance";
492 1.1 joerg case MT_Unknown:
493 1.1 joerg llvm_unreachable("invalid modifier type");
494 1.1 joerg }
495 1.1 joerg // Unhandled case
496 1.1 joerg llvm_unreachable("invalid modifier type");
497 1.1 joerg }
498 1.1 joerg
499 1.1 joerg struct Piece {
500 1.1 joerg // This type and its derived classes are move-only.
501 1.1 joerg Piece(PieceKind Kind) : ClassKind(Kind) {}
502 1.1 joerg Piece(Piece const &O) = delete;
503 1.1 joerg Piece &operator=(Piece const &) = delete;
504 1.1 joerg virtual ~Piece() {}
505 1.1 joerg
506 1.1 joerg PieceKind getPieceClass() const { return ClassKind; }
507 1.1 joerg static bool classof(const Piece *) { return true; }
508 1.1 joerg
509 1.1 joerg private:
510 1.1 joerg PieceKind ClassKind;
511 1.1 joerg };
512 1.1 joerg
513 1.1 joerg struct MultiPiece : Piece {
514 1.1 joerg MultiPiece() : Piece(MultiPieceClass) {}
515 1.1 joerg MultiPiece(std::vector<Piece *> Pieces)
516 1.1 joerg : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
517 1.1 joerg
518 1.1 joerg std::vector<Piece *> Pieces;
519 1.1 joerg
520 1.1 joerg static bool classof(const Piece *P) {
521 1.1 joerg return P->getPieceClass() == MultiPieceClass;
522 1.1 joerg }
523 1.1 joerg };
524 1.1 joerg
525 1.1 joerg struct TextPiece : Piece {
526 1.1 joerg StringRef Role;
527 1.1 joerg std::string Text;
528 1.1 joerg TextPiece(StringRef Text, StringRef Role = "")
529 1.1 joerg : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
530 1.1 joerg
531 1.1 joerg static bool classof(const Piece *P) {
532 1.1 joerg return P->getPieceClass() == TextPieceClass;
533 1.1 joerg }
534 1.1 joerg };
535 1.1 joerg
536 1.1 joerg struct PlaceholderPiece : Piece {
537 1.1 joerg ModifierType Kind;
538 1.1 joerg int Index;
539 1.1 joerg PlaceholderPiece(ModifierType Kind, int Index)
540 1.1 joerg : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
541 1.1 joerg
542 1.1 joerg static bool classof(const Piece *P) {
543 1.1 joerg return P->getPieceClass() == PlaceholderPieceClass;
544 1.1 joerg }
545 1.1 joerg };
546 1.1 joerg
547 1.1 joerg struct SelectPiece : Piece {
548 1.1 joerg protected:
549 1.1 joerg SelectPiece(PieceKind Kind, ModifierType ModKind)
550 1.1 joerg : Piece(Kind), ModKind(ModKind) {}
551 1.1 joerg
552 1.1 joerg public:
553 1.1 joerg SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {}
554 1.1 joerg
555 1.1 joerg ModifierType ModKind;
556 1.1 joerg std::vector<Piece *> Options;
557 1.1 joerg int Index;
558 1.1 joerg
559 1.1 joerg static bool classof(const Piece *P) {
560 1.1 joerg return P->getPieceClass() == SelectPieceClass ||
561 1.1 joerg P->getPieceClass() == PluralPieceClass;
562 1.1 joerg }
563 1.1 joerg };
564 1.1 joerg
565 1.1 joerg struct PluralPiece : SelectPiece {
566 1.1 joerg PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {}
567 1.1 joerg
568 1.1 joerg std::vector<Piece *> OptionPrefixes;
569 1.1 joerg int Index;
570 1.1 joerg
571 1.1 joerg static bool classof(const Piece *P) {
572 1.1 joerg return P->getPieceClass() == PluralPieceClass;
573 1.1 joerg }
574 1.1 joerg };
575 1.1 joerg
576 1.1 joerg struct DiffPiece : Piece {
577 1.1 joerg DiffPiece() : Piece(DiffPieceClass) {}
578 1.1 joerg
579 1.1 joerg Piece *Options[2] = {};
580 1.1 joerg int Indexes[2] = {};
581 1.1 joerg
582 1.1 joerg static bool classof(const Piece *P) {
583 1.1 joerg return P->getPieceClass() == DiffPieceClass;
584 1.1 joerg }
585 1.1 joerg };
586 1.1 joerg
587 1.1 joerg struct SubstitutionPiece : Piece {
588 1.1 joerg SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
589 1.1 joerg
590 1.1 joerg std::string Name;
591 1.1 joerg std::vector<int> Modifiers;
592 1.1 joerg
593 1.1 joerg static bool classof(const Piece *P) {
594 1.1 joerg return P->getPieceClass() == SubstitutionPieceClass;
595 1.1 joerg }
596 1.1 joerg };
597 1.1 joerg
598 1.1 joerg /// Diagnostic text, parsed into pieces.
599 1.1 joerg
600 1.1 joerg
601 1.1 joerg struct DiagnosticTextBuilder {
602 1.1 joerg DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete;
603 1.1 joerg DiagnosticTextBuilder &operator=(DiagnosticTextBuilder const &) = delete;
604 1.1 joerg
605 1.1 joerg DiagnosticTextBuilder(RecordKeeper &Records) {
606 1.1 joerg // Build up the list of substitution records.
607 1.1 joerg for (auto *S : Records.getAllDerivedDefinitions("TextSubstitution")) {
608 1.1 joerg EvaluatingRecordGuard Guard(&EvaluatingRecord, S);
609 1.1 joerg Substitutions.try_emplace(
610 1.1 joerg S->getName(), DiagText(*this, S->getValueAsString("Substitution")));
611 1.1 joerg }
612 1.1 joerg
613 1.1 joerg // Check that no diagnostic definitions have the same name as a
614 1.1 joerg // substitution.
615 1.1 joerg for (Record *Diag : Records.getAllDerivedDefinitions("Diagnostic")) {
616 1.1 joerg StringRef Name = Diag->getName();
617 1.1 joerg if (Substitutions.count(Name))
618 1.1 joerg llvm::PrintFatalError(
619 1.1 joerg Diag->getLoc(),
620 1.1 joerg "Diagnostic '" + Name +
621 1.1 joerg "' has same name as TextSubstitution definition");
622 1.1 joerg }
623 1.1 joerg }
624 1.1 joerg
625 1.1 joerg std::vector<std::string> buildForDocumentation(StringRef Role,
626 1.1 joerg const Record *R);
627 1.1 joerg std::string buildForDefinition(const Record *R);
628 1.1 joerg
629 1.1 joerg Piece *getSubstitution(SubstitutionPiece *S) const {
630 1.1 joerg auto It = Substitutions.find(S->Name);
631 1.1 joerg if (It == Substitutions.end())
632 1.1 joerg PrintFatalError("Failed to find substitution with name: " + S->Name);
633 1.1 joerg return It->second.Root;
634 1.1 joerg }
635 1.1 joerg
636 1.1 joerg LLVM_ATTRIBUTE_NORETURN void PrintFatalError(llvm::Twine const &Msg) const {
637 1.1 joerg assert(EvaluatingRecord && "not evaluating a record?");
638 1.1 joerg llvm::PrintFatalError(EvaluatingRecord->getLoc(), Msg);
639 1.1 joerg }
640 1.1 joerg
641 1.1 joerg private:
642 1.1 joerg struct DiagText {
643 1.1 joerg DiagnosticTextBuilder &Builder;
644 1.1 joerg std::vector<Piece *> AllocatedPieces;
645 1.1 joerg Piece *Root = nullptr;
646 1.1 joerg
647 1.1 joerg template <class T, class... Args> T *New(Args &&... args) {
648 1.1 joerg static_assert(std::is_base_of<Piece, T>::value, "must be piece");
649 1.1 joerg T *Mem = new T(std::forward<Args>(args)...);
650 1.1 joerg AllocatedPieces.push_back(Mem);
651 1.1 joerg return Mem;
652 1.1 joerg }
653 1.1 joerg
654 1.1 joerg DiagText(DiagnosticTextBuilder &Builder, StringRef Text)
655 1.1 joerg : Builder(Builder), Root(parseDiagText(Text)) {}
656 1.1 joerg
657 1.1 joerg Piece *parseDiagText(StringRef &Text, bool Nested = false);
658 1.1 joerg int parseModifier(StringRef &) const;
659 1.1 joerg
660 1.1 joerg public:
661 1.1 joerg DiagText(DiagText &&O) noexcept
662 1.1 joerg : Builder(O.Builder), AllocatedPieces(std::move(O.AllocatedPieces)),
663 1.1 joerg Root(O.Root) {
664 1.1 joerg O.Root = nullptr;
665 1.1 joerg }
666 1.1 joerg
667 1.1 joerg ~DiagText() {
668 1.1 joerg for (Piece *P : AllocatedPieces)
669 1.1 joerg delete P;
670 1.1 joerg }
671 1.1 joerg };
672 1.1 joerg
673 1.1 joerg private:
674 1.1 joerg const Record *EvaluatingRecord = nullptr;
675 1.1 joerg struct EvaluatingRecordGuard {
676 1.1 joerg EvaluatingRecordGuard(const Record **Dest, const Record *New)
677 1.1 joerg : Dest(Dest), Old(*Dest) {
678 1.1 joerg *Dest = New;
679 1.1 joerg }
680 1.1 joerg ~EvaluatingRecordGuard() { *Dest = Old; }
681 1.1 joerg const Record **Dest;
682 1.1 joerg const Record *Old;
683 1.1 joerg };
684 1.1 joerg
685 1.1 joerg StringMap<DiagText> Substitutions;
686 1.1 joerg };
687 1.1 joerg
688 1.1 joerg template <class Derived> struct DiagTextVisitor {
689 1.1 joerg using ModifierMappingsType = Optional<std::vector<int>>;
690 1.1 joerg
691 1.1 joerg private:
692 1.1 joerg Derived &getDerived() { return static_cast<Derived &>(*this); }
693 1.1 joerg
694 1.1 joerg public:
695 1.1 joerg std::vector<int>
696 1.1 joerg getSubstitutionMappings(SubstitutionPiece *P,
697 1.1 joerg const ModifierMappingsType &Mappings) const {
698 1.1 joerg std::vector<int> NewMappings;
699 1.1 joerg for (int Idx : P->Modifiers)
700 1.1 joerg NewMappings.push_back(mapIndex(Idx, Mappings));
701 1.1 joerg return NewMappings;
702 1.1 joerg }
703 1.1 joerg
704 1.1 joerg struct SubstitutionContext {
705 1.1 joerg SubstitutionContext(DiagTextVisitor &Visitor, SubstitutionPiece *P)
706 1.1 joerg : Visitor(Visitor) {
707 1.1 joerg Substitution = Visitor.Builder.getSubstitution(P);
708 1.1 joerg OldMappings = std::move(Visitor.ModifierMappings);
709 1.1 joerg std::vector<int> NewMappings =
710 1.1 joerg Visitor.getSubstitutionMappings(P, OldMappings);
711 1.1 joerg Visitor.ModifierMappings = std::move(NewMappings);
712 1.1 joerg }
713 1.1 joerg
714 1.1 joerg ~SubstitutionContext() {
715 1.1 joerg Visitor.ModifierMappings = std::move(OldMappings);
716 1.1 joerg }
717 1.1 joerg
718 1.1 joerg private:
719 1.1 joerg DiagTextVisitor &Visitor;
720 1.1 joerg Optional<std::vector<int>> OldMappings;
721 1.1 joerg
722 1.1 joerg public:
723 1.1 joerg Piece *Substitution;
724 1.1 joerg };
725 1.1 joerg
726 1.1 joerg public:
727 1.1 joerg DiagTextVisitor(DiagnosticTextBuilder &Builder) : Builder(Builder) {}
728 1.1 joerg
729 1.1 joerg void Visit(Piece *P) {
730 1.1 joerg switch (P->getPieceClass()) {
731 1.1 joerg #define CASE(T) \
732 1.1 joerg case T##PieceClass: \
733 1.1 joerg return getDerived().Visit##T(static_cast<T##Piece *>(P))
734 1.1 joerg CASE(Multi);
735 1.1 joerg CASE(Text);
736 1.1 joerg CASE(Placeholder);
737 1.1 joerg CASE(Select);
738 1.1 joerg CASE(Plural);
739 1.1 joerg CASE(Diff);
740 1.1 joerg CASE(Substitution);
741 1.1 joerg #undef CASE
742 1.1 joerg }
743 1.1 joerg }
744 1.1 joerg
745 1.1 joerg void VisitSubstitution(SubstitutionPiece *P) {
746 1.1 joerg SubstitutionContext Guard(*this, P);
747 1.1 joerg Visit(Guard.Substitution);
748 1.1 joerg }
749 1.1 joerg
750 1.1 joerg int mapIndex(int Idx,
751 1.1 joerg ModifierMappingsType const &ModifierMappings) const {
752 1.1 joerg if (!ModifierMappings)
753 1.1 joerg return Idx;
754 1.1 joerg if (ModifierMappings->size() <= static_cast<unsigned>(Idx))
755 1.1 joerg Builder.PrintFatalError("Modifier value '" + std::to_string(Idx) +
756 1.1 joerg "' is not valid for this mapping (has " +
757 1.1 joerg std::to_string(ModifierMappings->size()) +
758 1.1 joerg " mappings)");
759 1.1 joerg return (*ModifierMappings)[Idx];
760 1.1 joerg }
761 1.1 joerg
762 1.1 joerg int mapIndex(int Idx) const {
763 1.1 joerg return mapIndex(Idx, ModifierMappings);
764 1.1 joerg }
765 1.1 joerg
766 1.1 joerg protected:
767 1.1 joerg DiagnosticTextBuilder &Builder;
768 1.1 joerg ModifierMappingsType ModifierMappings;
769 1.1 joerg };
770 1.1 joerg
771 1.1 joerg void escapeRST(StringRef Str, std::string &Out) {
772 1.1 joerg for (auto K : Str) {
773 1.1 joerg if (StringRef("`*|_[]\\").count(K))
774 1.1 joerg Out.push_back('\\');
775 1.1 joerg Out.push_back(K);
776 1.1 joerg }
777 1.1 joerg }
778 1.1 joerg
779 1.1 joerg template <typename It> void padToSameLength(It Begin, It End) {
780 1.1 joerg size_t Width = 0;
781 1.1 joerg for (It I = Begin; I != End; ++I)
782 1.1 joerg Width = std::max(Width, I->size());
783 1.1 joerg for (It I = Begin; I != End; ++I)
784 1.1 joerg (*I) += std::string(Width - I->size(), ' ');
785 1.1 joerg }
786 1.1 joerg
787 1.1 joerg template <typename It> void makeTableRows(It Begin, It End) {
788 1.1 joerg if (Begin == End)
789 1.1 joerg return;
790 1.1 joerg padToSameLength(Begin, End);
791 1.1 joerg for (It I = Begin; I != End; ++I)
792 1.1 joerg *I = "|" + *I + "|";
793 1.1 joerg }
794 1.1 joerg
795 1.1 joerg void makeRowSeparator(std::string &Str) {
796 1.1 joerg for (char &K : Str)
797 1.1 joerg K = (K == '|' ? '+' : '-');
798 1.1 joerg }
799 1.1 joerg
800 1.1 joerg struct DiagTextDocPrinter : DiagTextVisitor<DiagTextDocPrinter> {
801 1.1 joerg using BaseTy = DiagTextVisitor<DiagTextDocPrinter>;
802 1.1 joerg DiagTextDocPrinter(DiagnosticTextBuilder &Builder,
803 1.1 joerg std::vector<std::string> &RST)
804 1.1 joerg : BaseTy(Builder), RST(RST) {}
805 1.1 joerg
806 1.1 joerg void gatherNodes(
807 1.1 joerg Piece *OrigP, const ModifierMappingsType &CurrentMappings,
808 1.1 joerg std::vector<std::pair<Piece *, ModifierMappingsType>> &Pieces) const {
809 1.1 joerg if (auto *Sub = dyn_cast<SubstitutionPiece>(OrigP)) {
810 1.1 joerg ModifierMappingsType NewMappings =
811 1.1 joerg getSubstitutionMappings(Sub, CurrentMappings);
812 1.1 joerg return gatherNodes(Builder.getSubstitution(Sub), NewMappings, Pieces);
813 1.1 joerg }
814 1.1 joerg if (auto *MD = dyn_cast<MultiPiece>(OrigP)) {
815 1.1 joerg for (Piece *Node : MD->Pieces)
816 1.1 joerg gatherNodes(Node, CurrentMappings, Pieces);
817 1.1 joerg return;
818 1.1 joerg }
819 1.1 joerg Pieces.push_back(std::make_pair(OrigP, CurrentMappings));
820 1.1 joerg }
821 1.1 joerg
822 1.1 joerg void VisitMulti(MultiPiece *P) {
823 1.1 joerg if (P->Pieces.empty()) {
824 1.1 joerg RST.push_back("");
825 1.1 joerg return;
826 1.1 joerg }
827 1.1 joerg
828 1.1 joerg if (P->Pieces.size() == 1)
829 1.1 joerg return Visit(P->Pieces[0]);
830 1.1 joerg
831 1.1 joerg // Flatten the list of nodes, replacing any substitution pieces with the
832 1.1 joerg // recursively flattened substituted node.
833 1.1 joerg std::vector<std::pair<Piece *, ModifierMappingsType>> Pieces;
834 1.1 joerg gatherNodes(P, ModifierMappings, Pieces);
835 1.1 joerg
836 1.1 joerg std::string EmptyLinePrefix;
837 1.1 joerg size_t Start = RST.size();
838 1.1 joerg bool HasMultipleLines = true;
839 1.1 joerg for (const std::pair<Piece *, ModifierMappingsType> &NodePair : Pieces) {
840 1.1 joerg std::vector<std::string> Lines;
841 1.1 joerg DiagTextDocPrinter Visitor{Builder, Lines};
842 1.1 joerg Visitor.ModifierMappings = NodePair.second;
843 1.1 joerg Visitor.Visit(NodePair.first);
844 1.1 joerg
845 1.1 joerg if (Lines.empty())
846 1.1 joerg continue;
847 1.1 joerg
848 1.1 joerg // We need a vertical separator if either this or the previous piece is a
849 1.1 joerg // multi-line piece, or this is the last piece.
850 1.1 joerg const char *Separator = (Lines.size() > 1 || HasMultipleLines) ? "|" : "";
851 1.1 joerg HasMultipleLines = Lines.size() > 1;
852 1.1 joerg
853 1.1 joerg if (Start + Lines.size() > RST.size())
854 1.1 joerg RST.resize(Start + Lines.size(), EmptyLinePrefix);
855 1.1 joerg
856 1.1 joerg padToSameLength(Lines.begin(), Lines.end());
857 1.1 joerg for (size_t I = 0; I != Lines.size(); ++I)
858 1.1 joerg RST[Start + I] += Separator + Lines[I];
859 1.1 joerg std::string Empty(Lines[0].size(), ' ');
860 1.1 joerg for (size_t I = Start + Lines.size(); I != RST.size(); ++I)
861 1.1 joerg RST[I] += Separator + Empty;
862 1.1 joerg EmptyLinePrefix += Separator + Empty;
863 1.1 joerg }
864 1.1 joerg for (size_t I = Start; I != RST.size(); ++I)
865 1.1 joerg RST[I] += "|";
866 1.1 joerg EmptyLinePrefix += "|";
867 1.1 joerg
868 1.1 joerg makeRowSeparator(EmptyLinePrefix);
869 1.1 joerg RST.insert(RST.begin() + Start, EmptyLinePrefix);
870 1.1 joerg RST.insert(RST.end(), EmptyLinePrefix);
871 1.1 joerg }
872 1.1 joerg
873 1.1 joerg void VisitText(TextPiece *P) {
874 1.1 joerg RST.push_back("");
875 1.1 joerg auto &S = RST.back();
876 1.1 joerg
877 1.1 joerg StringRef T = P->Text;
878 1.1 joerg while (!T.empty() && T.front() == ' ') {
879 1.1 joerg RST.back() += " |nbsp| ";
880 1.1 joerg T = T.drop_front();
881 1.1 joerg }
882 1.1 joerg
883 1.1 joerg std::string Suffix;
884 1.1 joerg while (!T.empty() && T.back() == ' ') {
885 1.1 joerg Suffix += " |nbsp| ";
886 1.1 joerg T = T.drop_back();
887 1.1 joerg }
888 1.1 joerg
889 1.1 joerg if (!T.empty()) {
890 1.1 joerg S += ':';
891 1.1 joerg S += P->Role;
892 1.1 joerg S += ":`";
893 1.1 joerg escapeRST(T, S);
894 1.1 joerg S += '`';
895 1.1 joerg }
896 1.1 joerg
897 1.1 joerg S += Suffix;
898 1.1 joerg }
899 1.1 joerg
900 1.1 joerg void VisitPlaceholder(PlaceholderPiece *P) {
901 1.1 joerg RST.push_back(std::string(":placeholder:`") +
902 1.1 joerg char('A' + mapIndex(P->Index)) + "`");
903 1.1 joerg }
904 1.1 joerg
905 1.1 joerg void VisitSelect(SelectPiece *P) {
906 1.1 joerg std::vector<size_t> SeparatorIndexes;
907 1.1 joerg SeparatorIndexes.push_back(RST.size());
908 1.1 joerg RST.emplace_back();
909 1.1 joerg for (auto *O : P->Options) {
910 1.1 joerg Visit(O);
911 1.1 joerg SeparatorIndexes.push_back(RST.size());
912 1.1 joerg RST.emplace_back();
913 1.1 joerg }
914 1.1 joerg
915 1.1 joerg makeTableRows(RST.begin() + SeparatorIndexes.front(),
916 1.1 joerg RST.begin() + SeparatorIndexes.back() + 1);
917 1.1 joerg for (size_t I : SeparatorIndexes)
918 1.1 joerg makeRowSeparator(RST[I]);
919 1.1 joerg }
920 1.1 joerg
921 1.1 joerg void VisitPlural(PluralPiece *P) { VisitSelect(P); }
922 1.1 joerg
923 1.1 joerg void VisitDiff(DiffPiece *P) { Visit(P->Options[1]); }
924 1.1 joerg
925 1.1 joerg std::vector<std::string> &RST;
926 1.1 joerg };
927 1.1 joerg
928 1.1 joerg struct DiagTextPrinter : DiagTextVisitor<DiagTextPrinter> {
929 1.1 joerg public:
930 1.1 joerg using BaseTy = DiagTextVisitor<DiagTextPrinter>;
931 1.1 joerg DiagTextPrinter(DiagnosticTextBuilder &Builder, std::string &Result)
932 1.1 joerg : BaseTy(Builder), Result(Result) {}
933 1.1 joerg
934 1.1 joerg void VisitMulti(MultiPiece *P) {
935 1.1 joerg for (auto *Child : P->Pieces)
936 1.1 joerg Visit(Child);
937 1.1 joerg }
938 1.1 joerg void VisitText(TextPiece *P) { Result += P->Text; }
939 1.1 joerg void VisitPlaceholder(PlaceholderPiece *P) {
940 1.1 joerg Result += "%";
941 1.1 joerg Result += getModifierName(P->Kind);
942 1.1 joerg addInt(mapIndex(P->Index));
943 1.1 joerg }
944 1.1 joerg void VisitSelect(SelectPiece *P) {
945 1.1 joerg Result += "%";
946 1.1 joerg Result += getModifierName(P->ModKind);
947 1.1 joerg if (P->ModKind == MT_Select) {
948 1.1 joerg Result += "{";
949 1.1 joerg for (auto *D : P->Options) {
950 1.1 joerg Visit(D);
951 1.1 joerg Result += '|';
952 1.1 joerg }
953 1.1 joerg if (!P->Options.empty())
954 1.1 joerg Result.erase(--Result.end());
955 1.1 joerg Result += '}';
956 1.1 joerg }
957 1.1 joerg addInt(mapIndex(P->Index));
958 1.1 joerg }
959 1.1 joerg
960 1.1 joerg void VisitPlural(PluralPiece *P) {
961 1.1 joerg Result += "%plural{";
962 1.1 joerg assert(P->Options.size() == P->OptionPrefixes.size());
963 1.1 joerg for (unsigned I = 0, End = P->Options.size(); I < End; ++I) {
964 1.1 joerg if (P->OptionPrefixes[I])
965 1.1 joerg Visit(P->OptionPrefixes[I]);
966 1.1 joerg Visit(P->Options[I]);
967 1.1 joerg Result += "|";
968 1.1 joerg }
969 1.1 joerg if (!P->Options.empty())
970 1.1 joerg Result.erase(--Result.end());
971 1.1 joerg Result += '}';
972 1.1 joerg addInt(mapIndex(P->Index));
973 1.1 joerg }
974 1.1 joerg
975 1.1 joerg void VisitDiff(DiffPiece *P) {
976 1.1 joerg Result += "%diff{";
977 1.1 joerg Visit(P->Options[0]);
978 1.1 joerg Result += "|";
979 1.1 joerg Visit(P->Options[1]);
980 1.1 joerg Result += "}";
981 1.1 joerg addInt(mapIndex(P->Indexes[0]));
982 1.1 joerg Result += ",";
983 1.1 joerg addInt(mapIndex(P->Indexes[1]));
984 1.1 joerg }
985 1.1 joerg
986 1.1 joerg void addInt(int Val) { Result += std::to_string(Val); }
987 1.1 joerg
988 1.1 joerg std::string &Result;
989 1.1 joerg };
990 1.1 joerg
991 1.1 joerg int DiagnosticTextBuilder::DiagText::parseModifier(StringRef &Text) const {
992 1.1 joerg if (Text.empty() || !isdigit(Text[0]))
993 1.1 joerg Builder.PrintFatalError("expected modifier in diagnostic");
994 1.1 joerg int Val = 0;
995 1.1 joerg do {
996 1.1 joerg Val *= 10;
997 1.1 joerg Val += Text[0] - '0';
998 1.1 joerg Text = Text.drop_front();
999 1.1 joerg } while (!Text.empty() && isdigit(Text[0]));
1000 1.1 joerg return Val;
1001 1.1 joerg }
1002 1.1 joerg
1003 1.1 joerg Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
1004 1.1 joerg bool Nested) {
1005 1.1 joerg std::vector<Piece *> Parsed;
1006 1.1 joerg
1007 1.1 joerg while (!Text.empty()) {
1008 1.1 joerg size_t End = (size_t)-2;
1009 1.1 joerg do
1010 1.1 joerg End = Nested ? Text.find_first_of("%|}", End + 2)
1011 1.1 joerg : Text.find_first_of('%', End + 2);
1012 1.1 joerg while (End < Text.size() - 1 && Text[End] == '%' &&
1013 1.1 joerg (Text[End + 1] == '%' || Text[End + 1] == '|'));
1014 1.1 joerg
1015 1.1 joerg if (End) {
1016 1.1 joerg Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext"));
1017 1.1 joerg Text = Text.slice(End, StringRef::npos);
1018 1.1 joerg if (Text.empty())
1019 1.1 joerg break;
1020 1.1 joerg }
1021 1.1 joerg
1022 1.1 joerg if (Text[0] == '|' || Text[0] == '}')
1023 1.1 joerg break;
1024 1.1 joerg
1025 1.1 joerg // Drop the '%'.
1026 1.1 joerg Text = Text.drop_front();
1027 1.1 joerg
1028 1.1 joerg // Extract the (optional) modifier.
1029 1.1 joerg size_t ModLength = Text.find_first_of("0123456789{");
1030 1.1 joerg StringRef Modifier = Text.slice(0, ModLength);
1031 1.1 joerg Text = Text.slice(ModLength, StringRef::npos);
1032 1.1 joerg ModifierType ModType = llvm::StringSwitch<ModifierType>{Modifier}
1033 1.1 joerg .Case("select", MT_Select)
1034 1.1 joerg .Case("sub", MT_Sub)
1035 1.1 joerg .Case("diff", MT_Diff)
1036 1.1 joerg .Case("plural", MT_Plural)
1037 1.1 joerg .Case("s", MT_S)
1038 1.1 joerg .Case("ordinal", MT_Ordinal)
1039 1.1 joerg .Case("q", MT_Q)
1040 1.1 joerg .Case("objcclass", MT_ObjCClass)
1041 1.1 joerg .Case("objcinstance", MT_ObjCInstance)
1042 1.1 joerg .Case("", MT_Placeholder)
1043 1.1 joerg .Default(MT_Unknown);
1044 1.1 joerg
1045 1.1 joerg switch (ModType) {
1046 1.1 joerg case MT_Unknown:
1047 1.1 joerg Builder.PrintFatalError("Unknown modifier type: " + Modifier);
1048 1.1 joerg case MT_Select: {
1049 1.1 joerg SelectPiece *Select = New<SelectPiece>(MT_Select);
1050 1.1 joerg do {
1051 1.1 joerg Text = Text.drop_front(); // '{' or '|'
1052 1.1 joerg Select->Options.push_back(parseDiagText(Text, true));
1053 1.1 joerg assert(!Text.empty() && "malformed %select");
1054 1.1 joerg } while (Text.front() == '|');
1055 1.1 joerg // Drop the trailing '}'.
1056 1.1 joerg Text = Text.drop_front(1);
1057 1.1 joerg Select->Index = parseModifier(Text);
1058 1.1 joerg Parsed.push_back(Select);
1059 1.1 joerg continue;
1060 1.1 joerg }
1061 1.1 joerg case MT_Plural: {
1062 1.1 joerg PluralPiece *Plural = New<PluralPiece>();
1063 1.1 joerg do {
1064 1.1 joerg Text = Text.drop_front(); // '{' or '|'
1065 1.1 joerg size_t End = Text.find_first_of(":");
1066 1.1 joerg if (End == StringRef::npos)
1067 1.1 joerg Builder.PrintFatalError("expected ':' while parsing %plural");
1068 1.1 joerg ++End;
1069 1.1 joerg assert(!Text.empty());
1070 1.1 joerg Plural->OptionPrefixes.push_back(
1071 1.1 joerg New<TextPiece>(Text.slice(0, End), "diagtext"));
1072 1.1 joerg Text = Text.slice(End, StringRef::npos);
1073 1.1 joerg Plural->Options.push_back(parseDiagText(Text, true));
1074 1.1 joerg assert(!Text.empty() && "malformed %select");
1075 1.1 joerg } while (Text.front() == '|');
1076 1.1 joerg // Drop the trailing '}'.
1077 1.1 joerg Text = Text.drop_front(1);
1078 1.1 joerg Plural->Index = parseModifier(Text);
1079 1.1 joerg Parsed.push_back(Plural);
1080 1.1 joerg continue;
1081 1.1 joerg }
1082 1.1 joerg case MT_Sub: {
1083 1.1 joerg SubstitutionPiece *Sub = New<SubstitutionPiece>();
1084 1.1 joerg Text = Text.drop_front(); // '{'
1085 1.1 joerg size_t NameSize = Text.find_first_of('}');
1086 1.1 joerg assert(NameSize != size_t(-1) && "failed to find the end of the name");
1087 1.1 joerg assert(NameSize != 0 && "empty name?");
1088 1.1 joerg Sub->Name = Text.substr(0, NameSize).str();
1089 1.1 joerg Text = Text.drop_front(NameSize);
1090 1.1 joerg Text = Text.drop_front(); // '}'
1091 1.1 joerg if (!Text.empty()) {
1092 1.1 joerg while (true) {
1093 1.1 joerg if (!isdigit(Text[0]))
1094 1.1 joerg break;
1095 1.1 joerg Sub->Modifiers.push_back(parseModifier(Text));
1096 1.1 joerg if (Text.empty() || Text[0] != ',')
1097 1.1 joerg break;
1098 1.1 joerg Text = Text.drop_front(); // ','
1099 1.1 joerg assert(!Text.empty() && isdigit(Text[0]) &&
1100 1.1 joerg "expected another modifier");
1101 1.1 joerg }
1102 1.1 joerg }
1103 1.1 joerg Parsed.push_back(Sub);
1104 1.1 joerg continue;
1105 1.1 joerg }
1106 1.1 joerg case MT_Diff: {
1107 1.1 joerg DiffPiece *Diff = New<DiffPiece>();
1108 1.1 joerg Text = Text.drop_front(); // '{'
1109 1.1 joerg Diff->Options[0] = parseDiagText(Text, true);
1110 1.1 joerg Text = Text.drop_front(); // '|'
1111 1.1 joerg Diff->Options[1] = parseDiagText(Text, true);
1112 1.1 joerg
1113 1.1 joerg Text = Text.drop_front(); // '}'
1114 1.1 joerg Diff->Indexes[0] = parseModifier(Text);
1115 1.1 joerg Text = Text.drop_front(); // ','
1116 1.1 joerg Diff->Indexes[1] = parseModifier(Text);
1117 1.1 joerg Parsed.push_back(Diff);
1118 1.1 joerg continue;
1119 1.1 joerg }
1120 1.1 joerg case MT_S: {
1121 1.1 joerg SelectPiece *Select = New<SelectPiece>(ModType);
1122 1.1 joerg Select->Options.push_back(New<TextPiece>(""));
1123 1.1 joerg Select->Options.push_back(New<TextPiece>("s", "diagtext"));
1124 1.1 joerg Select->Index = parseModifier(Text);
1125 1.1 joerg Parsed.push_back(Select);
1126 1.1 joerg continue;
1127 1.1 joerg }
1128 1.1 joerg case MT_Q:
1129 1.1 joerg case MT_Placeholder:
1130 1.1 joerg case MT_ObjCClass:
1131 1.1 joerg case MT_ObjCInstance:
1132 1.1 joerg case MT_Ordinal: {
1133 1.1 joerg Parsed.push_back(New<PlaceholderPiece>(ModType, parseModifier(Text)));
1134 1.1 joerg continue;
1135 1.1 joerg }
1136 1.1 joerg }
1137 1.1 joerg }
1138 1.1 joerg
1139 1.1 joerg return New<MultiPiece>(Parsed);
1140 1.1 joerg }
1141 1.1 joerg
1142 1.1 joerg std::vector<std::string>
1143 1.1 joerg DiagnosticTextBuilder::buildForDocumentation(StringRef Severity,
1144 1.1 joerg const Record *R) {
1145 1.1 joerg EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
1146 1.1 joerg StringRef Text = R->getValueAsString("Text");
1147 1.1 joerg
1148 1.1 joerg DiagText D(*this, Text);
1149 1.1 joerg TextPiece *Prefix = D.New<TextPiece>(Severity, Severity);
1150 1.1 joerg Prefix->Text += ": ";
1151 1.1 joerg auto *MP = dyn_cast<MultiPiece>(D.Root);
1152 1.1 joerg if (!MP) {
1153 1.1 joerg MP = D.New<MultiPiece>();
1154 1.1 joerg MP->Pieces.push_back(D.Root);
1155 1.1 joerg D.Root = MP;
1156 1.1 joerg }
1157 1.1 joerg MP->Pieces.insert(MP->Pieces.begin(), Prefix);
1158 1.1 joerg std::vector<std::string> Result;
1159 1.1 joerg DiagTextDocPrinter{*this, Result}.Visit(D.Root);
1160 1.1 joerg return Result;
1161 1.1 joerg }
1162 1.1 joerg
1163 1.1 joerg std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) {
1164 1.1 joerg EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
1165 1.1 joerg StringRef Text = R->getValueAsString("Text");
1166 1.1 joerg DiagText D(*this, Text);
1167 1.1 joerg std::string Result;
1168 1.1 joerg DiagTextPrinter{*this, Result}.Visit(D.Root);
1169 1.1 joerg return Result;
1170 1.1 joerg }
1171 1.1 joerg
1172 1.1 joerg } // namespace
1173 1.1 joerg
1174 1.1 joerg //===----------------------------------------------------------------------===//
1175 1.1 joerg // Warning Tables (.inc file) generation.
1176 1.1 joerg //===----------------------------------------------------------------------===//
1177 1.1 joerg
1178 1.1 joerg static bool isError(const Record &Diag) {
1179 1.1 joerg const std::string &ClsName = Diag.getValueAsDef("Class")->getName();
1180 1.1 joerg return ClsName == "CLASS_ERROR";
1181 1.1 joerg }
1182 1.1 joerg
1183 1.1 joerg static bool isRemark(const Record &Diag) {
1184 1.1 joerg const std::string &ClsName = Diag.getValueAsDef("Class")->getName();
1185 1.1 joerg return ClsName == "CLASS_REMARK";
1186 1.1 joerg }
1187 1.1 joerg
1188 1.1 joerg
1189 1.1 joerg /// ClangDiagsDefsEmitter - The top-level class emits .def files containing
1190 1.1 joerg /// declarations of Clang diagnostics.
1191 1.1 joerg void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
1192 1.1 joerg const std::string &Component) {
1193 1.1 joerg // Write the #if guard
1194 1.1 joerg if (!Component.empty()) {
1195 1.1 joerg std::string ComponentName = StringRef(Component).upper();
1196 1.1 joerg OS << "#ifdef " << ComponentName << "START\n";
1197 1.1 joerg OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
1198 1.1 joerg << ",\n";
1199 1.1 joerg OS << "#undef " << ComponentName << "START\n";
1200 1.1 joerg OS << "#endif\n\n";
1201 1.1 joerg }
1202 1.1 joerg
1203 1.1 joerg DiagnosticTextBuilder DiagTextBuilder(Records);
1204 1.1 joerg
1205 1.1 joerg std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
1206 1.1 joerg
1207 1.1 joerg std::vector<Record*> DiagGroups
1208 1.1 joerg = Records.getAllDerivedDefinitions("DiagGroup");
1209 1.1 joerg
1210 1.1 joerg std::map<std::string, GroupInfo> DiagsInGroup;
1211 1.1 joerg groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1212 1.1 joerg
1213 1.1 joerg DiagCategoryIDMap CategoryIDs(Records);
1214 1.1 joerg DiagGroupParentMap DGParentMap(Records);
1215 1.1 joerg
1216 1.1 joerg // Compute the set of diagnostics that are in -Wpedantic.
1217 1.1 joerg RecordSet DiagsInPedantic;
1218 1.1 joerg InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1219 1.1 joerg inferPedantic.compute(&DiagsInPedantic, (RecordVec*)nullptr);
1220 1.1 joerg
1221 1.1 joerg for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
1222 1.1 joerg const Record &R = *Diags[i];
1223 1.1 joerg
1224 1.1 joerg // Check if this is an error that is accidentally in a warning
1225 1.1 joerg // group.
1226 1.1 joerg if (isError(R)) {
1227 1.1 joerg if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) {
1228 1.1 joerg const Record *GroupRec = Group->getDef();
1229 1.1 joerg const std::string &GroupName = GroupRec->getValueAsString("GroupName");
1230 1.1 joerg PrintFatalError(R.getLoc(), "Error " + R.getName() +
1231 1.1 joerg " cannot be in a warning group [" + GroupName + "]");
1232 1.1 joerg }
1233 1.1 joerg }
1234 1.1 joerg
1235 1.1 joerg // Check that all remarks have an associated diagnostic group.
1236 1.1 joerg if (isRemark(R)) {
1237 1.1 joerg if (!isa<DefInit>(R.getValueInit("Group"))) {
1238 1.1 joerg PrintFatalError(R.getLoc(), "Error " + R.getName() +
1239 1.1 joerg " not in any diagnostic group");
1240 1.1 joerg }
1241 1.1 joerg }
1242 1.1 joerg
1243 1.1 joerg // Filter by component.
1244 1.1 joerg if (!Component.empty() && Component != R.getValueAsString("Component"))
1245 1.1 joerg continue;
1246 1.1 joerg
1247 1.1 joerg OS << "DIAG(" << R.getName() << ", ";
1248 1.1 joerg OS << R.getValueAsDef("Class")->getName();
1249 1.1 joerg OS << ", (unsigned)diag::Severity::"
1250 1.1 joerg << R.getValueAsDef("DefaultSeverity")->getValueAsString("Name");
1251 1.1 joerg
1252 1.1 joerg // Description string.
1253 1.1 joerg OS << ", \"";
1254 1.1 joerg OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"';
1255 1.1 joerg
1256 1.1 joerg // Warning associated with the diagnostic. This is stored as an index into
1257 1.1 joerg // the alphabetically sorted warning table.
1258 1.1 joerg if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
1259 1.1 joerg std::map<std::string, GroupInfo>::iterator I =
1260 1.1 joerg DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName"));
1261 1.1 joerg assert(I != DiagsInGroup.end());
1262 1.1 joerg OS << ", " << I->second.IDNo;
1263 1.1 joerg } else if (DiagsInPedantic.count(&R)) {
1264 1.1 joerg std::map<std::string, GroupInfo>::iterator I =
1265 1.1 joerg DiagsInGroup.find("pedantic");
1266 1.1 joerg assert(I != DiagsInGroup.end() && "pedantic group not defined");
1267 1.1 joerg OS << ", " << I->second.IDNo;
1268 1.1 joerg } else {
1269 1.1 joerg OS << ", 0";
1270 1.1 joerg }
1271 1.1 joerg
1272 1.1 joerg // SFINAE response.
1273 1.1 joerg OS << ", " << R.getValueAsDef("SFINAE")->getName();
1274 1.1 joerg
1275 1.1 joerg // Default warning has no Werror bit.
1276 1.1 joerg if (R.getValueAsBit("WarningNoWerror"))
1277 1.1 joerg OS << ", true";
1278 1.1 joerg else
1279 1.1 joerg OS << ", false";
1280 1.1 joerg
1281 1.1 joerg if (R.getValueAsBit("ShowInSystemHeader"))
1282 1.1 joerg OS << ", true";
1283 1.1 joerg else
1284 1.1 joerg OS << ", false";
1285 1.1 joerg
1286 1.1 joerg // Category number.
1287 1.1 joerg OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
1288 1.1 joerg OS << ")\n";
1289 1.1 joerg }
1290 1.1 joerg }
1291 1.1 joerg
1292 1.1 joerg //===----------------------------------------------------------------------===//
1293 1.1 joerg // Warning Group Tables generation
1294 1.1 joerg //===----------------------------------------------------------------------===//
1295 1.1 joerg
1296 1.1 joerg static std::string getDiagCategoryEnum(llvm::StringRef name) {
1297 1.1 joerg if (name.empty())
1298 1.1 joerg return "DiagCat_None";
1299 1.1 joerg SmallString<256> enumName = llvm::StringRef("DiagCat_");
1300 1.1 joerg for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
1301 1.1 joerg enumName += isalnum(*I) ? *I : '_';
1302 1.1 joerg return enumName.str();
1303 1.1 joerg }
1304 1.1 joerg
1305 1.1 joerg /// Emit the array of diagnostic subgroups.
1306 1.1 joerg ///
1307 1.1 joerg /// The array of diagnostic subgroups contains for each group a list of its
1308 1.1 joerg /// subgroups. The individual lists are separated by '-1'. Groups with no
1309 1.1 joerg /// subgroups are skipped.
1310 1.1 joerg ///
1311 1.1 joerg /// \code
1312 1.1 joerg /// static const int16_t DiagSubGroups[] = {
1313 1.1 joerg /// /* Empty */ -1,
1314 1.1 joerg /// /* DiagSubGroup0 */ 142, -1,
1315 1.1 joerg /// /* DiagSubGroup13 */ 265, 322, 399, -1
1316 1.1 joerg /// }
1317 1.1 joerg /// \endcode
1318 1.1 joerg ///
1319 1.1 joerg static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup,
1320 1.1 joerg RecordVec &GroupsInPedantic, raw_ostream &OS) {
1321 1.1 joerg OS << "static const int16_t DiagSubGroups[] = {\n"
1322 1.1 joerg << " /* Empty */ -1,\n";
1323 1.1 joerg for (auto const &I : DiagsInGroup) {
1324 1.1 joerg const bool IsPedantic = I.first == "pedantic";
1325 1.1 joerg
1326 1.1 joerg const std::vector<std::string> &SubGroups = I.second.SubGroups;
1327 1.1 joerg if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
1328 1.1 joerg OS << " /* DiagSubGroup" << I.second.IDNo << " */ ";
1329 1.1 joerg for (auto const &SubGroup : SubGroups) {
1330 1.1 joerg std::map<std::string, GroupInfo>::const_iterator RI =
1331 1.1 joerg DiagsInGroup.find(SubGroup);
1332 1.1 joerg assert(RI != DiagsInGroup.end() && "Referenced without existing?");
1333 1.1 joerg OS << RI->second.IDNo << ", ";
1334 1.1 joerg }
1335 1.1 joerg // Emit the groups implicitly in "pedantic".
1336 1.1 joerg if (IsPedantic) {
1337 1.1 joerg for (auto const &Group : GroupsInPedantic) {
1338 1.1 joerg const std::string &GroupName = Group->getValueAsString("GroupName");
1339 1.1 joerg std::map<std::string, GroupInfo>::const_iterator RI =
1340 1.1 joerg DiagsInGroup.find(GroupName);
1341 1.1 joerg assert(RI != DiagsInGroup.end() && "Referenced without existing?");
1342 1.1 joerg OS << RI->second.IDNo << ", ";
1343 1.1 joerg }
1344 1.1 joerg }
1345 1.1 joerg
1346 1.1 joerg OS << "-1,\n";
1347 1.1 joerg }
1348 1.1 joerg }
1349 1.1 joerg OS << "};\n\n";
1350 1.1 joerg }
1351 1.1 joerg
1352 1.1 joerg /// Emit the list of diagnostic arrays.
1353 1.1 joerg ///
1354 1.1 joerg /// This data structure is a large array that contains itself arrays of varying
1355 1.1 joerg /// size. Each array represents a list of diagnostics. The different arrays are
1356 1.1 joerg /// separated by the value '-1'.
1357 1.1 joerg ///
1358 1.1 joerg /// \code
1359 1.1 joerg /// static const int16_t DiagArrays[] = {
1360 1.1 joerg /// /* Empty */ -1,
1361 1.1 joerg /// /* DiagArray1 */ diag::warn_pragma_message,
1362 1.1 joerg /// -1,
1363 1.1 joerg /// /* DiagArray2 */ diag::warn_abs_too_small,
1364 1.1 joerg /// diag::warn_unsigned_abs,
1365 1.1 joerg /// diag::warn_wrong_absolute_value_type,
1366 1.1 joerg /// -1
1367 1.1 joerg /// };
1368 1.1 joerg /// \endcode
1369 1.1 joerg ///
1370 1.1 joerg static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
1371 1.1 joerg RecordVec &DiagsInPedantic, raw_ostream &OS) {
1372 1.1 joerg OS << "static const int16_t DiagArrays[] = {\n"
1373 1.1 joerg << " /* Empty */ -1,\n";
1374 1.1 joerg for (auto const &I : DiagsInGroup) {
1375 1.1 joerg const bool IsPedantic = I.first == "pedantic";
1376 1.1 joerg
1377 1.1 joerg const std::vector<const Record *> &V = I.second.DiagsInGroup;
1378 1.1 joerg if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
1379 1.1 joerg OS << " /* DiagArray" << I.second.IDNo << " */ ";
1380 1.1 joerg for (auto *Record : V)
1381 1.1 joerg OS << "diag::" << Record->getName() << ", ";
1382 1.1 joerg // Emit the diagnostics implicitly in "pedantic".
1383 1.1 joerg if (IsPedantic) {
1384 1.1 joerg for (auto const &Diag : DiagsInPedantic)
1385 1.1 joerg OS << "diag::" << Diag->getName() << ", ";
1386 1.1 joerg }
1387 1.1 joerg OS << "-1,\n";
1388 1.1 joerg }
1389 1.1 joerg }
1390 1.1 joerg OS << "};\n\n";
1391 1.1 joerg }
1392 1.1 joerg
1393 1.1 joerg /// Emit a list of group names.
1394 1.1 joerg ///
1395 1.1 joerg /// This creates a long string which by itself contains a list of pascal style
1396 1.1 joerg /// strings, which consist of a length byte directly followed by the string.
1397 1.1 joerg ///
1398 1.1 joerg /// \code
1399 1.1 joerg /// static const char DiagGroupNames[] = {
1400 1.1 joerg /// \000\020#pragma-messages\t#warnings\020CFString-literal"
1401 1.1 joerg /// };
1402 1.1 joerg /// \endcode
1403 1.1 joerg static void emitDiagGroupNames(StringToOffsetTable &GroupNames,
1404 1.1 joerg raw_ostream &OS) {
1405 1.1 joerg OS << "static const char DiagGroupNames[] = {\n";
1406 1.1 joerg GroupNames.EmitString(OS);
1407 1.1 joerg OS << "};\n\n";
1408 1.1 joerg }
1409 1.1 joerg
1410 1.1 joerg /// Emit diagnostic arrays and related data structures.
1411 1.1 joerg ///
1412 1.1 joerg /// This creates the actual diagnostic array, an array of diagnostic subgroups
1413 1.1 joerg /// and an array of subgroup names.
1414 1.1 joerg ///
1415 1.1 joerg /// \code
1416 1.1 joerg /// #ifdef GET_DIAG_ARRAYS
1417 1.1 joerg /// static const int16_t DiagArrays[];
1418 1.1 joerg /// static const int16_t DiagSubGroups[];
1419 1.1 joerg /// static const char DiagGroupNames[];
1420 1.1 joerg /// #endif
1421 1.1 joerg /// \endcode
1422 1.1 joerg static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
1423 1.1 joerg RecordVec &DiagsInPedantic,
1424 1.1 joerg RecordVec &GroupsInPedantic,
1425 1.1 joerg StringToOffsetTable &GroupNames,
1426 1.1 joerg raw_ostream &OS) {
1427 1.1 joerg OS << "\n#ifdef GET_DIAG_ARRAYS\n";
1428 1.1 joerg emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS);
1429 1.1 joerg emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS);
1430 1.1 joerg emitDiagGroupNames(GroupNames, OS);
1431 1.1 joerg OS << "#endif // GET_DIAG_ARRAYS\n\n";
1432 1.1 joerg }
1433 1.1 joerg
1434 1.1 joerg /// Emit diagnostic table.
1435 1.1 joerg ///
1436 1.1 joerg /// The table is sorted by the name of the diagnostic group. Each element
1437 1.1 joerg /// consists of the name of the diagnostic group (given as offset in the
1438 1.1 joerg /// group name table), a reference to a list of diagnostics (optional) and a
1439 1.1 joerg /// reference to a set of subgroups (optional).
1440 1.1 joerg ///
1441 1.1 joerg /// \code
1442 1.1 joerg /// #ifdef GET_DIAG_TABLE
1443 1.1 joerg /// {/* abi */ 159, /* DiagArray11 */ 19, /* Empty */ 0},
1444 1.1 joerg /// {/* aggregate-return */ 180, /* Empty */ 0, /* Empty */ 0},
1445 1.1 joerg /// {/* all */ 197, /* Empty */ 0, /* DiagSubGroup13 */ 3},
1446 1.1 joerg /// {/* deprecated */ 1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */ 9},
1447 1.1 joerg /// #endif
1448 1.1 joerg /// \endcode
1449 1.1 joerg static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup,
1450 1.1 joerg RecordVec &DiagsInPedantic,
1451 1.1 joerg RecordVec &GroupsInPedantic,
1452 1.1 joerg StringToOffsetTable &GroupNames, raw_ostream &OS) {
1453 1.1 joerg unsigned MaxLen = 0;
1454 1.1 joerg
1455 1.1 joerg for (auto const &I: DiagsInGroup)
1456 1.1 joerg MaxLen = std::max(MaxLen, (unsigned)I.first.size());
1457 1.1 joerg
1458 1.1 joerg OS << "\n#ifdef GET_DIAG_TABLE\n";
1459 1.1 joerg unsigned SubGroupIndex = 1, DiagArrayIndex = 1;
1460 1.1 joerg for (auto const &I: DiagsInGroup) {
1461 1.1 joerg // Group option string.
1462 1.1 joerg OS << " { /* ";
1463 1.1 joerg if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
1464 1.1 joerg "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1465 1.1 joerg "0123456789!@#$%^*-+=:?") !=
1466 1.1 joerg std::string::npos)
1467 1.1 joerg PrintFatalError("Invalid character in diagnostic group '" + I.first +
1468 1.1 joerg "'");
1469 1.1 joerg OS << I.first << " */ " << std::string(MaxLen - I.first.size(), ' ');
1470 1.1 joerg // Store a pascal-style length byte at the beginning of the string.
1471 1.1 joerg std::string Name = char(I.first.size()) + I.first;
1472 1.1 joerg OS << GroupNames.GetOrAddStringOffset(Name, false) << ", ";
1473 1.1 joerg
1474 1.1 joerg // Special handling for 'pedantic'.
1475 1.1 joerg const bool IsPedantic = I.first == "pedantic";
1476 1.1 joerg
1477 1.1 joerg // Diagnostics in the group.
1478 1.1 joerg const std::vector<const Record *> &V = I.second.DiagsInGroup;
1479 1.1 joerg const bool hasDiags =
1480 1.1 joerg !V.empty() || (IsPedantic && !DiagsInPedantic.empty());
1481 1.1 joerg if (hasDiags) {
1482 1.1 joerg OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex
1483 1.1 joerg << ", ";
1484 1.1 joerg if (IsPedantic)
1485 1.1 joerg DiagArrayIndex += DiagsInPedantic.size();
1486 1.1 joerg DiagArrayIndex += V.size() + 1;
1487 1.1 joerg } else {
1488 1.1 joerg OS << "/* Empty */ 0, ";
1489 1.1 joerg }
1490 1.1 joerg
1491 1.1 joerg // Subgroups.
1492 1.1 joerg const std::vector<std::string> &SubGroups = I.second.SubGroups;
1493 1.1 joerg const bool hasSubGroups =
1494 1.1 joerg !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty());
1495 1.1 joerg if (hasSubGroups) {
1496 1.1 joerg OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex;
1497 1.1 joerg if (IsPedantic)
1498 1.1 joerg SubGroupIndex += GroupsInPedantic.size();
1499 1.1 joerg SubGroupIndex += SubGroups.size() + 1;
1500 1.1 joerg } else {
1501 1.1 joerg OS << "/* Empty */ 0";
1502 1.1 joerg }
1503 1.1 joerg
1504 1.1 joerg OS << " },\n";
1505 1.1 joerg }
1506 1.1 joerg OS << "#endif // GET_DIAG_TABLE\n\n";
1507 1.1 joerg }
1508 1.1 joerg
1509 1.1 joerg /// Emit the table of diagnostic categories.
1510 1.1 joerg ///
1511 1.1 joerg /// The table has the form of macro calls that have two parameters. The
1512 1.1 joerg /// category's name as well as an enum that represents the category. The
1513 1.1 joerg /// table can be used by defining the macro 'CATEGORY' and including this
1514 1.1 joerg /// table right after.
1515 1.1 joerg ///
1516 1.1 joerg /// \code
1517 1.1 joerg /// #ifdef GET_CATEGORY_TABLE
1518 1.1 joerg /// CATEGORY("Semantic Issue", DiagCat_Semantic_Issue)
1519 1.1 joerg /// CATEGORY("Lambda Issue", DiagCat_Lambda_Issue)
1520 1.1 joerg /// #endif
1521 1.1 joerg /// \endcode
1522 1.1 joerg static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) {
1523 1.1 joerg DiagCategoryIDMap CategoriesByID(Records);
1524 1.1 joerg OS << "\n#ifdef GET_CATEGORY_TABLE\n";
1525 1.1 joerg for (auto const &C : CategoriesByID)
1526 1.1 joerg OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n";
1527 1.1 joerg OS << "#endif // GET_CATEGORY_TABLE\n\n";
1528 1.1 joerg }
1529 1.1 joerg
1530 1.1 joerg void clang::EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
1531 1.1 joerg // Compute a mapping from a DiagGroup to all of its parents.
1532 1.1 joerg DiagGroupParentMap DGParentMap(Records);
1533 1.1 joerg
1534 1.1 joerg std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
1535 1.1 joerg
1536 1.1 joerg std::vector<Record *> DiagGroups =
1537 1.1 joerg Records.getAllDerivedDefinitions("DiagGroup");
1538 1.1 joerg
1539 1.1 joerg std::map<std::string, GroupInfo> DiagsInGroup;
1540 1.1 joerg groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1541 1.1 joerg
1542 1.1 joerg // All extensions are implicitly in the "pedantic" group. Record the
1543 1.1 joerg // implicit set of groups in the "pedantic" group, and use this information
1544 1.1 joerg // later when emitting the group information for Pedantic.
1545 1.1 joerg RecordVec DiagsInPedantic;
1546 1.1 joerg RecordVec GroupsInPedantic;
1547 1.1 joerg InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1548 1.1 joerg inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
1549 1.1 joerg
1550 1.1 joerg StringToOffsetTable GroupNames;
1551 1.1 joerg for (std::map<std::string, GroupInfo>::const_iterator
1552 1.1 joerg I = DiagsInGroup.begin(),
1553 1.1 joerg E = DiagsInGroup.end();
1554 1.1 joerg I != E; ++I) {
1555 1.1 joerg // Store a pascal-style length byte at the beginning of the string.
1556 1.1 joerg std::string Name = char(I->first.size()) + I->first;
1557 1.1 joerg GroupNames.GetOrAddStringOffset(Name, false);
1558 1.1 joerg }
1559 1.1 joerg
1560 1.1 joerg emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
1561 1.1 joerg OS);
1562 1.1 joerg emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
1563 1.1 joerg OS);
1564 1.1 joerg emitCategoryTable(Records, OS);
1565 1.1 joerg }
1566 1.1 joerg
1567 1.1 joerg //===----------------------------------------------------------------------===//
1568 1.1 joerg // Diagnostic name index generation
1569 1.1 joerg //===----------------------------------------------------------------------===//
1570 1.1 joerg
1571 1.1 joerg namespace {
1572 1.1 joerg struct RecordIndexElement
1573 1.1 joerg {
1574 1.1 joerg RecordIndexElement() {}
1575 1.1 joerg explicit RecordIndexElement(Record const &R):
1576 1.1 joerg Name(R.getName()) {}
1577 1.1 joerg
1578 1.1 joerg std::string Name;
1579 1.1 joerg };
1580 1.1 joerg } // end anonymous namespace.
1581 1.1 joerg
1582 1.1 joerg void clang::EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
1583 1.1 joerg const std::vector<Record*> &Diags =
1584 1.1 joerg Records.getAllDerivedDefinitions("Diagnostic");
1585 1.1 joerg
1586 1.1 joerg std::vector<RecordIndexElement> Index;
1587 1.1 joerg Index.reserve(Diags.size());
1588 1.1 joerg for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
1589 1.1 joerg const Record &R = *(Diags[i]);
1590 1.1 joerg Index.push_back(RecordIndexElement(R));
1591 1.1 joerg }
1592 1.1 joerg
1593 1.1 joerg llvm::sort(Index,
1594 1.1 joerg [](const RecordIndexElement &Lhs, const RecordIndexElement &Rhs) {
1595 1.1 joerg return Lhs.Name < Rhs.Name;
1596 1.1 joerg });
1597 1.1 joerg
1598 1.1 joerg for (unsigned i = 0, e = Index.size(); i != e; ++i) {
1599 1.1 joerg const RecordIndexElement &R = Index[i];
1600 1.1 joerg
1601 1.1 joerg OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
1602 1.1 joerg }
1603 1.1 joerg }
1604 1.1 joerg
1605 1.1 joerg //===----------------------------------------------------------------------===//
1606 1.1 joerg // Diagnostic documentation generation
1607 1.1 joerg //===----------------------------------------------------------------------===//
1608 1.1 joerg
1609 1.1 joerg namespace docs {
1610 1.1 joerg namespace {
1611 1.1 joerg
1612 1.1 joerg bool isRemarkGroup(const Record *DiagGroup,
1613 1.1 joerg const std::map<std::string, GroupInfo> &DiagsInGroup) {
1614 1.1 joerg bool AnyRemarks = false, AnyNonRemarks = false;
1615 1.1 joerg
1616 1.1 joerg std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
1617 1.1 joerg auto &GroupInfo = DiagsInGroup.find(GroupName)->second;
1618 1.1 joerg for (const Record *Diag : GroupInfo.DiagsInGroup)
1619 1.1 joerg (isRemark(*Diag) ? AnyRemarks : AnyNonRemarks) = true;
1620 1.1 joerg for (const auto &Name : GroupInfo.SubGroups)
1621 1.1 joerg Visit(Name);
1622 1.1 joerg };
1623 1.1 joerg Visit(DiagGroup->getValueAsString("GroupName"));
1624 1.1 joerg
1625 1.1 joerg if (AnyRemarks && AnyNonRemarks)
1626 1.1 joerg PrintFatalError(
1627 1.1 joerg DiagGroup->getLoc(),
1628 1.1 joerg "Diagnostic group contains both remark and non-remark diagnostics");
1629 1.1 joerg return AnyRemarks;
1630 1.1 joerg }
1631 1.1 joerg
1632 1.1 joerg std::string getDefaultSeverity(const Record *Diag) {
1633 1.1 joerg return Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name");
1634 1.1 joerg }
1635 1.1 joerg
1636 1.1 joerg std::set<std::string>
1637 1.1 joerg getDefaultSeverities(const Record *DiagGroup,
1638 1.1 joerg const std::map<std::string, GroupInfo> &DiagsInGroup) {
1639 1.1 joerg std::set<std::string> States;
1640 1.1 joerg
1641 1.1 joerg std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
1642 1.1 joerg auto &GroupInfo = DiagsInGroup.find(GroupName)->second;
1643 1.1 joerg for (const Record *Diag : GroupInfo.DiagsInGroup)
1644 1.1 joerg States.insert(getDefaultSeverity(Diag));
1645 1.1 joerg for (const auto &Name : GroupInfo.SubGroups)
1646 1.1 joerg Visit(Name);
1647 1.1 joerg };
1648 1.1 joerg Visit(DiagGroup->getValueAsString("GroupName"));
1649 1.1 joerg return States;
1650 1.1 joerg }
1651 1.1 joerg
1652 1.1 joerg void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
1653 1.1 joerg OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
1654 1.1 joerg }
1655 1.1 joerg
1656 1.1 joerg void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R,
1657 1.1 joerg StringRef Role, raw_ostream &OS) {
1658 1.1 joerg StringRef Text = R->getValueAsString("Text");
1659 1.1 joerg if (Text == "%0")
1660 1.1 joerg OS << "The text of this diagnostic is not controlled by Clang.\n\n";
1661 1.1 joerg else {
1662 1.1 joerg std::vector<std::string> Out = Builder.buildForDocumentation(Role, R);
1663 1.1 joerg for (auto &Line : Out)
1664 1.1 joerg OS << Line << "\n";
1665 1.1 joerg OS << "\n";
1666 1.1 joerg }
1667 1.1 joerg }
1668 1.1 joerg
1669 1.1 joerg } // namespace
1670 1.1 joerg } // namespace docs
1671 1.1 joerg
1672 1.1 joerg void clang::EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) {
1673 1.1 joerg using namespace docs;
1674 1.1 joerg
1675 1.1 joerg // Get the documentation introduction paragraph.
1676 1.1 joerg const Record *Documentation = Records.getDef("GlobalDocumentation");
1677 1.1 joerg if (!Documentation) {
1678 1.1 joerg PrintFatalError("The Documentation top-level definition is missing, "
1679 1.1 joerg "no documentation will be generated.");
1680 1.1 joerg return;
1681 1.1 joerg }
1682 1.1 joerg
1683 1.1 joerg OS << Documentation->getValueAsString("Intro") << "\n";
1684 1.1 joerg
1685 1.1 joerg DiagnosticTextBuilder Builder(Records);
1686 1.1 joerg
1687 1.1 joerg std::vector<Record*> Diags =
1688 1.1 joerg Records.getAllDerivedDefinitions("Diagnostic");
1689 1.1 joerg
1690 1.1 joerg std::vector<Record*> DiagGroups =
1691 1.1 joerg Records.getAllDerivedDefinitions("DiagGroup");
1692 1.1 joerg llvm::sort(DiagGroups, diagGroupBeforeByName);
1693 1.1 joerg
1694 1.1 joerg DiagGroupParentMap DGParentMap(Records);
1695 1.1 joerg
1696 1.1 joerg std::map<std::string, GroupInfo> DiagsInGroup;
1697 1.1 joerg groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1698 1.1 joerg
1699 1.1 joerg // Compute the set of diagnostics that are in -Wpedantic.
1700 1.1 joerg {
1701 1.1 joerg RecordSet DiagsInPedanticSet;
1702 1.1 joerg RecordSet GroupsInPedanticSet;
1703 1.1 joerg InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1704 1.1 joerg inferPedantic.compute(&DiagsInPedanticSet, &GroupsInPedanticSet);
1705 1.1 joerg auto &PedDiags = DiagsInGroup["pedantic"];
1706 1.1 joerg // Put the diagnostics into a deterministic order.
1707 1.1 joerg RecordVec DiagsInPedantic(DiagsInPedanticSet.begin(),
1708 1.1 joerg DiagsInPedanticSet.end());
1709 1.1 joerg RecordVec GroupsInPedantic(GroupsInPedanticSet.begin(),
1710 1.1 joerg GroupsInPedanticSet.end());
1711 1.1 joerg llvm::sort(DiagsInPedantic, beforeThanCompare);
1712 1.1 joerg llvm::sort(GroupsInPedantic, beforeThanCompare);
1713 1.1 joerg PedDiags.DiagsInGroup.insert(PedDiags.DiagsInGroup.end(),
1714 1.1 joerg DiagsInPedantic.begin(),
1715 1.1 joerg DiagsInPedantic.end());
1716 1.1 joerg for (auto *Group : GroupsInPedantic)
1717 1.1 joerg PedDiags.SubGroups.push_back(Group->getValueAsString("GroupName"));
1718 1.1 joerg }
1719 1.1 joerg
1720 1.1 joerg // FIXME: Write diagnostic categories and link to diagnostic groups in each.
1721 1.1 joerg
1722 1.1 joerg // Write out the diagnostic groups.
1723 1.1 joerg for (const Record *G : DiagGroups) {
1724 1.1 joerg bool IsRemarkGroup = isRemarkGroup(G, DiagsInGroup);
1725 1.1 joerg auto &GroupInfo = DiagsInGroup[G->getValueAsString("GroupName")];
1726 1.1 joerg bool IsSynonym = GroupInfo.DiagsInGroup.empty() &&
1727 1.1 joerg GroupInfo.SubGroups.size() == 1;
1728 1.1 joerg
1729 1.1 joerg writeHeader(((IsRemarkGroup ? "-R" : "-W") +
1730 1.1 joerg G->getValueAsString("GroupName")).str(),
1731 1.1 joerg OS);
1732 1.1 joerg
1733 1.1 joerg if (!IsSynonym) {
1734 1.1 joerg // FIXME: Ideally, all the diagnostics in a group should have the same
1735 1.1 joerg // default state, but that is not currently the case.
1736 1.1 joerg auto DefaultSeverities = getDefaultSeverities(G, DiagsInGroup);
1737 1.1 joerg if (!DefaultSeverities.empty() && !DefaultSeverities.count("Ignored")) {
1738 1.1 joerg bool AnyNonErrors = DefaultSeverities.count("Warning") ||
1739 1.1 joerg DefaultSeverities.count("Remark");
1740 1.1 joerg if (!AnyNonErrors)
1741 1.1 joerg OS << "This diagnostic is an error by default, but the flag ``-Wno-"
1742 1.1 joerg << G->getValueAsString("GroupName") << "`` can be used to disable "
1743 1.1 joerg << "the error.\n\n";
1744 1.1 joerg else
1745 1.1 joerg OS << "This diagnostic is enabled by default.\n\n";
1746 1.1 joerg } else if (DefaultSeverities.size() > 1) {
1747 1.1 joerg OS << "Some of the diagnostics controlled by this flag are enabled "
1748 1.1 joerg << "by default.\n\n";
1749 1.1 joerg }
1750 1.1 joerg }
1751 1.1 joerg
1752 1.1 joerg if (!GroupInfo.SubGroups.empty()) {
1753 1.1 joerg if (IsSynonym)
1754 1.1 joerg OS << "Synonym for ";
1755 1.1 joerg else if (GroupInfo.DiagsInGroup.empty())
1756 1.1 joerg OS << "Controls ";
1757 1.1 joerg else
1758 1.1 joerg OS << "Also controls ";
1759 1.1 joerg
1760 1.1 joerg bool First = true;
1761 1.1 joerg llvm::sort(GroupInfo.SubGroups);
1762 1.1 joerg for (const auto &Name : GroupInfo.SubGroups) {
1763 1.1 joerg if (!First) OS << ", ";
1764 1.1 joerg OS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_";
1765 1.1 joerg First = false;
1766 1.1 joerg }
1767 1.1 joerg OS << ".\n\n";
1768 1.1 joerg }
1769 1.1 joerg
1770 1.1 joerg if (!GroupInfo.DiagsInGroup.empty()) {
1771 1.1 joerg OS << "**Diagnostic text:**\n\n";
1772 1.1 joerg for (const Record *D : GroupInfo.DiagsInGroup) {
1773 1.1 joerg auto Severity = getDefaultSeverity(D);
1774 1.1 joerg Severity[0] = tolower(Severity[0]);
1775 1.1 joerg if (Severity == "ignored")
1776 1.1 joerg Severity = IsRemarkGroup ? "remark" : "warning";
1777 1.1 joerg
1778 1.1 joerg writeDiagnosticText(Builder, D, Severity, OS);
1779 1.1 joerg }
1780 1.1 joerg }
1781 1.1 joerg
1782 1.1 joerg auto Doc = G->getValueAsString("Documentation");
1783 1.1 joerg if (!Doc.empty())
1784 1.1 joerg OS << Doc;
1785 1.1 joerg else if (GroupInfo.SubGroups.empty() && GroupInfo.DiagsInGroup.empty())
1786 1.1 joerg OS << "This diagnostic flag exists for GCC compatibility, and has no "
1787 1.1 joerg "effect in Clang.\n";
1788 1.1 joerg OS << "\n";
1789 1.1 joerg }
1790 1.1 joerg }
1791