1 //=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // These tablegen backends emit Clang diagnostics tables.
12 //===----------------------------------------------------------------------===//
14 #include "ClangDiagnosticsEmitter.h"
16 #include "llvm/Support/Debug.h"
17 #include "llvm/Support/Compiler.h"
18 #include "llvm/ADT/DenseSet.h"
19 #include "llvm/ADT/StringExtras.h"
20 #include "llvm/ADT/VectorExtras.h"
25 //===----------------------------------------------------------------------===//
26 // Warning Tables (.inc file) generation.
27 //===----------------------------------------------------------------------===//
29 void ClangDiagsDefsEmitter::run(raw_ostream
&OS
) {
30 // Write the #if guard
31 if (!Component
.empty()) {
32 std::string ComponentName
= UppercaseString(Component
);
33 OS
<< "#ifdef " << ComponentName
<< "START\n";
34 OS
<< "__" << ComponentName
<< "START = DIAG_START_" << ComponentName
36 OS
<< "#undef " << ComponentName
<< "START\n";
40 const std::vector
<Record
*> &Diags
=
41 Records
.getAllDerivedDefinitions("Diagnostic");
43 for (unsigned i
= 0, e
= Diags
.size(); i
!= e
; ++i
) {
44 const Record
&R
= *Diags
[i
];
45 // Filter by component.
46 if (!Component
.empty() && Component
!= R
.getValueAsString("Component"))
49 OS
<< "DIAG(" << R
.getName() << ", ";
50 OS
<< R
.getValueAsDef("Class")->getName();
51 OS
<< ", diag::" << R
.getValueAsDef("DefaultMapping")->getName();
53 // Description string.
55 std::string S
= R
.getValueAsString("Text");
59 // Warning associated with the diagnostic.
60 if (DefInit
*DI
= dynamic_cast<DefInit
*>(R
.getValueInit("Group"))) {
61 S
= DI
->getDef()->getValueAsString("GroupName");
63 OS
<< ", \"" << S
<< "\"";
69 if (R
.getValueAsBit("SFINAE"))
77 //===----------------------------------------------------------------------===//
78 // Warning Group Tables generation
79 //===----------------------------------------------------------------------===//
82 std::vector
<const Record
*> DiagsInGroup
;
83 std::vector
<std::string
> SubGroups
;
87 void ClangDiagGroupsEmitter::run(raw_ostream
&OS
) {
88 // Invert the 1-[0/1] mapping of diags to group into a one to many mapping of
89 // groups to diags in the group.
90 std::map
<std::string
, GroupInfo
> DiagsInGroup
;
92 std::vector
<Record
*> Diags
=
93 Records
.getAllDerivedDefinitions("Diagnostic");
94 for (unsigned i
= 0, e
= Diags
.size(); i
!= e
; ++i
) {
95 const Record
*R
= Diags
[i
];
96 DefInit
*DI
= dynamic_cast<DefInit
*>(R
->getValueInit("Group"));
97 if (DI
== 0) continue;
98 std::string GroupName
= DI
->getDef()->getValueAsString("GroupName");
99 DiagsInGroup
[GroupName
].DiagsInGroup
.push_back(R
);
102 // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
103 // groups (these are warnings that GCC supports that clang never produces).
104 Diags
= Records
.getAllDerivedDefinitions("DiagGroup");
105 for (unsigned i
= 0, e
= Diags
.size(); i
!= e
; ++i
) {
106 Record
*Group
= Diags
[i
];
107 GroupInfo
&GI
= DiagsInGroup
[Group
->getValueAsString("GroupName")];
109 std::vector
<Record
*> SubGroups
= Group
->getValueAsListOfDefs("SubGroups");
110 for (unsigned j
= 0, e
= SubGroups
.size(); j
!= e
; ++j
)
111 GI
.SubGroups
.push_back(SubGroups
[j
]->getValueAsString("GroupName"));
114 // Assign unique ID numbers to the groups.
116 for (std::map
<std::string
, GroupInfo
>::iterator
117 I
= DiagsInGroup
.begin(), E
= DiagsInGroup
.end(); I
!= E
; ++I
, ++IDNo
)
118 I
->second
.IDNo
= IDNo
;
120 // Walk through the groups emitting an array for each diagnostic of the diags
121 // that are mapped to.
122 OS
<< "\n#ifdef GET_DIAG_ARRAYS\n";
124 for (std::map
<std::string
, GroupInfo
>::iterator
125 I
= DiagsInGroup
.begin(), E
= DiagsInGroup
.end(); I
!= E
; ++I
) {
126 MaxLen
= std::max(MaxLen
, (unsigned)I
->first
.size());
128 std::vector
<const Record
*> &V
= I
->second
.DiagsInGroup
;
130 OS
<< "static const short DiagArray" << I
->second
.IDNo
<< "[] = { ";
131 for (unsigned i
= 0, e
= V
.size(); i
!= e
; ++i
)
132 OS
<< "diag::" << V
[i
]->getName() << ", ";
136 const std::vector
<std::string
> &SubGroups
= I
->second
.SubGroups
;
137 if (!SubGroups
.empty()) {
138 OS
<< "static const char DiagSubGroup" << I
->second
.IDNo
<< "[] = { ";
139 for (unsigned i
= 0, e
= SubGroups
.size(); i
!= e
; ++i
) {
140 std::map
<std::string
, GroupInfo
>::iterator RI
=
141 DiagsInGroup
.find(SubGroups
[i
]);
142 assert(RI
!= DiagsInGroup
.end() && "Referenced without existing?");
143 OS
<< RI
->second
.IDNo
<< ", ";
148 OS
<< "#endif // GET_DIAG_ARRAYS\n\n";
150 // Emit the table now.
151 OS
<< "\n#ifdef GET_DIAG_TABLE\n";
152 for (std::map
<std::string
, GroupInfo
>::iterator
153 I
= DiagsInGroup
.begin(), E
= DiagsInGroup
.end(); I
!= E
; ++I
) {
154 std::string S
= I
->first
;
156 // Group option string.
157 OS
<< " { \"" << S
<< "\","
158 << std::string(MaxLen
-I
->first
.size()+1, ' ');
160 // Diagnostics in the group.
161 if (I
->second
.DiagsInGroup
.empty())
164 OS
<< "DiagArray" << I
->second
.IDNo
<< ", ";
167 if (I
->second
.SubGroups
.empty())
170 OS
<< "DiagSubGroup" << I
->second
.IDNo
;
173 OS
<< "#endif // GET_DIAG_TABLE\n\n";