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