1 //=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // These tablegen backends emit Clang diagnostics tables.
11 //===----------------------------------------------------------------------===//
13 #include "TableGenBackends.h"
14 #include "llvm/ADT/DenseSet.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/StringSwitch.h"
22 #include "llvm/ADT/Twine.h"
23 #include "llvm/Support/Casting.h"
24 #include "llvm/TableGen/Error.h"
25 #include "llvm/TableGen/Record.h"
26 #include "llvm/TableGen/StringToOffsetTable.h"
27 #include "llvm/TableGen/TableGenBackend.h"
36 //===----------------------------------------------------------------------===//
37 // Diagnostic category computation code.
38 //===----------------------------------------------------------------------===//
41 class DiagGroupParentMap
{
42 RecordKeeper
&Records
;
43 std::map
<const Record
*, std::vector
<Record
*> > Mapping
;
45 DiagGroupParentMap(RecordKeeper
&records
) : Records(records
) {
46 std::vector
<Record
*> DiagGroups
47 = Records
.getAllDerivedDefinitions("DiagGroup");
48 for (unsigned i
= 0, e
= DiagGroups
.size(); i
!= e
; ++i
) {
49 std::vector
<Record
*> SubGroups
=
50 DiagGroups
[i
]->getValueAsListOfDefs("SubGroups");
51 for (unsigned j
= 0, e
= SubGroups
.size(); j
!= e
; ++j
)
52 Mapping
[SubGroups
[j
]].push_back(DiagGroups
[i
]);
56 const std::vector
<Record
*> &getParents(const Record
*Group
) {
57 return Mapping
[Group
];
60 } // end anonymous namespace.
63 getCategoryFromDiagGroup(const Record
*Group
,
64 DiagGroupParentMap
&DiagGroupParents
) {
65 // If the DiagGroup has a category, return it.
66 std::string CatName
= std::string(Group
->getValueAsString("CategoryName"));
67 if (!CatName
.empty()) return CatName
;
69 // The diag group may the subgroup of one or more other diagnostic groups,
70 // check these for a category as well.
71 const std::vector
<Record
*> &Parents
= DiagGroupParents
.getParents(Group
);
72 for (unsigned i
= 0, e
= Parents
.size(); i
!= e
; ++i
) {
73 CatName
= getCategoryFromDiagGroup(Parents
[i
], DiagGroupParents
);
74 if (!CatName
.empty()) return CatName
;
79 /// getDiagnosticCategory - Return the category that the specified diagnostic
81 static std::string
getDiagnosticCategory(const Record
*R
,
82 DiagGroupParentMap
&DiagGroupParents
) {
83 // If the diagnostic is in a group, and that group has a category, use it.
84 if (DefInit
*Group
= dyn_cast
<DefInit
>(R
->getValueInit("Group"))) {
85 // Check the diagnostic's diag group for a category.
86 std::string CatName
= getCategoryFromDiagGroup(Group
->getDef(),
88 if (!CatName
.empty()) return CatName
;
91 // If the diagnostic itself has a category, get it.
92 return std::string(R
->getValueAsString("CategoryName"));
96 class DiagCategoryIDMap
{
97 RecordKeeper
&Records
;
98 StringMap
<unsigned> CategoryIDs
;
99 std::vector
<std::string
> CategoryStrings
;
101 DiagCategoryIDMap(RecordKeeper
&records
) : Records(records
) {
102 DiagGroupParentMap
ParentInfo(Records
);
104 // The zero'th category is "".
105 CategoryStrings
.push_back("");
108 std::vector
<Record
*> Diags
=
109 Records
.getAllDerivedDefinitions("Diagnostic");
110 for (unsigned i
= 0, e
= Diags
.size(); i
!= e
; ++i
) {
111 std::string Category
= getDiagnosticCategory(Diags
[i
], ParentInfo
);
112 if (Category
.empty()) continue; // Skip diags with no category.
114 unsigned &ID
= CategoryIDs
[Category
];
115 if (ID
!= 0) continue; // Already seen.
117 ID
= CategoryStrings
.size();
118 CategoryStrings
.push_back(Category
);
122 unsigned getID(StringRef CategoryString
) {
123 return CategoryIDs
[CategoryString
];
126 typedef std::vector
<std::string
>::const_iterator const_iterator
;
127 const_iterator
begin() const { return CategoryStrings
.begin(); }
128 const_iterator
end() const { return CategoryStrings
.end(); }
132 llvm::StringRef GroupName
;
133 std::vector
<const Record
*> DiagsInGroup
;
134 std::vector
<std::string
> SubGroups
;
137 llvm::SmallVector
<const Record
*, 1> Defs
;
139 GroupInfo() = default;
141 } // end anonymous namespace.
143 static bool beforeThanCompare(const Record
*LHS
, const Record
*RHS
) {
144 assert(!LHS
->getLoc().empty() && !RHS
->getLoc().empty());
146 LHS
->getLoc().front().getPointer() < RHS
->getLoc().front().getPointer();
149 static bool diagGroupBeforeByName(const Record
*LHS
, const Record
*RHS
) {
150 return LHS
->getValueAsString("GroupName") <
151 RHS
->getValueAsString("GroupName");
154 /// Invert the 1-[0/1] mapping of diags to group into a one to many
155 /// mapping of groups to diags in the group.
156 static void groupDiagnostics(const std::vector
<Record
*> &Diags
,
157 const std::vector
<Record
*> &DiagGroups
,
158 std::map
<std::string
, GroupInfo
> &DiagsInGroup
) {
160 for (unsigned i
= 0, e
= Diags
.size(); i
!= e
; ++i
) {
161 const Record
*R
= Diags
[i
];
162 DefInit
*DI
= dyn_cast
<DefInit
>(R
->getValueInit("Group"));
165 assert(R
->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
166 "Note can't be in a DiagGroup");
167 std::string GroupName
=
168 std::string(DI
->getDef()->getValueAsString("GroupName"));
169 DiagsInGroup
[GroupName
].DiagsInGroup
.push_back(R
);
172 // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
173 // groups (these are warnings that GCC supports that clang never produces).
174 for (unsigned i
= 0, e
= DiagGroups
.size(); i
!= e
; ++i
) {
175 Record
*Group
= DiagGroups
[i
];
177 DiagsInGroup
[std::string(Group
->getValueAsString("GroupName"))];
178 GI
.GroupName
= Group
->getName();
179 GI
.Defs
.push_back(Group
);
181 std::vector
<Record
*> SubGroups
= Group
->getValueAsListOfDefs("SubGroups");
182 for (unsigned j
= 0, e
= SubGroups
.size(); j
!= e
; ++j
)
183 GI
.SubGroups
.push_back(
184 std::string(SubGroups
[j
]->getValueAsString("GroupName")));
187 // Assign unique ID numbers to the groups.
189 for (std::map
<std::string
, GroupInfo
>::iterator
190 I
= DiagsInGroup
.begin(), E
= DiagsInGroup
.end(); I
!= E
; ++I
, ++IDNo
)
191 I
->second
.IDNo
= IDNo
;
193 // Warn if the same group is defined more than once (including implicitly).
194 for (auto &Group
: DiagsInGroup
) {
195 if (Group
.second
.Defs
.size() == 1 &&
196 (!Group
.second
.Defs
.front()->isAnonymous() ||
197 Group
.second
.DiagsInGroup
.size() <= 1))
201 for (const Record
*Def
: Group
.second
.Defs
) {
202 // Skip implicit definitions from diagnostics; we'll report those
204 bool IsImplicit
= false;
205 for (const Record
*Diag
: Group
.second
.DiagsInGroup
) {
206 if (cast
<DefInit
>(Diag
->getValueInit("Group"))->getDef() == Def
) {
214 llvm::SMLoc Loc
= Def
->getLoc().front();
216 SrcMgr
.PrintMessage(Loc
, SourceMgr::DK_Error
,
217 Twine("group '") + Group
.first
+
218 "' is defined more than once");
221 SrcMgr
.PrintMessage(Loc
, SourceMgr::DK_Note
, "also defined here");
225 for (const Record
*Diag
: Group
.second
.DiagsInGroup
) {
226 if (!cast
<DefInit
>(Diag
->getValueInit("Group"))->getDef()->isAnonymous())
229 llvm::SMLoc Loc
= Diag
->getLoc().front();
231 SrcMgr
.PrintMessage(Loc
, SourceMgr::DK_Error
,
232 Twine("group '") + Group
.first
+
233 "' is implicitly defined more than once");
236 SrcMgr
.PrintMessage(Loc
, SourceMgr::DK_Note
,
237 "also implicitly defined here");
243 //===----------------------------------------------------------------------===//
244 // Infer members of -Wpedantic.
245 //===----------------------------------------------------------------------===//
247 typedef std::vector
<const Record
*> RecordVec
;
248 typedef llvm::DenseSet
<const Record
*> RecordSet
;
249 typedef llvm::PointerUnion
<RecordVec
*, RecordSet
*> VecOrSet
;
252 class InferPedantic
{
253 typedef llvm::DenseMap
<const Record
*,
254 std::pair
<unsigned, std::optional
<unsigned>>>
257 DiagGroupParentMap
&DiagGroupParents
;
258 const std::vector
<Record
*> &Diags
;
259 const std::vector
<Record
*> DiagGroups
;
260 std::map
<std::string
, GroupInfo
> &DiagsInGroup
;
261 llvm::DenseSet
<const Record
*> DiagsSet
;
264 InferPedantic(DiagGroupParentMap
&DiagGroupParents
,
265 const std::vector
<Record
*> &Diags
,
266 const std::vector
<Record
*> &DiagGroups
,
267 std::map
<std::string
, GroupInfo
> &DiagsInGroup
)
268 : DiagGroupParents(DiagGroupParents
),
270 DiagGroups(DiagGroups
),
271 DiagsInGroup(DiagsInGroup
) {}
273 /// Compute the set of diagnostics and groups that are immediately
275 void compute(VecOrSet DiagsInPedantic
,
276 VecOrSet GroupsInPedantic
);
279 /// Determine whether a group is a subgroup of another group.
280 bool isSubGroupOfGroup(const Record
*Group
,
281 llvm::StringRef RootGroupName
);
283 /// Determine if the diagnostic is an extension.
284 bool isExtension(const Record
*Diag
);
286 /// Determine if the diagnostic is off by default.
287 bool isOffByDefault(const Record
*Diag
);
289 /// Increment the count for a group, and transitively marked
290 /// parent groups when appropriate.
291 void markGroup(const Record
*Group
);
293 /// Return true if the diagnostic is in a pedantic group.
294 bool groupInPedantic(const Record
*Group
, bool increment
= false);
296 } // end anonymous namespace
298 bool InferPedantic::isSubGroupOfGroup(const Record
*Group
,
299 llvm::StringRef GName
) {
300 const std::string
&GroupName
=
301 std::string(Group
->getValueAsString("GroupName"));
302 if (GName
== GroupName
)
305 const std::vector
<Record
*> &Parents
= DiagGroupParents
.getParents(Group
);
306 for (unsigned i
= 0, e
= Parents
.size(); i
!= e
; ++i
)
307 if (isSubGroupOfGroup(Parents
[i
], GName
))
313 /// Determine if the diagnostic is an extension.
314 bool InferPedantic::isExtension(const Record
*Diag
) {
315 const std::string
&ClsName
=
316 std::string(Diag
->getValueAsDef("Class")->getName());
317 return ClsName
== "CLASS_EXTENSION";
320 bool InferPedantic::isOffByDefault(const Record
*Diag
) {
321 const std::string
&DefSeverity
= std::string(
322 Diag
->getValueAsDef("DefaultSeverity")->getValueAsString("Name"));
323 return DefSeverity
== "Ignored";
326 bool InferPedantic::groupInPedantic(const Record
*Group
, bool increment
) {
327 GMap::mapped_type
&V
= GroupCount
[Group
];
328 // Lazily compute the threshold value for the group count.
330 const GroupInfo
&GI
=
331 DiagsInGroup
[std::string(Group
->getValueAsString("GroupName"))];
332 V
.second
= GI
.SubGroups
.size() + GI
.DiagsInGroup
.size();
338 // Consider a group in -Wpendatic IFF if has at least one diagnostic
339 // or subgroup AND all of those diagnostics and subgroups are covered
340 // by -Wpedantic via our computation.
341 return V
.first
!= 0 && V
.first
== *V
.second
;
344 void InferPedantic::markGroup(const Record
*Group
) {
345 // If all the diagnostics and subgroups have been marked as being
346 // covered by -Wpedantic, increment the count of parent groups. Once the
347 // group's count is equal to the number of subgroups and diagnostics in
348 // that group, we can safely add this group to -Wpedantic.
349 if (groupInPedantic(Group
, /* increment */ true)) {
350 const std::vector
<Record
*> &Parents
= DiagGroupParents
.getParents(Group
);
351 for (unsigned i
= 0, e
= Parents
.size(); i
!= e
; ++i
)
352 markGroup(Parents
[i
]);
356 void InferPedantic::compute(VecOrSet DiagsInPedantic
,
357 VecOrSet GroupsInPedantic
) {
358 // All extensions that are not on by default are implicitly in the
359 // "pedantic" group. For those that aren't explicitly included in -Wpedantic,
360 // mark them for consideration to be included in -Wpedantic directly.
361 for (unsigned i
= 0, e
= Diags
.size(); i
!= e
; ++i
) {
362 Record
*R
= Diags
[i
];
363 if (isExtension(R
) && isOffByDefault(R
)) {
365 if (DefInit
*Group
= dyn_cast
<DefInit
>(R
->getValueInit("Group"))) {
366 const Record
*GroupRec
= Group
->getDef();
367 if (!isSubGroupOfGroup(GroupRec
, "pedantic")) {
374 // Compute the set of diagnostics that are directly in -Wpedantic. We
375 // march through Diags a second time to ensure the results are emitted
376 // in deterministic order.
377 for (unsigned i
= 0, e
= Diags
.size(); i
!= e
; ++i
) {
378 Record
*R
= Diags
[i
];
379 if (!DiagsSet
.count(R
))
381 // Check if the group is implicitly in -Wpedantic. If so,
382 // the diagnostic should not be directly included in the -Wpedantic
384 if (DefInit
*Group
= dyn_cast
<DefInit
>(R
->getValueInit("Group")))
385 if (groupInPedantic(Group
->getDef()))
388 // The diagnostic is not included in a group that is (transitively) in
389 // -Wpedantic. Include it in -Wpedantic directly.
390 if (RecordVec
*V
= DiagsInPedantic
.dyn_cast
<RecordVec
*>())
393 DiagsInPedantic
.get
<RecordSet
*>()->insert(R
);
397 if (!GroupsInPedantic
)
400 // Compute the set of groups that are directly in -Wpedantic. We
401 // march through the groups to ensure the results are emitted
402 /// in a deterministc order.
403 for (unsigned i
= 0, ei
= DiagGroups
.size(); i
!= ei
; ++i
) {
404 Record
*Group
= DiagGroups
[i
];
405 if (!groupInPedantic(Group
))
408 const std::vector
<Record
*> &Parents
= DiagGroupParents
.getParents(Group
);
409 bool AllParentsInPedantic
=
410 llvm::all_of(Parents
, [&](Record
*R
) { return groupInPedantic(R
); });
411 // If all the parents are in -Wpedantic, this means that this diagnostic
412 // group will be indirectly included by -Wpedantic already. In that
413 // case, do not add it directly to -Wpedantic. If the group has no
414 // parents, obviously it should go into -Wpedantic.
415 if (Parents
.size() > 0 && AllParentsInPedantic
)
418 if (RecordVec
*V
= GroupsInPedantic
.dyn_cast
<RecordVec
*>())
421 GroupsInPedantic
.get
<RecordSet
*>()->insert(Group
);
430 PlaceholderPieceClass
,
434 SubstitutionPieceClass
,
451 static StringRef
getModifierName(ModifierType MT
) {
471 case MT_ObjCInstance
:
472 return "objcinstance";
474 llvm_unreachable("invalid modifier type");
477 llvm_unreachable("invalid modifier type");
481 // This type and its derived classes are move-only.
482 Piece(PieceKind Kind
) : ClassKind(Kind
) {}
483 Piece(Piece
const &O
) = delete;
484 Piece
&operator=(Piece
const &) = delete;
487 PieceKind
getPieceClass() const { return ClassKind
; }
488 static bool classof(const Piece
*) { return true; }
494 struct MultiPiece
: Piece
{
495 MultiPiece() : Piece(MultiPieceClass
) {}
496 MultiPiece(std::vector
<Piece
*> Pieces
)
497 : Piece(MultiPieceClass
), Pieces(std::move(Pieces
)) {}
499 std::vector
<Piece
*> Pieces
;
501 static bool classof(const Piece
*P
) {
502 return P
->getPieceClass() == MultiPieceClass
;
506 struct TextPiece
: Piece
{
509 TextPiece(StringRef Text
, StringRef Role
= "")
510 : Piece(TextPieceClass
), Role(Role
), Text(Text
.str()) {}
512 static bool classof(const Piece
*P
) {
513 return P
->getPieceClass() == TextPieceClass
;
517 struct PlaceholderPiece
: Piece
{
520 PlaceholderPiece(ModifierType Kind
, int Index
)
521 : Piece(PlaceholderPieceClass
), Kind(Kind
), Index(Index
) {}
523 static bool classof(const Piece
*P
) {
524 return P
->getPieceClass() == PlaceholderPieceClass
;
528 struct SelectPiece
: Piece
{
530 SelectPiece(PieceKind Kind
, ModifierType ModKind
)
531 : Piece(Kind
), ModKind(ModKind
) {}
534 SelectPiece(ModifierType ModKind
) : SelectPiece(SelectPieceClass
, ModKind
) {}
536 ModifierType ModKind
;
537 std::vector
<Piece
*> Options
;
540 static bool classof(const Piece
*P
) {
541 return P
->getPieceClass() == SelectPieceClass
||
542 P
->getPieceClass() == PluralPieceClass
;
546 struct PluralPiece
: SelectPiece
{
547 PluralPiece() : SelectPiece(PluralPieceClass
, MT_Plural
) {}
549 std::vector
<Piece
*> OptionPrefixes
;
552 static bool classof(const Piece
*P
) {
553 return P
->getPieceClass() == PluralPieceClass
;
557 struct DiffPiece
: Piece
{
558 DiffPiece() : Piece(DiffPieceClass
) {}
560 Piece
*Parts
[4] = {};
563 static bool classof(const Piece
*P
) {
564 return P
->getPieceClass() == DiffPieceClass
;
568 struct SubstitutionPiece
: Piece
{
569 SubstitutionPiece() : Piece(SubstitutionPieceClass
) {}
572 std::vector
<int> Modifiers
;
574 static bool classof(const Piece
*P
) {
575 return P
->getPieceClass() == SubstitutionPieceClass
;
579 /// Diagnostic text, parsed into pieces.
582 struct DiagnosticTextBuilder
{
583 DiagnosticTextBuilder(DiagnosticTextBuilder
const &) = delete;
584 DiagnosticTextBuilder
&operator=(DiagnosticTextBuilder
const &) = delete;
586 DiagnosticTextBuilder(RecordKeeper
&Records
) {
587 // Build up the list of substitution records.
588 for (auto *S
: Records
.getAllDerivedDefinitions("TextSubstitution")) {
589 EvaluatingRecordGuard
Guard(&EvaluatingRecord
, S
);
590 Substitutions
.try_emplace(
591 S
->getName(), DiagText(*this, S
->getValueAsString("Substitution")));
594 // Check that no diagnostic definitions have the same name as a
596 for (Record
*Diag
: Records
.getAllDerivedDefinitions("Diagnostic")) {
597 StringRef Name
= Diag
->getName();
598 if (Substitutions
.count(Name
))
599 llvm::PrintFatalError(
601 "Diagnostic '" + Name
+
602 "' has same name as TextSubstitution definition");
606 std::vector
<std::string
> buildForDocumentation(StringRef Role
,
608 std::string
buildForDefinition(const Record
*R
);
610 Piece
*getSubstitution(SubstitutionPiece
*S
) const {
611 auto It
= Substitutions
.find(S
->Name
);
612 if (It
== Substitutions
.end())
613 PrintFatalError("Failed to find substitution with name: " + S
->Name
);
614 return It
->second
.Root
;
617 [[noreturn
]] void PrintFatalError(llvm::Twine
const &Msg
) const {
618 assert(EvaluatingRecord
&& "not evaluating a record?");
619 llvm::PrintFatalError(EvaluatingRecord
->getLoc(), Msg
);
624 DiagnosticTextBuilder
&Builder
;
625 std::vector
<Piece
*> AllocatedPieces
;
626 Piece
*Root
= nullptr;
628 template <class T
, class... Args
> T
*New(Args
&&... args
) {
629 static_assert(std::is_base_of
<Piece
, T
>::value
, "must be piece");
630 T
*Mem
= new T(std::forward
<Args
>(args
)...);
631 AllocatedPieces
.push_back(Mem
);
635 DiagText(DiagnosticTextBuilder
&Builder
, StringRef Text
)
636 : Builder(Builder
), Root(parseDiagText(Text
, StopAt::End
)) {}
639 // Parse until the end of the string.
641 // Additionally stop if we hit a non-nested '|' or '}'.
643 // Additionally stop if we hit a non-nested '$'.
647 Piece
*parseDiagText(StringRef
&Text
, StopAt Stop
);
648 int parseModifier(StringRef
&) const;
651 DiagText(DiagText
&&O
) noexcept
652 : Builder(O
.Builder
), AllocatedPieces(std::move(O
.AllocatedPieces
)),
656 // The move assignment operator is defined as deleted pending further
658 DiagText
&operator=(DiagText
&&) = delete;
660 // The copy constrcutor and copy assignment operator is defined as deleted
661 // pending further motivation.
662 DiagText(const DiagText
&) = delete;
663 DiagText
&operator=(const DiagText
&) = delete;
666 for (Piece
*P
: AllocatedPieces
)
672 const Record
*EvaluatingRecord
= nullptr;
673 struct EvaluatingRecordGuard
{
674 EvaluatingRecordGuard(const Record
**Dest
, const Record
*New
)
675 : Dest(Dest
), Old(*Dest
) {
678 ~EvaluatingRecordGuard() { *Dest
= Old
; }
683 StringMap
<DiagText
> Substitutions
;
686 template <class Derived
> struct DiagTextVisitor
{
687 using ModifierMappingsType
= std::optional
<std::vector
<int>>;
690 Derived
&getDerived() { return static_cast<Derived
&>(*this); }
694 getSubstitutionMappings(SubstitutionPiece
*P
,
695 const ModifierMappingsType
&Mappings
) const {
696 std::vector
<int> NewMappings
;
697 for (int Idx
: P
->Modifiers
)
698 NewMappings
.push_back(mapIndex(Idx
, Mappings
));
702 struct SubstitutionContext
{
703 SubstitutionContext(DiagTextVisitor
&Visitor
, SubstitutionPiece
*P
)
705 Substitution
= Visitor
.Builder
.getSubstitution(P
);
706 OldMappings
= std::move(Visitor
.ModifierMappings
);
707 std::vector
<int> NewMappings
=
708 Visitor
.getSubstitutionMappings(P
, OldMappings
);
709 Visitor
.ModifierMappings
= std::move(NewMappings
);
712 ~SubstitutionContext() {
713 Visitor
.ModifierMappings
= std::move(OldMappings
);
717 DiagTextVisitor
&Visitor
;
718 std::optional
<std::vector
<int>> OldMappings
;
725 DiagTextVisitor(DiagnosticTextBuilder
&Builder
) : Builder(Builder
) {}
727 void Visit(Piece
*P
) {
728 switch (P
->getPieceClass()) {
730 case T##PieceClass: \
731 return getDerived().Visit##T(static_cast<T##Piece *>(P))
743 void VisitSubstitution(SubstitutionPiece
*P
) {
744 SubstitutionContext
Guard(*this, P
);
745 Visit(Guard
.Substitution
);
748 int mapIndex(int Idx
,
749 ModifierMappingsType
const &ModifierMappings
) const {
750 if (!ModifierMappings
)
752 if (ModifierMappings
->size() <= static_cast<unsigned>(Idx
))
753 Builder
.PrintFatalError("Modifier value '" + std::to_string(Idx
) +
754 "' is not valid for this mapping (has " +
755 std::to_string(ModifierMappings
->size()) +
757 return (*ModifierMappings
)[Idx
];
760 int mapIndex(int Idx
) const {
761 return mapIndex(Idx
, ModifierMappings
);
765 DiagnosticTextBuilder
&Builder
;
766 ModifierMappingsType ModifierMappings
;
769 void escapeRST(StringRef Str
, std::string
&Out
) {
771 if (StringRef("`*|_[]\\").count(K
))
777 template <typename It
> void padToSameLength(It Begin
, It End
) {
779 for (It I
= Begin
; I
!= End
; ++I
)
780 Width
= std::max(Width
, I
->size());
781 for (It I
= Begin
; I
!= End
; ++I
)
782 (*I
) += std::string(Width
- I
->size(), ' ');
785 template <typename It
> void makeTableRows(It Begin
, It End
) {
788 padToSameLength(Begin
, End
);
789 for (It I
= Begin
; I
!= End
; ++I
)
793 void makeRowSeparator(std::string
&Str
) {
795 K
= (K
== '|' ? '+' : '-');
798 struct DiagTextDocPrinter
: DiagTextVisitor
<DiagTextDocPrinter
> {
799 using BaseTy
= DiagTextVisitor
<DiagTextDocPrinter
>;
800 DiagTextDocPrinter(DiagnosticTextBuilder
&Builder
,
801 std::vector
<std::string
> &RST
)
802 : BaseTy(Builder
), RST(RST
) {}
805 Piece
*OrigP
, const ModifierMappingsType
&CurrentMappings
,
806 std::vector
<std::pair
<Piece
*, ModifierMappingsType
>> &Pieces
) const {
807 if (auto *Sub
= dyn_cast
<SubstitutionPiece
>(OrigP
)) {
808 ModifierMappingsType NewMappings
=
809 getSubstitutionMappings(Sub
, CurrentMappings
);
810 return gatherNodes(Builder
.getSubstitution(Sub
), NewMappings
, Pieces
);
812 if (auto *MD
= dyn_cast
<MultiPiece
>(OrigP
)) {
813 for (Piece
*Node
: MD
->Pieces
)
814 gatherNodes(Node
, CurrentMappings
, Pieces
);
817 Pieces
.push_back(std::make_pair(OrigP
, CurrentMappings
));
820 void VisitMulti(MultiPiece
*P
) {
821 if (P
->Pieces
.empty()) {
826 if (P
->Pieces
.size() == 1)
827 return Visit(P
->Pieces
[0]);
829 // Flatten the list of nodes, replacing any substitution pieces with the
830 // recursively flattened substituted node.
831 std::vector
<std::pair
<Piece
*, ModifierMappingsType
>> Pieces
;
832 gatherNodes(P
, ModifierMappings
, Pieces
);
834 std::string EmptyLinePrefix
;
835 size_t Start
= RST
.size();
836 bool HasMultipleLines
= true;
837 for (const std::pair
<Piece
*, ModifierMappingsType
> &NodePair
: Pieces
) {
838 std::vector
<std::string
> Lines
;
839 DiagTextDocPrinter Visitor
{Builder
, Lines
};
840 Visitor
.ModifierMappings
= NodePair
.second
;
841 Visitor
.Visit(NodePair
.first
);
846 // We need a vertical separator if either this or the previous piece is a
847 // multi-line piece, or this is the last piece.
848 const char *Separator
= (Lines
.size() > 1 || HasMultipleLines
) ? "|" : "";
849 HasMultipleLines
= Lines
.size() > 1;
851 if (Start
+ Lines
.size() > RST
.size())
852 RST
.resize(Start
+ Lines
.size(), EmptyLinePrefix
);
854 padToSameLength(Lines
.begin(), Lines
.end());
855 for (size_t I
= 0; I
!= Lines
.size(); ++I
)
856 RST
[Start
+ I
] += Separator
+ Lines
[I
];
857 std::string
Empty(Lines
[0].size(), ' ');
858 for (size_t I
= Start
+ Lines
.size(); I
!= RST
.size(); ++I
)
859 RST
[I
] += Separator
+ Empty
;
860 EmptyLinePrefix
+= Separator
+ Empty
;
862 for (size_t I
= Start
; I
!= RST
.size(); ++I
)
864 EmptyLinePrefix
+= "|";
866 makeRowSeparator(EmptyLinePrefix
);
867 RST
.insert(RST
.begin() + Start
, EmptyLinePrefix
);
868 RST
.insert(RST
.end(), EmptyLinePrefix
);
871 void VisitText(TextPiece
*P
) {
873 auto &S
= RST
.back();
875 StringRef T
= P
->Text
;
876 while (!T
.empty() && T
.front() == ' ') {
877 RST
.back() += " |nbsp| ";
882 while (!T
.empty() && T
.back() == ' ') {
883 Suffix
+= " |nbsp| ";
898 void VisitPlaceholder(PlaceholderPiece
*P
) {
899 RST
.push_back(std::string(":placeholder:`") +
900 char('A' + mapIndex(P
->Index
)) + "`");
903 void VisitSelect(SelectPiece
*P
) {
904 std::vector
<size_t> SeparatorIndexes
;
905 SeparatorIndexes
.push_back(RST
.size());
907 for (auto *O
: P
->Options
) {
909 SeparatorIndexes
.push_back(RST
.size());
913 makeTableRows(RST
.begin() + SeparatorIndexes
.front(),
914 RST
.begin() + SeparatorIndexes
.back() + 1);
915 for (size_t I
: SeparatorIndexes
)
916 makeRowSeparator(RST
[I
]);
919 void VisitPlural(PluralPiece
*P
) { VisitSelect(P
); }
921 void VisitDiff(DiffPiece
*P
) {
922 // Render %diff{a $ b $ c|d}e,f as %select{a %e b %f c|d}.
923 PlaceholderPiece
E(MT_Placeholder
, P
->Indexes
[0]);
924 PlaceholderPiece
F(MT_Placeholder
, P
->Indexes
[1]);
926 MultiPiece FirstOption
;
927 FirstOption
.Pieces
.push_back(P
->Parts
[0]);
928 FirstOption
.Pieces
.push_back(&E
);
929 FirstOption
.Pieces
.push_back(P
->Parts
[1]);
930 FirstOption
.Pieces
.push_back(&F
);
931 FirstOption
.Pieces
.push_back(P
->Parts
[2]);
933 SelectPiece
Select(MT_Diff
);
934 Select
.Options
.push_back(&FirstOption
);
935 Select
.Options
.push_back(P
->Parts
[3]);
937 VisitSelect(&Select
);
940 std::vector
<std::string
> &RST
;
943 struct DiagTextPrinter
: DiagTextVisitor
<DiagTextPrinter
> {
945 using BaseTy
= DiagTextVisitor
<DiagTextPrinter
>;
946 DiagTextPrinter(DiagnosticTextBuilder
&Builder
, std::string
&Result
)
947 : BaseTy(Builder
), Result(Result
) {}
949 void VisitMulti(MultiPiece
*P
) {
950 for (auto *Child
: P
->Pieces
)
953 void VisitText(TextPiece
*P
) { Result
+= P
->Text
; }
954 void VisitPlaceholder(PlaceholderPiece
*P
) {
956 Result
+= getModifierName(P
->Kind
);
957 addInt(mapIndex(P
->Index
));
959 void VisitSelect(SelectPiece
*P
) {
961 Result
+= getModifierName(P
->ModKind
);
962 if (P
->ModKind
== MT_Select
) {
964 for (auto *D
: P
->Options
) {
968 if (!P
->Options
.empty())
969 Result
.erase(--Result
.end());
972 addInt(mapIndex(P
->Index
));
975 void VisitPlural(PluralPiece
*P
) {
976 Result
+= "%plural{";
977 assert(P
->Options
.size() == P
->OptionPrefixes
.size());
978 for (unsigned I
= 0, End
= P
->Options
.size(); I
< End
; ++I
) {
979 if (P
->OptionPrefixes
[I
])
980 Visit(P
->OptionPrefixes
[I
]);
981 Visit(P
->Options
[I
]);
984 if (!P
->Options
.empty())
985 Result
.erase(--Result
.end());
987 addInt(mapIndex(P
->Index
));
990 void VisitDiff(DiffPiece
*P
) {
1000 addInt(mapIndex(P
->Indexes
[0]));
1002 addInt(mapIndex(P
->Indexes
[1]));
1005 void addInt(int Val
) { Result
+= std::to_string(Val
); }
1007 std::string
&Result
;
1010 int DiagnosticTextBuilder::DiagText::parseModifier(StringRef
&Text
) const {
1011 if (Text
.empty() || !isdigit(Text
[0]))
1012 Builder
.PrintFatalError("expected modifier in diagnostic");
1016 Val
+= Text
[0] - '0';
1017 Text
= Text
.drop_front();
1018 } while (!Text
.empty() && isdigit(Text
[0]));
1022 Piece
*DiagnosticTextBuilder::DiagText::parseDiagText(StringRef
&Text
,
1024 std::vector
<Piece
*> Parsed
;
1026 constexpr llvm::StringLiteral StopSets
[] = {"%", "%|}", "%|}$"};
1027 llvm::StringRef StopSet
= StopSets
[static_cast<int>(Stop
)];
1029 while (!Text
.empty()) {
1030 size_t End
= (size_t)-2;
1032 End
= Text
.find_first_of(StopSet
, End
+ 2);
1034 End
< Text
.size() - 1 && Text
[End
] == '%' &&
1035 (Text
[End
+ 1] == '%' || Text
[End
+ 1] == '|' || Text
[End
+ 1] == '$'));
1038 Parsed
.push_back(New
<TextPiece
>(Text
.slice(0, End
), "diagtext"));
1039 Text
= Text
.slice(End
, StringRef::npos
);
1044 if (Text
[0] == '|' || Text
[0] == '}' || Text
[0] == '$')
1048 Text
= Text
.drop_front();
1050 // Extract the (optional) modifier.
1051 size_t ModLength
= Text
.find_first_of("0123456789{");
1052 StringRef Modifier
= Text
.slice(0, ModLength
);
1053 Text
= Text
.slice(ModLength
, StringRef::npos
);
1054 ModifierType ModType
= llvm::StringSwitch
<ModifierType
>{Modifier
}
1055 .Case("select", MT_Select
)
1056 .Case("sub", MT_Sub
)
1057 .Case("diff", MT_Diff
)
1058 .Case("plural", MT_Plural
)
1060 .Case("ordinal", MT_Ordinal
)
1062 .Case("objcclass", MT_ObjCClass
)
1063 .Case("objcinstance", MT_ObjCInstance
)
1064 .Case("", MT_Placeholder
)
1065 .Default(MT_Unknown
);
1067 auto ExpectAndConsume
= [&](StringRef Prefix
) {
1068 if (!Text
.consume_front(Prefix
))
1069 Builder
.PrintFatalError("expected '" + Prefix
+ "' while parsing %" +
1075 Builder
.PrintFatalError("Unknown modifier type: " + Modifier
);
1077 SelectPiece
*Select
= New
<SelectPiece
>(MT_Select
);
1079 Text
= Text
.drop_front(); // '{' or '|'
1080 Select
->Options
.push_back(
1081 parseDiagText(Text
, StopAt::PipeOrCloseBrace
));
1082 assert(!Text
.empty() && "malformed %select");
1083 } while (Text
.front() == '|');
1084 ExpectAndConsume("}");
1085 Select
->Index
= parseModifier(Text
);
1086 Parsed
.push_back(Select
);
1090 PluralPiece
*Plural
= New
<PluralPiece
>();
1092 Text
= Text
.drop_front(); // '{' or '|'
1093 size_t End
= Text
.find_first_of(":");
1094 if (End
== StringRef::npos
)
1095 Builder
.PrintFatalError("expected ':' while parsing %plural");
1097 assert(!Text
.empty());
1098 Plural
->OptionPrefixes
.push_back(
1099 New
<TextPiece
>(Text
.slice(0, End
), "diagtext"));
1100 Text
= Text
.slice(End
, StringRef::npos
);
1101 Plural
->Options
.push_back(
1102 parseDiagText(Text
, StopAt::PipeOrCloseBrace
));
1103 assert(!Text
.empty() && "malformed %plural");
1104 } while (Text
.front() == '|');
1105 ExpectAndConsume("}");
1106 Plural
->Index
= parseModifier(Text
);
1107 Parsed
.push_back(Plural
);
1111 SubstitutionPiece
*Sub
= New
<SubstitutionPiece
>();
1112 ExpectAndConsume("{");
1113 size_t NameSize
= Text
.find_first_of('}');
1114 assert(NameSize
!= size_t(-1) && "failed to find the end of the name");
1115 assert(NameSize
!= 0 && "empty name?");
1116 Sub
->Name
= Text
.substr(0, NameSize
).str();
1117 Text
= Text
.drop_front(NameSize
);
1118 ExpectAndConsume("}");
1119 if (!Text
.empty()) {
1121 if (!isdigit(Text
[0]))
1123 Sub
->Modifiers
.push_back(parseModifier(Text
));
1124 if (Text
.empty() || Text
[0] != ',')
1126 Text
= Text
.drop_front(); // ','
1127 assert(!Text
.empty() && isdigit(Text
[0]) &&
1128 "expected another modifier");
1131 Parsed
.push_back(Sub
);
1135 DiffPiece
*Diff
= New
<DiffPiece
>();
1136 ExpectAndConsume("{");
1137 Diff
->Parts
[0] = parseDiagText(Text
, StopAt::Dollar
);
1138 ExpectAndConsume("$");
1139 Diff
->Parts
[1] = parseDiagText(Text
, StopAt::Dollar
);
1140 ExpectAndConsume("$");
1141 Diff
->Parts
[2] = parseDiagText(Text
, StopAt::PipeOrCloseBrace
);
1142 ExpectAndConsume("|");
1143 Diff
->Parts
[3] = parseDiagText(Text
, StopAt::PipeOrCloseBrace
);
1144 ExpectAndConsume("}");
1145 Diff
->Indexes
[0] = parseModifier(Text
);
1146 ExpectAndConsume(",");
1147 Diff
->Indexes
[1] = parseModifier(Text
);
1148 Parsed
.push_back(Diff
);
1152 SelectPiece
*Select
= New
<SelectPiece
>(ModType
);
1153 Select
->Options
.push_back(New
<TextPiece
>(""));
1154 Select
->Options
.push_back(New
<TextPiece
>("s", "diagtext"));
1155 Select
->Index
= parseModifier(Text
);
1156 Parsed
.push_back(Select
);
1160 case MT_Placeholder
:
1162 case MT_ObjCInstance
:
1164 Parsed
.push_back(New
<PlaceholderPiece
>(ModType
, parseModifier(Text
)));
1170 return New
<MultiPiece
>(Parsed
);
1173 std::vector
<std::string
>
1174 DiagnosticTextBuilder::buildForDocumentation(StringRef Severity
,
1176 EvaluatingRecordGuard
Guard(&EvaluatingRecord
, R
);
1177 StringRef Text
= R
->getValueAsString("Summary");
1179 DiagText
D(*this, Text
);
1180 TextPiece
*Prefix
= D
.New
<TextPiece
>(Severity
, Severity
);
1181 Prefix
->Text
+= ": ";
1182 auto *MP
= dyn_cast
<MultiPiece
>(D
.Root
);
1184 MP
= D
.New
<MultiPiece
>();
1185 MP
->Pieces
.push_back(D
.Root
);
1188 MP
->Pieces
.insert(MP
->Pieces
.begin(), Prefix
);
1189 std::vector
<std::string
> Result
;
1190 DiagTextDocPrinter
{*this, Result
}.Visit(D
.Root
);
1194 std::string
DiagnosticTextBuilder::buildForDefinition(const Record
*R
) {
1195 EvaluatingRecordGuard
Guard(&EvaluatingRecord
, R
);
1196 StringRef Text
= R
->getValueAsString("Summary");
1197 DiagText
D(*this, Text
);
1199 DiagTextPrinter
{*this, Result
}.Visit(D
.Root
);
1205 //===----------------------------------------------------------------------===//
1206 // Warning Tables (.inc file) generation.
1207 //===----------------------------------------------------------------------===//
1209 static bool isError(const Record
&Diag
) {
1210 const std::string
&ClsName
=
1211 std::string(Diag
.getValueAsDef("Class")->getName());
1212 return ClsName
== "CLASS_ERROR";
1215 static bool isRemark(const Record
&Diag
) {
1216 const std::string
&ClsName
=
1217 std::string(Diag
.getValueAsDef("Class")->getName());
1218 return ClsName
== "CLASS_REMARK";
1222 /// ClangDiagsDefsEmitter - The top-level class emits .def files containing
1223 /// declarations of Clang diagnostics.
1224 void clang::EmitClangDiagsDefs(RecordKeeper
&Records
, raw_ostream
&OS
,
1225 const std::string
&Component
) {
1226 // Write the #if guard
1227 if (!Component
.empty()) {
1228 std::string ComponentName
= StringRef(Component
).upper();
1229 OS
<< "#ifdef " << ComponentName
<< "START\n";
1230 OS
<< "__" << ComponentName
<< "START = DIAG_START_" << ComponentName
1232 OS
<< "#undef " << ComponentName
<< "START\n";
1236 DiagnosticTextBuilder
DiagTextBuilder(Records
);
1238 std::vector
<Record
*> Diags
= Records
.getAllDerivedDefinitions("Diagnostic");
1240 std::vector
<Record
*> DiagGroups
1241 = Records
.getAllDerivedDefinitions("DiagGroup");
1243 std::map
<std::string
, GroupInfo
> DiagsInGroup
;
1244 groupDiagnostics(Diags
, DiagGroups
, DiagsInGroup
);
1246 DiagCategoryIDMap
CategoryIDs(Records
);
1247 DiagGroupParentMap
DGParentMap(Records
);
1249 // Compute the set of diagnostics that are in -Wpedantic.
1250 RecordSet DiagsInPedantic
;
1251 InferPedantic
inferPedantic(DGParentMap
, Diags
, DiagGroups
, DiagsInGroup
);
1252 inferPedantic
.compute(&DiagsInPedantic
, (RecordVec
*)nullptr);
1254 for (unsigned i
= 0, e
= Diags
.size(); i
!= e
; ++i
) {
1255 const Record
&R
= *Diags
[i
];
1257 // Check if this is an error that is accidentally in a warning
1260 if (DefInit
*Group
= dyn_cast
<DefInit
>(R
.getValueInit("Group"))) {
1261 const Record
*GroupRec
= Group
->getDef();
1262 const std::string
&GroupName
=
1263 std::string(GroupRec
->getValueAsString("GroupName"));
1264 PrintFatalError(R
.getLoc(), "Error " + R
.getName() +
1265 " cannot be in a warning group [" + GroupName
+ "]");
1269 // Check that all remarks have an associated diagnostic group.
1271 if (!isa
<DefInit
>(R
.getValueInit("Group"))) {
1272 PrintFatalError(R
.getLoc(), "Error " + R
.getName() +
1273 " not in any diagnostic group");
1277 // Filter by component.
1278 if (!Component
.empty() && Component
!= R
.getValueAsString("Component"))
1281 OS
<< "DIAG(" << R
.getName() << ", ";
1282 OS
<< R
.getValueAsDef("Class")->getName();
1283 OS
<< ", (unsigned)diag::Severity::"
1284 << R
.getValueAsDef("DefaultSeverity")->getValueAsString("Name");
1286 // Description string.
1288 OS
.write_escaped(DiagTextBuilder
.buildForDefinition(&R
)) << '"';
1290 // Warning group associated with the diagnostic. This is stored as an index
1291 // into the alphabetically sorted warning group table.
1292 if (DefInit
*DI
= dyn_cast
<DefInit
>(R
.getValueInit("Group"))) {
1293 std::map
<std::string
, GroupInfo
>::iterator I
= DiagsInGroup
.find(
1294 std::string(DI
->getDef()->getValueAsString("GroupName")));
1295 assert(I
!= DiagsInGroup
.end());
1296 OS
<< ", " << I
->second
.IDNo
;
1297 } else if (DiagsInPedantic
.count(&R
)) {
1298 std::map
<std::string
, GroupInfo
>::iterator I
=
1299 DiagsInGroup
.find("pedantic");
1300 assert(I
!= DiagsInGroup
.end() && "pedantic group not defined");
1301 OS
<< ", " << I
->second
.IDNo
;
1307 OS
<< ", " << R
.getValueAsDef("SFINAE")->getName();
1309 // Default warning has no Werror bit.
1310 if (R
.getValueAsBit("WarningNoWerror"))
1315 if (R
.getValueAsBit("ShowInSystemHeader"))
1320 if (R
.getValueAsBit("ShowInSystemMacro"))
1325 if (R
.getValueAsBit("Deferrable"))
1331 OS
<< ", " << CategoryIDs
.getID(getDiagnosticCategory(&R
, DGParentMap
));
1336 //===----------------------------------------------------------------------===//
1337 // Warning Group Tables generation
1338 //===----------------------------------------------------------------------===//
1340 static std::string
getDiagCategoryEnum(llvm::StringRef name
) {
1342 return "DiagCat_None";
1343 SmallString
<256> enumName
= llvm::StringRef("DiagCat_");
1344 for (llvm::StringRef::iterator I
= name
.begin(), E
= name
.end(); I
!= E
; ++I
)
1345 enumName
+= isalnum(*I
) ? *I
: '_';
1346 return std::string(enumName
.str());
1349 /// Emit the array of diagnostic subgroups.
1351 /// The array of diagnostic subgroups contains for each group a list of its
1352 /// subgroups. The individual lists are separated by '-1'. Groups with no
1353 /// subgroups are skipped.
1356 /// static const int16_t DiagSubGroups[] = {
1358 /// /* DiagSubGroup0 */ 142, -1,
1359 /// /* DiagSubGroup13 */ 265, 322, 399, -1
1363 static void emitDiagSubGroups(std::map
<std::string
, GroupInfo
> &DiagsInGroup
,
1364 RecordVec
&GroupsInPedantic
, raw_ostream
&OS
) {
1365 OS
<< "static const int16_t DiagSubGroups[] = {\n"
1366 << " /* Empty */ -1,\n";
1367 for (auto const &I
: DiagsInGroup
) {
1368 const bool IsPedantic
= I
.first
== "pedantic";
1370 const std::vector
<std::string
> &SubGroups
= I
.second
.SubGroups
;
1371 if (!SubGroups
.empty() || (IsPedantic
&& !GroupsInPedantic
.empty())) {
1372 OS
<< " /* DiagSubGroup" << I
.second
.IDNo
<< " */ ";
1373 for (auto const &SubGroup
: SubGroups
) {
1374 std::map
<std::string
, GroupInfo
>::const_iterator RI
=
1375 DiagsInGroup
.find(SubGroup
);
1376 assert(RI
!= DiagsInGroup
.end() && "Referenced without existing?");
1377 OS
<< RI
->second
.IDNo
<< ", ";
1379 // Emit the groups implicitly in "pedantic".
1381 for (auto const &Group
: GroupsInPedantic
) {
1382 const std::string
&GroupName
=
1383 std::string(Group
->getValueAsString("GroupName"));
1384 std::map
<std::string
, GroupInfo
>::const_iterator RI
=
1385 DiagsInGroup
.find(GroupName
);
1386 assert(RI
!= DiagsInGroup
.end() && "Referenced without existing?");
1387 OS
<< RI
->second
.IDNo
<< ", ";
1397 /// Emit the list of diagnostic arrays.
1399 /// This data structure is a large array that contains itself arrays of varying
1400 /// size. Each array represents a list of diagnostics. The different arrays are
1401 /// separated by the value '-1'.
1404 /// static const int16_t DiagArrays[] = {
1406 /// /* DiagArray1 */ diag::warn_pragma_message,
1408 /// /* DiagArray2 */ diag::warn_abs_too_small,
1409 /// diag::warn_unsigned_abs,
1410 /// diag::warn_wrong_absolute_value_type,
1415 static void emitDiagArrays(std::map
<std::string
, GroupInfo
> &DiagsInGroup
,
1416 RecordVec
&DiagsInPedantic
, raw_ostream
&OS
) {
1417 OS
<< "static const int16_t DiagArrays[] = {\n"
1418 << " /* Empty */ -1,\n";
1419 for (auto const &I
: DiagsInGroup
) {
1420 const bool IsPedantic
= I
.first
== "pedantic";
1422 const std::vector
<const Record
*> &V
= I
.second
.DiagsInGroup
;
1423 if (!V
.empty() || (IsPedantic
&& !DiagsInPedantic
.empty())) {
1424 OS
<< " /* DiagArray" << I
.second
.IDNo
<< " */ ";
1425 for (auto *Record
: V
)
1426 OS
<< "diag::" << Record
->getName() << ", ";
1427 // Emit the diagnostics implicitly in "pedantic".
1429 for (auto const &Diag
: DiagsInPedantic
)
1430 OS
<< "diag::" << Diag
->getName() << ", ";
1438 /// Emit a list of group names.
1440 /// This creates a long string which by itself contains a list of pascal style
1441 /// strings, which consist of a length byte directly followed by the string.
1444 /// static const char DiagGroupNames[] = {
1445 /// \000\020#pragma-messages\t#warnings\020CFString-literal"
1448 static void emitDiagGroupNames(StringToOffsetTable
&GroupNames
,
1450 OS
<< "static const char DiagGroupNames[] = {\n";
1451 GroupNames
.EmitString(OS
);
1455 /// Emit diagnostic arrays and related data structures.
1457 /// This creates the actual diagnostic array, an array of diagnostic subgroups
1458 /// and an array of subgroup names.
1461 /// #ifdef GET_DIAG_ARRAYS
1462 /// static const int16_t DiagArrays[];
1463 /// static const int16_t DiagSubGroups[];
1464 /// static const char DiagGroupNames[];
1467 static void emitAllDiagArrays(std::map
<std::string
, GroupInfo
> &DiagsInGroup
,
1468 RecordVec
&DiagsInPedantic
,
1469 RecordVec
&GroupsInPedantic
,
1470 StringToOffsetTable
&GroupNames
,
1472 OS
<< "\n#ifdef GET_DIAG_ARRAYS\n";
1473 emitDiagArrays(DiagsInGroup
, DiagsInPedantic
, OS
);
1474 emitDiagSubGroups(DiagsInGroup
, GroupsInPedantic
, OS
);
1475 emitDiagGroupNames(GroupNames
, OS
);
1476 OS
<< "#endif // GET_DIAG_ARRAYS\n\n";
1479 /// Emit diagnostic table.
1481 /// The table is sorted by the name of the diagnostic group. Each element
1482 /// consists of the name of the diagnostic group (given as offset in the
1483 /// group name table), a reference to a list of diagnostics (optional) and a
1484 /// reference to a set of subgroups (optional).
1487 /// #ifdef GET_DIAG_TABLE
1488 /// {/* abi */ 159, /* DiagArray11 */ 19, /* Empty */ 0},
1489 /// {/* aggregate-return */ 180, /* Empty */ 0, /* Empty */ 0},
1490 /// {/* all */ 197, /* Empty */ 0, /* DiagSubGroup13 */ 3},
1491 /// {/* deprecated */ 1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */ 9},
1494 static void emitDiagTable(std::map
<std::string
, GroupInfo
> &DiagsInGroup
,
1495 RecordVec
&DiagsInPedantic
,
1496 RecordVec
&GroupsInPedantic
,
1497 StringToOffsetTable
&GroupNames
, raw_ostream
&OS
) {
1498 unsigned MaxLen
= 0;
1500 for (auto const &I
: DiagsInGroup
)
1501 MaxLen
= std::max(MaxLen
, (unsigned)I
.first
.size());
1503 OS
<< "\n#ifdef DIAG_ENTRY\n";
1504 unsigned SubGroupIndex
= 1, DiagArrayIndex
= 1;
1505 for (auto const &I
: DiagsInGroup
) {
1506 // Group option string.
1507 OS
<< "DIAG_ENTRY(";
1508 OS
<< I
.second
.GroupName
<< " /* ";
1510 if (I
.first
.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
1511 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1512 "0123456789!@#$%^*-+=:?") !=
1514 PrintFatalError("Invalid character in diagnostic group '" + I
.first
+
1516 OS
<< I
.first
<< " */, ";
1517 // Store a pascal-style length byte at the beginning of the string.
1518 std::string Name
= char(I
.first
.size()) + I
.first
;
1519 OS
<< GroupNames
.GetOrAddStringOffset(Name
, false) << ", ";
1521 // Special handling for 'pedantic'.
1522 const bool IsPedantic
= I
.first
== "pedantic";
1524 // Diagnostics in the group.
1525 const std::vector
<const Record
*> &V
= I
.second
.DiagsInGroup
;
1526 const bool hasDiags
=
1527 !V
.empty() || (IsPedantic
&& !DiagsInPedantic
.empty());
1529 OS
<< "/* DiagArray" << I
.second
.IDNo
<< " */ " << DiagArrayIndex
1532 DiagArrayIndex
+= DiagsInPedantic
.size();
1533 DiagArrayIndex
+= V
.size() + 1;
1539 const std::vector
<std::string
> &SubGroups
= I
.second
.SubGroups
;
1540 const bool hasSubGroups
=
1541 !SubGroups
.empty() || (IsPedantic
&& !GroupsInPedantic
.empty());
1543 OS
<< "/* DiagSubGroup" << I
.second
.IDNo
<< " */ " << SubGroupIndex
1546 SubGroupIndex
+= GroupsInPedantic
.size();
1547 SubGroupIndex
+= SubGroups
.size() + 1;
1552 std::string Documentation
= I
.second
.Defs
.back()
1553 ->getValue("Documentation")
1555 ->getAsUnquotedString();
1557 OS
<< "R\"(" << StringRef(Documentation
).trim() << ")\"";
1561 OS
<< "#endif // DIAG_ENTRY\n\n";
1564 /// Emit the table of diagnostic categories.
1566 /// The table has the form of macro calls that have two parameters. The
1567 /// category's name as well as an enum that represents the category. The
1568 /// table can be used by defining the macro 'CATEGORY' and including this
1569 /// table right after.
1572 /// #ifdef GET_CATEGORY_TABLE
1573 /// CATEGORY("Semantic Issue", DiagCat_Semantic_Issue)
1574 /// CATEGORY("Lambda Issue", DiagCat_Lambda_Issue)
1577 static void emitCategoryTable(RecordKeeper
&Records
, raw_ostream
&OS
) {
1578 DiagCategoryIDMap
CategoriesByID(Records
);
1579 OS
<< "\n#ifdef GET_CATEGORY_TABLE\n";
1580 for (auto const &C
: CategoriesByID
)
1581 OS
<< "CATEGORY(\"" << C
<< "\", " << getDiagCategoryEnum(C
) << ")\n";
1582 OS
<< "#endif // GET_CATEGORY_TABLE\n\n";
1585 void clang::EmitClangDiagGroups(RecordKeeper
&Records
, raw_ostream
&OS
) {
1586 // Compute a mapping from a DiagGroup to all of its parents.
1587 DiagGroupParentMap
DGParentMap(Records
);
1589 std::vector
<Record
*> Diags
= Records
.getAllDerivedDefinitions("Diagnostic");
1591 std::vector
<Record
*> DiagGroups
=
1592 Records
.getAllDerivedDefinitions("DiagGroup");
1594 std::map
<std::string
, GroupInfo
> DiagsInGroup
;
1595 groupDiagnostics(Diags
, DiagGroups
, DiagsInGroup
);
1597 // All extensions are implicitly in the "pedantic" group. Record the
1598 // implicit set of groups in the "pedantic" group, and use this information
1599 // later when emitting the group information for Pedantic.
1600 RecordVec DiagsInPedantic
;
1601 RecordVec GroupsInPedantic
;
1602 InferPedantic
inferPedantic(DGParentMap
, Diags
, DiagGroups
, DiagsInGroup
);
1603 inferPedantic
.compute(&DiagsInPedantic
, &GroupsInPedantic
);
1605 StringToOffsetTable GroupNames
;
1606 for (std::map
<std::string
, GroupInfo
>::const_iterator
1607 I
= DiagsInGroup
.begin(),
1608 E
= DiagsInGroup
.end();
1610 // Store a pascal-style length byte at the beginning of the string.
1611 std::string Name
= char(I
->first
.size()) + I
->first
;
1612 GroupNames
.GetOrAddStringOffset(Name
, false);
1615 emitAllDiagArrays(DiagsInGroup
, DiagsInPedantic
, GroupsInPedantic
, GroupNames
,
1617 emitDiagTable(DiagsInGroup
, DiagsInPedantic
, GroupsInPedantic
, GroupNames
,
1619 emitCategoryTable(Records
, OS
);
1622 //===----------------------------------------------------------------------===//
1623 // Diagnostic name index generation
1624 //===----------------------------------------------------------------------===//
1627 struct RecordIndexElement
1629 RecordIndexElement() {}
1630 explicit RecordIndexElement(Record
const &R
)
1631 : Name(std::string(R
.getName())) {}
1635 } // end anonymous namespace.
1637 void clang::EmitClangDiagsIndexName(RecordKeeper
&Records
, raw_ostream
&OS
) {
1638 const std::vector
<Record
*> &Diags
=
1639 Records
.getAllDerivedDefinitions("Diagnostic");
1641 std::vector
<RecordIndexElement
> Index
;
1642 Index
.reserve(Diags
.size());
1643 for (unsigned i
= 0, e
= Diags
.size(); i
!= e
; ++i
) {
1644 const Record
&R
= *(Diags
[i
]);
1645 Index
.push_back(RecordIndexElement(R
));
1649 [](const RecordIndexElement
&Lhs
, const RecordIndexElement
&Rhs
) {
1650 return Lhs
.Name
< Rhs
.Name
;
1653 for (unsigned i
= 0, e
= Index
.size(); i
!= e
; ++i
) {
1654 const RecordIndexElement
&R
= Index
[i
];
1656 OS
<< "DIAG_NAME_INDEX(" << R
.Name
<< ")\n";
1660 //===----------------------------------------------------------------------===//
1661 // Diagnostic documentation generation
1662 //===----------------------------------------------------------------------===//
1667 bool isRemarkGroup(const Record
*DiagGroup
,
1668 const std::map
<std::string
, GroupInfo
> &DiagsInGroup
) {
1669 bool AnyRemarks
= false, AnyNonRemarks
= false;
1671 std::function
<void(StringRef
)> Visit
= [&](StringRef GroupName
) {
1672 auto &GroupInfo
= DiagsInGroup
.find(std::string(GroupName
))->second
;
1673 for (const Record
*Diag
: GroupInfo
.DiagsInGroup
)
1674 (isRemark(*Diag
) ? AnyRemarks
: AnyNonRemarks
) = true;
1675 for (const auto &Name
: GroupInfo
.SubGroups
)
1678 Visit(DiagGroup
->getValueAsString("GroupName"));
1680 if (AnyRemarks
&& AnyNonRemarks
)
1682 DiagGroup
->getLoc(),
1683 "Diagnostic group contains both remark and non-remark diagnostics");
1687 std::string
getDefaultSeverity(const Record
*Diag
) {
1689 Diag
->getValueAsDef("DefaultSeverity")->getValueAsString("Name"));
1692 std::set
<std::string
>
1693 getDefaultSeverities(const Record
*DiagGroup
,
1694 const std::map
<std::string
, GroupInfo
> &DiagsInGroup
) {
1695 std::set
<std::string
> States
;
1697 std::function
<void(StringRef
)> Visit
= [&](StringRef GroupName
) {
1698 auto &GroupInfo
= DiagsInGroup
.find(std::string(GroupName
))->second
;
1699 for (const Record
*Diag
: GroupInfo
.DiagsInGroup
)
1700 States
.insert(getDefaultSeverity(Diag
));
1701 for (const auto &Name
: GroupInfo
.SubGroups
)
1704 Visit(DiagGroup
->getValueAsString("GroupName"));
1708 void writeHeader(StringRef Str
, raw_ostream
&OS
, char Kind
= '-') {
1709 OS
<< Str
<< "\n" << std::string(Str
.size(), Kind
) << "\n";
1712 void writeDiagnosticText(DiagnosticTextBuilder
&Builder
, const Record
*R
,
1713 StringRef Role
, raw_ostream
&OS
) {
1714 StringRef Text
= R
->getValueAsString("Summary");
1716 OS
<< "The text of this diagnostic is not controlled by Clang.\n\n";
1718 std::vector
<std::string
> Out
= Builder
.buildForDocumentation(Role
, R
);
1719 for (auto &Line
: Out
)
1728 void clang::EmitClangDiagDocs(RecordKeeper
&Records
, raw_ostream
&OS
) {
1729 using namespace docs
;
1731 // Get the documentation introduction paragraph.
1732 const Record
*Documentation
= Records
.getDef("GlobalDocumentation");
1733 if (!Documentation
) {
1734 PrintFatalError("The Documentation top-level definition is missing, "
1735 "no documentation will be generated.");
1739 OS
<< Documentation
->getValueAsString("Intro") << "\n";
1741 DiagnosticTextBuilder
Builder(Records
);
1743 std::vector
<Record
*> Diags
=
1744 Records
.getAllDerivedDefinitions("Diagnostic");
1746 std::vector
<Record
*> DiagGroups
=
1747 Records
.getAllDerivedDefinitions("DiagGroup");
1748 llvm::sort(DiagGroups
, diagGroupBeforeByName
);
1750 DiagGroupParentMap
DGParentMap(Records
);
1752 std::map
<std::string
, GroupInfo
> DiagsInGroup
;
1753 groupDiagnostics(Diags
, DiagGroups
, DiagsInGroup
);
1755 // Compute the set of diagnostics that are in -Wpedantic.
1757 RecordSet DiagsInPedanticSet
;
1758 RecordSet GroupsInPedanticSet
;
1759 InferPedantic
inferPedantic(DGParentMap
, Diags
, DiagGroups
, DiagsInGroup
);
1760 inferPedantic
.compute(&DiagsInPedanticSet
, &GroupsInPedanticSet
);
1761 auto &PedDiags
= DiagsInGroup
["pedantic"];
1762 // Put the diagnostics into a deterministic order.
1763 RecordVec
DiagsInPedantic(DiagsInPedanticSet
.begin(),
1764 DiagsInPedanticSet
.end());
1765 RecordVec
GroupsInPedantic(GroupsInPedanticSet
.begin(),
1766 GroupsInPedanticSet
.end());
1767 llvm::sort(DiagsInPedantic
, beforeThanCompare
);
1768 llvm::sort(GroupsInPedantic
, beforeThanCompare
);
1769 PedDiags
.DiagsInGroup
.insert(PedDiags
.DiagsInGroup
.end(),
1770 DiagsInPedantic
.begin(),
1771 DiagsInPedantic
.end());
1772 for (auto *Group
: GroupsInPedantic
)
1773 PedDiags
.SubGroups
.push_back(
1774 std::string(Group
->getValueAsString("GroupName")));
1777 // FIXME: Write diagnostic categories and link to diagnostic groups in each.
1779 // Write out the diagnostic groups.
1780 for (const Record
*G
: DiagGroups
) {
1781 bool IsRemarkGroup
= isRemarkGroup(G
, DiagsInGroup
);
1783 DiagsInGroup
[std::string(G
->getValueAsString("GroupName"))];
1784 bool IsSynonym
= GroupInfo
.DiagsInGroup
.empty() &&
1785 GroupInfo
.SubGroups
.size() == 1;
1787 writeHeader(((IsRemarkGroup
? "-R" : "-W") +
1788 G
->getValueAsString("GroupName")).str(),
1792 // FIXME: Ideally, all the diagnostics in a group should have the same
1793 // default state, but that is not currently the case.
1794 auto DefaultSeverities
= getDefaultSeverities(G
, DiagsInGroup
);
1795 if (!DefaultSeverities
.empty() && !DefaultSeverities
.count("Ignored")) {
1796 bool AnyNonErrors
= DefaultSeverities
.count("Warning") ||
1797 DefaultSeverities
.count("Remark");
1799 OS
<< "This diagnostic is an error by default, but the flag ``-Wno-"
1800 << G
->getValueAsString("GroupName") << "`` can be used to disable "
1801 << "the error.\n\n";
1803 OS
<< "This diagnostic is enabled by default.\n\n";
1804 } else if (DefaultSeverities
.size() > 1) {
1805 OS
<< "Some of the diagnostics controlled by this flag are enabled "
1806 << "by default.\n\n";
1810 if (!GroupInfo
.SubGroups
.empty()) {
1812 OS
<< "Synonym for ";
1813 else if (GroupInfo
.DiagsInGroup
.empty())
1816 OS
<< "Also controls ";
1819 llvm::sort(GroupInfo
.SubGroups
);
1820 for (const auto &Name
: GroupInfo
.SubGroups
) {
1821 if (!First
) OS
<< ", ";
1822 OS
<< "`" << (IsRemarkGroup
? "-R" : "-W") << Name
<< "`_";
1828 if (!GroupInfo
.DiagsInGroup
.empty()) {
1829 OS
<< "**Diagnostic text:**\n\n";
1830 for (const Record
*D
: GroupInfo
.DiagsInGroup
) {
1831 auto Severity
= getDefaultSeverity(D
);
1832 Severity
[0] = tolower(Severity
[0]);
1833 if (Severity
== "ignored")
1834 Severity
= IsRemarkGroup
? "remark" : "warning";
1836 writeDiagnosticText(Builder
, D
, Severity
, OS
);
1840 auto Doc
= G
->getValueAsString("Documentation");
1843 else if (GroupInfo
.SubGroups
.empty() && GroupInfo
.DiagsInGroup
.empty())
1844 OS
<< "This diagnostic flag exists for GCC compatibility, and has no "
1845 "effect in Clang.\n";