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/Support/Streams.h"
19 #include "llvm/ADT/DenseSet.h"
20 #include "llvm/ADT/StringExtras.h"
21 #include "llvm/ADT/VectorExtras.h"
26 //===----------------------------------------------------------------------===//
27 // Warning Tables (.inc file) generation.
28 //===----------------------------------------------------------------------===//
30 void ClangDiagsDefsEmitter::run(std::ostream
&OS
) {
31 // Write the #if guard
32 if (!Component
.empty()) {
33 std::string ComponentName
= UppercaseString(Component
);
34 OS
<< "#ifdef " << ComponentName
<< "START\n";
35 OS
<< "__" << ComponentName
<< "START = DIAG_START_" << ComponentName
37 OS
<< "#undef " << ComponentName
<< "START\n";
41 const std::vector
<Record
*> &Diags
=
42 Records
.getAllDerivedDefinitions("Diagnostic");
44 for (unsigned i
= 0, e
= Diags
.size(); i
!= e
; ++i
) {
45 const Record
&R
= *Diags
[i
];
46 // Filter by component.
47 if (!Component
.empty() && Component
!= R
.getValueAsString("Component"))
50 OS
<< "DIAG(" << R
.getName() << ", ";
51 OS
<< R
.getValueAsDef("Class")->getName();
52 OS
<< ", diag::" << R
.getValueAsDef("DefaultMapping")->getName();
54 // Description string.
56 std::string S
= R
.getValueAsString("Text");
60 // Warning associated with the diagnostic.
61 if (DefInit
*DI
= dynamic_cast<DefInit
*>(R
.getValueInit("Group"))) {
62 S
= DI
->getDef()->getValueAsString("GroupName");
64 OS
<< ", \"" << S
<< "\"";
72 //===----------------------------------------------------------------------===//
73 // Warning Group Tables generation
74 //===----------------------------------------------------------------------===//
77 std::vector
<const Record
*> DiagsInGroup
;
78 std::vector
<std::string
> SubGroups
;
82 void ClangDiagGroupsEmitter::run(std::ostream
&OS
) {
83 // Invert the 1-[0/1] mapping of diags to group into a one to many mapping of
84 // groups to diags in the group.
85 std::map
<std::string
, GroupInfo
> DiagsInGroup
;
87 std::vector
<Record
*> Diags
=
88 Records
.getAllDerivedDefinitions("Diagnostic");
89 for (unsigned i
= 0, e
= Diags
.size(); i
!= e
; ++i
) {
90 const Record
*R
= Diags
[i
];
91 DefInit
*DI
= dynamic_cast<DefInit
*>(R
->getValueInit("Group"));
92 if (DI
== 0) continue;
93 std::string GroupName
= DI
->getDef()->getValueAsString("GroupName");
94 DiagsInGroup
[GroupName
].DiagsInGroup
.push_back(R
);
97 // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
98 // groups (these are warnings that GCC supports that clang never produces).
99 Diags
= Records
.getAllDerivedDefinitions("DiagGroup");
100 for (unsigned i
= 0, e
= Diags
.size(); i
!= e
; ++i
) {
101 Record
*Group
= Diags
[i
];
102 GroupInfo
&GI
= DiagsInGroup
[Group
->getValueAsString("GroupName")];
104 std::vector
<Record
*> SubGroups
= Group
->getValueAsListOfDefs("SubGroups");
105 for (unsigned j
= 0, e
= SubGroups
.size(); j
!= e
; ++j
)
106 GI
.SubGroups
.push_back(SubGroups
[j
]->getValueAsString("GroupName"));
109 // Assign unique ID numbers to the groups.
111 for (std::map
<std::string
, GroupInfo
>::iterator
112 I
= DiagsInGroup
.begin(), E
= DiagsInGroup
.end(); I
!= E
; ++I
, ++IDNo
)
113 I
->second
.IDNo
= IDNo
;
115 // Walk through the groups emitting an array for each diagnostic of the diags
116 // that are mapped to.
117 OS
<< "\n#ifdef GET_DIAG_ARRAYS\n";
119 for (std::map
<std::string
, GroupInfo
>::iterator
120 I
= DiagsInGroup
.begin(), E
= DiagsInGroup
.end(); I
!= E
; ++I
) {
121 MaxLen
= std::max(MaxLen
, (unsigned)I
->first
.size());
123 std::vector
<const Record
*> &V
= I
->second
.DiagsInGroup
;
125 OS
<< "static const short DiagArray" << I
->second
.IDNo
<< "[] = { ";
126 for (unsigned i
= 0, e
= V
.size(); i
!= e
; ++i
)
127 OS
<< "diag::" << V
[i
]->getName() << ", ";
131 const std::vector
<std::string
> &SubGroups
= I
->second
.SubGroups
;
132 if (!SubGroups
.empty()) {
133 OS
<< "static const char DiagSubGroup" << I
->second
.IDNo
<< "[] = { ";
134 for (unsigned i
= 0, e
= SubGroups
.size(); i
!= e
; ++i
) {
135 std::map
<std::string
, GroupInfo
>::iterator RI
=
136 DiagsInGroup
.find(SubGroups
[i
]);
137 assert(RI
!= DiagsInGroup
.end() && "Referenced without existing?");
138 OS
<< RI
->second
.IDNo
<< ", ";
143 OS
<< "#endif // GET_DIAG_ARRAYS\n\n";
145 // Emit the table now.
146 OS
<< "\n#ifdef GET_DIAG_TABLE\n";
147 for (std::map
<std::string
, GroupInfo
>::iterator
148 I
= DiagsInGroup
.begin(), E
= DiagsInGroup
.end(); I
!= E
; ++I
) {
149 std::string S
= I
->first
;
151 // Group option string.
152 OS
<< " { \"" << S
<< "\","
153 << std::string(MaxLen
-I
->first
.size()+1, ' ');
155 // Diagnostics in the group.
156 if (I
->second
.DiagsInGroup
.empty())
159 OS
<< "DiagArray" << I
->second
.IDNo
<< ", ";
162 if (I
->second
.SubGroups
.empty())
165 OS
<< "DiagSubGroup" << I
->second
.IDNo
;
168 OS
<< "#endif // GET_DIAG_TABLE\n\n";