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/VectorExtras.h"
20 #include "llvm/ADT/DenseSet.h"
26 //===----------------------------------------------------------------------===//
27 // Generic routines for all Clang TableGen backens.
28 //===----------------------------------------------------------------------===//
30 typedef std::vector<Record*> RecordVector;
31 typedef std::vector<Record*> SuperClassVector;
32 typedef std::vector<RecordVal> RecordValVector;
34 static const RecordVal* findRecordVal(const Record& R, const std::string &key) {
35 const RecordValVector &Vals = R.getValues();
36 for (RecordValVector::const_iterator I=Vals.begin(), E=Vals.end(); I!=E; ++I)
37 if ((*I).getName() == key)
43 static const Record* getDiagKind(const Record* DiagClass, const Record &R) {
44 const SuperClassVector &SC = R.getSuperClasses();
45 for (SuperClassVector::const_iterator I=SC.begin(), E=SC.end(); I!=E; ++I)
46 if ((*I)->isSubClassOf(DiagClass) &&
47 (*I)->getName() != "DiagnosticControlled")
53 static void EmitEscaped(std::ostream& OS, const std::string &s) {
54 for (std::string::const_iterator I=s.begin(), E=s.end(); I!=E; ++I)
56 default: OS << *I; break;
57 case '\"': OS << "\\" << *I; break;
58 case '\\': OS << "\\\\"; break;
62 static void EmitAllCaps(std::ostream& OS, const std::string &s) {
63 for (std::string::const_iterator I=s.begin(), E=s.end(); I!=E; ++I)
64 OS << char(toupper(*I));
67 //===----------------------------------------------------------------------===//
68 // Warning Tables (.inc file) generation.
69 //===----------------------------------------------------------------------===//
71 static void ProcessDiag(std::ostream& OS, const Record* DiagClass,
74 const Record* DiagKind = getDiagKind(DiagClass, R);
78 OS << "DIAG(" << R.getName() << ", ";
79 EmitAllCaps(OS, DiagKind->getName());
81 const RecordVal* Text = findRecordVal(R, "Text");
82 assert(Text && "No 'Text' entry in Diagnostic.");
83 const StringInit* TextVal = dynamic_cast<const StringInit*>(Text->getValue());
84 assert(TextVal && "Value 'Text' must be a string.");
86 EmitEscaped(OS, TextVal->getValue());
90 void ClangDiagsDefsEmitter::run(std::ostream &OS) {
91 const RecordVector &Diags = Records.getAllDerivedDefinitions("Diagnostic");
93 const Record* DiagClass = Records.getClass("Diagnostic");
94 assert(DiagClass && "No Diagnostic class defined.");
96 // Write the #if guard
97 if (!Component.empty()) {
99 EmitAllCaps(OS, Component);
101 EmitAllCaps(OS, Component);
102 OS << "START = DIAG_START_";
103 EmitAllCaps(OS, Component);
105 EmitAllCaps(OS, Component);
106 OS << "START\n#endif\n";
109 for (RecordVector::const_iterator I=Diags.begin(), E=Diags.end(); I!=E; ++I) {
110 if (!Component.empty()) {
111 const RecordVal* V = findRecordVal(**I, "Component");
115 const StringInit* SV = dynamic_cast<const StringInit*>(V->getValue());
116 if (SV->getValue() != Component)
120 ProcessDiag(OS, DiagClass, **I);
124 //===----------------------------------------------------------------------===//
125 // Warning Group Tables generation.
126 //===----------------------------------------------------------------------===//
128 static const std::string &getOptName(const Record *R) {
129 const RecordVal *V = findRecordVal(*R, "Name");
130 assert(V && "Options must have a 'Name' value.");
131 const StringInit* SV = dynamic_cast<const StringInit*>(V->getValue());
132 assert(SV && "'Name' entry must be a string.");
133 return SV->getValue();
137 struct VISIBILITY_HIDDEN CompareOptName {
138 bool operator()(const Record* A, const Record* B) {
139 return getOptName(A) < getOptName(B);
144 typedef std::set<const Record*> DiagnosticSet;
145 typedef std::map<const Record*, DiagnosticSet, CompareOptName> OptionMap;
146 typedef llvm::DenseSet<const ListInit*> VisitedLists;
148 static void BuildGroup(DiagnosticSet& DS, VisitedLists &Visited, const Init* X);
150 static void BuildGroup(DiagnosticSet &DS, VisitedLists &Visited,
151 const ListInit* LV) {
153 // Simple hack to prevent including a list multiple times. This may be useful
154 // if one declares an Option by including a bunch of other Options that
155 // include other Options, etc.
156 if (Visited.count(LV))
161 // Iterate through the list and grab all DiagnosticControlled.
162 for (ListInit::const_iterator I = LV->begin(), E = LV->end(); I!=E; ++I)
163 BuildGroup(DS, Visited, *I);
166 static void BuildGroup(DiagnosticSet& DS, VisitedLists &Visited,
169 // If an Option includes another Option, inline the Diagnostics of the
171 if (Def->isSubClassOf("Option")) {
172 if (const RecordVal* V = findRecordVal(*Def, "Members"))
173 if (const ListInit* LV = dynamic_cast<const ListInit*>(V->getValue()))
174 BuildGroup(DS, Visited, LV);
179 if (Def->isSubClassOf("DiagnosticControlled"))
183 static void BuildGroup(DiagnosticSet& DS, VisitedLists &Visited,
186 if (const DefInit *D = dynamic_cast<const DefInit*>(X))
187 BuildGroup(DS, Visited, D->getDef());
189 // We may have some other cases here in the future.
193 void ClangOptionsEmitter::run(std::ostream &OS) {
194 // Build up a map from options to controlled diagnostics.
197 const RecordVector &Opts = Records.getAllDerivedDefinitions("Option");
198 for (RecordVector::const_iterator I=Opts.begin(), E=Opts.end(); I!=E; ++I)
199 if (const RecordVal* V = findRecordVal(**I, "Members"))
200 if (const ListInit* LV = dynamic_cast<const ListInit*>(V->getValue())) {
201 VisitedLists Visited;
202 BuildGroup(OM[*I], Visited, LV);
205 // Iterate through the OptionMap and emit the declarations.
206 for (OptionMap::iterator I = OM.begin(), E = OM.end(); I!=E; ++I) {
207 // Output the option.
208 OS << "static const diag::kind " << I->first->getName() << "[] = { ";
210 DiagnosticSet &DS = I->second;
212 for (DiagnosticSet::iterator I2 = DS.begin(), E2 = DS.end(); I2!=E2; ++I2) {
218 OS << "diag::" << (*I2)->getName();
223 // Now emit the OptionTable table.
224 OS << "\nstatic const WarningOption OptionTable[] = {";
226 for (OptionMap::iterator I = OM.begin(), E = OM.end(); I!=E; ++I) {
232 OS << "\n {\"" << getOptName(I->first)
233 << "\", DIAGS(" << I->first->getName() << ")}";