blob: a3f27ba75f2b36bcc15dfb6fa9696d49de925ad8 [file] [log] [blame]
Ted Kremenek04a847e2009-03-13 22:21:17 +00001//=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// These tablegen backends emit Clang diagnostics tables.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ClangDiagnosticsEmitter.h"
15#include "Record.h"
16#include "llvm/Support/Debug.h"
17#include "llvm/Support/Streams.h"
18#include "llvm/ADT/VectorExtras.h"
Ted Kremenek8b9d0272009-03-18 21:16:16 +000019#include "llvm/ADT/DenseSet.h"
20#include <set>
21#include <map>
Ted Kremenek04a847e2009-03-13 22:21:17 +000022
23using namespace llvm;
Ted Kremenek8b9d0272009-03-18 21:16:16 +000024
25//===----------------------------------------------------------------------===//
26// Generic routines for all Clang TableGen backens.
27//===----------------------------------------------------------------------===//
28
Ted Kremenek04a847e2009-03-13 22:21:17 +000029typedef std::vector<Record*> RecordVector;
30typedef std::vector<Record*> SuperClassVector;
31typedef std::vector<RecordVal> RecordValVector;
32
Ted Kremenek557f7f82009-03-13 22:53:41 +000033static const RecordVal* findRecordVal(const Record& R, const std::string &key) {
34 const RecordValVector &Vals = R.getValues();
Ted Kremenek04a847e2009-03-13 22:21:17 +000035 for (RecordValVector::const_iterator I=Vals.begin(), E=Vals.end(); I!=E; ++I)
36 if ((*I).getName() == key)
37 return &*I;
38
39 return 0;
40}
41
42static const Record* getDiagKind(const Record* DiagClass, const Record &R) {
43 const SuperClassVector &SC = R.getSuperClasses();
44 for (SuperClassVector::const_iterator I=SC.begin(), E=SC.end(); I!=E; ++I)
45 if ((*I)->isSubClassOf(DiagClass))
46 return *I;
47
48 return 0;
49}
50
51static void EmitEscaped(std::ostream& OS, const std::string &s) {
52 for (std::string::const_iterator I=s.begin(), E=s.end(); I!=E; ++I)
53 switch (*I) {
54 default: OS << *I; break;
55 case '\"': OS << "\\" << *I; break;
56 case '\\': OS << "\\\\"; break;
57 }
58}
59
Ted Kremenek557f7f82009-03-13 22:53:41 +000060static void EmitAllCaps(std::ostream& OS, const std::string &s) {
61 for (std::string::const_iterator I=s.begin(), E=s.end(); I!=E; ++I)
62 OS << char(toupper(*I));
63}
64
Ted Kremenek8b9d0272009-03-18 21:16:16 +000065//===----------------------------------------------------------------------===//
66// Warning Tables (.inc file) generation.
67//===----------------------------------------------------------------------===//
68
Ted Kremenek04a847e2009-03-13 22:21:17 +000069static void ProcessDiag(std::ostream& OS, const Record* DiagClass,
70 const Record& R) {
71
72 const Record* DiagKind = getDiagKind(DiagClass, R);
73 if (!DiagKind)
74 return;
75
76 OS << "DIAG(" << R.getName() << ", ";
Ted Kremenek557f7f82009-03-13 22:53:41 +000077 EmitAllCaps(OS, DiagKind->getName());
Ted Kremenek04a847e2009-03-13 22:21:17 +000078
Ted Kremenek557f7f82009-03-13 22:53:41 +000079 const RecordVal* Text = findRecordVal(R, "Text");
Ted Kremenek04a847e2009-03-13 22:21:17 +000080 assert(Text && "No 'Text' entry in Diagnostic.");
81 const StringInit* TextVal = dynamic_cast<const StringInit*>(Text->getValue());
82 assert(TextVal && "Value 'Text' must be a string.");
83 OS << ", \"";
84 EmitEscaped(OS, TextVal->getValue());
85 OS << "\")\n";
86}
87
88void ClangDiagsDefsEmitter::run(std::ostream &OS) {
89 const RecordVector &Diags = Records.getAllDerivedDefinitions("Diagnostic");
90
91 const Record* DiagClass = Records.getClass("Diagnostic");
92 assert(DiagClass && "No Diagnostic class defined.");
93
Ted Kremenek557f7f82009-03-13 22:53:41 +000094 // Write the #if guard
95 if (!Component.empty()) {
96 OS << "#ifdef ";
97 EmitAllCaps(OS, Component);
98 OS << "START\n__";
99 EmitAllCaps(OS, Component);
100 OS << "START = DIAG_START_";
101 EmitAllCaps(OS, Component);
102 OS << ",\n#undef ";
103 EmitAllCaps(OS, Component);
104 OS << "START\n#endif\n";
105 }
106
Ted Kremenek04a847e2009-03-13 22:21:17 +0000107 for (RecordVector::const_iterator I=Diags.begin(), E=Diags.end(); I!=E; ++I) {
Ted Kremenek557f7f82009-03-13 22:53:41 +0000108 if (!Component.empty()) {
109 const RecordVal* V = findRecordVal(**I, "Component");
110 if (!V)
111 continue;
112
113 const StringInit* SV = dynamic_cast<const StringInit*>(V->getValue());
114 if (SV->getValue() != Component)
115 continue;
116 }
117
Ted Kremenek04a847e2009-03-13 22:21:17 +0000118 ProcessDiag(OS, DiagClass, **I);
119 }
Ted Kremenek557f7f82009-03-13 22:53:41 +0000120}
Ted Kremenek8b9d0272009-03-18 21:16:16 +0000121
122//===----------------------------------------------------------------------===//
123// Warning Group Tables generation.
124//===----------------------------------------------------------------------===//
125
126typedef std::set<const Record*> DiagnosticSet;
127typedef std::map<const Record*, DiagnosticSet> OptionMap;
128typedef llvm::DenseSet<const ListInit*> VisitedLists;
129
130static void BuildGroup(DiagnosticSet& DS, VisitedLists &Visited, const Init* X);
131
132static void BuildGroup(DiagnosticSet &DS, VisitedLists &Visited,
133 const ListInit* LV) {
134
135 // Simple hack to prevent including a list multiple times. This may be useful
136 // if one declares an Option by including a bunch of other Options that
137 // include other Options, etc.
138 if (Visited.count(LV))
139 return;
140
141 Visited.insert(LV);
142
143 // Iterate through the list and grab all DiagnosticControlled.
144 for (ListInit::const_iterator I = LV->begin(), E = LV->end(); I!=E; ++I)
145 BuildGroup(DS, Visited, *I);
146}
147
148static void BuildGroup(DiagnosticSet& DS, VisitedLists &Visited,
149 const Record *Def) {
150
151 // If an Option includes another Option, inline the Diagnostics of the
152 // included Option.
153 if (Def->isSubClassOf("Option")) {
154 if (const RecordVal* V = findRecordVal(*Def, "Members"))
155 if (const ListInit* LV = dynamic_cast<const ListInit*>(V->getValue()))
156 BuildGroup(DS, Visited, LV);
157
158 return;
159 }
160
161 if (Def->isSubClassOf("DiagnosticControlled"))
162 DS.insert(Def);
163}
164
165static void BuildGroup(DiagnosticSet& DS, VisitedLists &Visited,
166 const Init* X) {
167
168 if (const DefInit *D = dynamic_cast<const DefInit*>(X))
169 BuildGroup(DS, Visited, D->getDef());
170
171 // We may have some other cases here in the future.
172}
173
174
175void ClangOptionsEmitter::run(std::ostream &OS) {
176 // Build up a map from options to controlled diagnostics.
177 OptionMap OM;
178
179 const RecordVector &Opts = Records.getAllDerivedDefinitions("Option");
180 for (RecordVector::const_iterator I=Opts.begin(), E=Opts.end(); I!=E; ++I)
181 if (const RecordVal* V = findRecordVal(**I, "Members"))
182 if (const ListInit* LV = dynamic_cast<const ListInit*>(V->getValue())) {
183 VisitedLists Visited;
184 BuildGroup(OM[*I], Visited, LV);
185 }
186
187 // Iterate through the OptionMap and emit the declarations.
188 for (OptionMap::iterator I = OM.begin(), E = OM.end(); I!=E; ++I) {
189// const RecordVal *V = findRecordVal(*I->first, "Name");
190// assert(V && "Options must have a 'Name' value.");
191// const StringInit* SV = dynamic_cast<const StringInit*>(V->getValue());
192// assert(SV && "'Name' entry must be a string.");
193
194 // Output the option.
195 OS << "static const diag::kind " << I->first->getName() << "[] = { ";
196
197 DiagnosticSet &DS = I->second;
198 bool first = true;
199 for (DiagnosticSet::iterator I2 = DS.begin(), E2 = DS.end(); I2!=E2; ++I2) {
200 if (first)
201 first = false;
202 else
203 OS << ", ";
204
205 OS << "diag::" << (*I2)->getName();
206 }
207 OS << " };\n";
208 }
209}