blob: 158e8ff33f48a8b5602c7d7815e7ed0c7a5fcf4b [file] [log] [blame]
Reid Spencer5f016e22007-07-11 17:01:13 +00001//===--- Diagnostic.cpp - C Language Family Diagnostic Handling -----------===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner0bc735f2007-12-29 19:59:25 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Reid Spencer5f016e22007-07-11 17:01:13 +00007//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the Diagnostic-related interfaces.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Basic/Diagnostic.h"
15#include "clang/Basic/SourceLocation.h"
16#include <cassert>
Chris Lattner182745a2007-12-02 01:09:57 +000017#include <vector>
18#include <map>
Reid Spencer5f016e22007-07-11 17:01:13 +000019using namespace clang;
20
Chris Lattner182745a2007-12-02 01:09:57 +000021//===----------------------------------------------------------------------===//
22// Builtin Diagnostic information
23//===----------------------------------------------------------------------===//
24
Reid Spencer5f016e22007-07-11 17:01:13 +000025/// Flag values for diagnostics.
26enum {
27 // Diagnostic classes.
28 NOTE = 0x01,
29 WARNING = 0x02,
30 EXTENSION = 0x03,
31 ERROR = 0x04,
Reid Spencer5f016e22007-07-11 17:01:13 +000032 class_mask = 0x07
33};
34
35/// DiagnosticFlags - A set of flags, or'd together, that describe the
36/// diagnostic.
37static unsigned char DiagnosticFlags[] = {
38#define DIAG(ENUM,FLAGS,DESC) FLAGS,
39#include "clang/Basic/DiagnosticKinds.def"
40 0
41};
42
43/// getDiagClass - Return the class field of the diagnostic.
44///
Chris Lattner07506182007-11-30 22:53:43 +000045static unsigned getBuiltinDiagClass(unsigned DiagID) {
46 assert(DiagID < diag::NUM_BUILTIN_DIAGNOSTICS &&
47 "Diagnostic ID out of range!");
Reid Spencer5f016e22007-07-11 17:01:13 +000048 return DiagnosticFlags[DiagID] & class_mask;
49}
50
51/// DiagnosticText - An english message to print for the diagnostic. These
52/// should be localized.
53static const char * const DiagnosticText[] = {
54#define DIAG(ENUM,FLAGS,DESC) DESC,
55#include "clang/Basic/DiagnosticKinds.def"
56 0
57};
58
Chris Lattner182745a2007-12-02 01:09:57 +000059//===----------------------------------------------------------------------===//
60// Custom Diagnostic information
61//===----------------------------------------------------------------------===//
62
63namespace clang {
64 namespace diag {
65 class CustomDiagInfo {
66 typedef std::pair<Diagnostic::Level, std::string> DiagDesc;
67 std::vector<DiagDesc> DiagInfo;
68 std::map<DiagDesc, unsigned> DiagIDs;
69 public:
70
71 /// getDescription - Return the description of the specified custom
72 /// diagnostic.
73 const char *getDescription(unsigned DiagID) const {
74 assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() &&
75 "Invalid diagnosic ID");
76 return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].second.c_str();
77 }
78
79 /// getLevel - Return the level of the specified custom diagnostic.
80 Diagnostic::Level getLevel(unsigned DiagID) const {
81 assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() &&
82 "Invalid diagnosic ID");
83 return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].first;
84 }
85
86 unsigned getOrCreateDiagID(Diagnostic::Level L, const char *Message) {
87 DiagDesc D(L, Message);
88 // Check to see if it already exists.
89 std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
90 if (I != DiagIDs.end() && I->first == D)
91 return I->second;
92
93 // If not, assign a new ID.
94 unsigned ID = DiagInfo.size()+diag::NUM_BUILTIN_DIAGNOSTICS;
95 DiagIDs.insert(std::make_pair(D, ID));
96 DiagInfo.push_back(D);
97 return ID;
98 }
99 };
100
101 } // end diag namespace
102} // end clang namespace
103
104
105//===----------------------------------------------------------------------===//
106// Common Diagnostic implementation
107//===----------------------------------------------------------------------===//
108
Reid Spencer5f016e22007-07-11 17:01:13 +0000109Diagnostic::Diagnostic(DiagnosticClient &client) : Client(client) {
110 WarningsAsErrors = false;
111 WarnOnExtensions = false;
112 ErrorOnExtensions = false;
113 // Clear all mappings, setting them to MAP_DEFAULT.
114 memset(DiagMappings, 0, sizeof(DiagMappings));
115
116 ErrorOccurred = false;
117 NumDiagnostics = 0;
118 NumErrors = 0;
Chris Lattner182745a2007-12-02 01:09:57 +0000119 CustomDiagInfo = 0;
Reid Spencer5f016e22007-07-11 17:01:13 +0000120}
121
Chris Lattner182745a2007-12-02 01:09:57 +0000122Diagnostic::~Diagnostic() {
123 delete CustomDiagInfo;
124}
125
126/// getCustomDiagID - Return an ID for a diagnostic with the specified message
127/// and level. If this is the first request for this diagnosic, it is
128/// registered and created, otherwise the existing ID is returned.
129unsigned Diagnostic::getCustomDiagID(Level L, const char *Message) {
130 if (CustomDiagInfo == 0)
131 CustomDiagInfo = new diag::CustomDiagInfo();
132 return CustomDiagInfo->getOrCreateDiagID(L, Message);
133}
134
135
Chris Lattner07506182007-11-30 22:53:43 +0000136/// isBuiltinNoteWarningOrExtension - Return true if the unmapped diagnostic
137/// level of the specified diagnostic ID is a Note, Warning, or Extension.
138/// Note that this only works on builtin diagnostics, not custom ones.
139bool Diagnostic::isBuiltinNoteWarningOrExtension(unsigned DiagID) {
140 return DiagID < diag::NUM_BUILTIN_DIAGNOSTICS &&
141 getBuiltinDiagClass(DiagID) < ERROR;
Reid Spencer5f016e22007-07-11 17:01:13 +0000142}
143
144
145/// getDescription - Given a diagnostic ID, return a description of the
146/// issue.
147const char *Diagnostic::getDescription(unsigned DiagID) {
Chris Lattner07506182007-11-30 22:53:43 +0000148 if (DiagID < diag::NUM_BUILTIN_DIAGNOSTICS)
149 return DiagnosticText[DiagID];
150 else
Chris Lattner182745a2007-12-02 01:09:57 +0000151 return CustomDiagInfo->getDescription(DiagID);
Reid Spencer5f016e22007-07-11 17:01:13 +0000152}
153
154/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
155/// object, classify the specified diagnostic ID into a Level, consumable by
156/// the DiagnosticClient.
157Diagnostic::Level Diagnostic::getDiagnosticLevel(unsigned DiagID) const {
Chris Lattner182745a2007-12-02 01:09:57 +0000158 // Handle custom diagnostics, which cannot be mapped.
159 if (DiagID >= diag::NUM_BUILTIN_DIAGNOSTICS)
160 return CustomDiagInfo->getLevel(DiagID);
Chris Lattner07506182007-11-30 22:53:43 +0000161
162 unsigned DiagClass = getBuiltinDiagClass(DiagID);
Reid Spencer5f016e22007-07-11 17:01:13 +0000163
164 // Specific non-error diagnostics may be mapped to various levels from ignored
165 // to error.
166 if (DiagClass < ERROR) {
167 switch (getDiagnosticMapping((diag::kind)DiagID)) {
168 case diag::MAP_DEFAULT: break;
169 case diag::MAP_IGNORE: return Ignored;
170 case diag::MAP_WARNING: DiagClass = WARNING; break;
171 case diag::MAP_ERROR: DiagClass = ERROR; break;
172 }
173 }
174
175 // Map diagnostic classes based on command line argument settings.
176 if (DiagClass == EXTENSION) {
177 if (ErrorOnExtensions)
178 DiagClass = ERROR;
179 else if (WarnOnExtensions)
180 DiagClass = WARNING;
181 else
182 return Ignored;
183 }
184
185 // If warnings are to be treated as errors, indicate this as such.
186 if (DiagClass == WARNING && WarningsAsErrors)
187 DiagClass = ERROR;
188
189 switch (DiagClass) {
190 default: assert(0 && "Unknown diagnostic class!");
191 case NOTE: return Diagnostic::Note;
192 case WARNING: return Diagnostic::Warning;
193 case ERROR: return Diagnostic::Error;
Reid Spencer5f016e22007-07-11 17:01:13 +0000194 }
195}
196
197/// Report - Issue the message to the client. If the client wants us to stop
198/// compilation, return true, otherwise return false. DiagID is a member of
199/// the diag::kind enum.
Ted Kremenek9c728dc2007-12-12 22:39:36 +0000200void Diagnostic::Report(FullSourceLoc Pos, unsigned DiagID,
Reid Spencer5f016e22007-07-11 17:01:13 +0000201 const std::string *Strs, unsigned NumStrs,
202 const SourceRange *Ranges, unsigned NumRanges) {
203 // Figure out the diagnostic level of this message.
204 Diagnostic::Level DiagLevel = getDiagnosticLevel(DiagID);
205
206 // If the client doesn't care about this message, don't issue it.
207 if (DiagLevel == Diagnostic::Ignored)
208 return;
209
210 if (DiagLevel >= Diagnostic::Error) {
211 ErrorOccurred = true;
212 ++NumErrors;
213 }
214
215 // Are we going to ignore this diagnosic?
Ted Kremenek9c728dc2007-12-12 22:39:36 +0000216 if (Client.IgnoreDiagnostic(DiagLevel, Pos))
Reid Spencer5f016e22007-07-11 17:01:13 +0000217 return;
218
219 // Finally, report it.
Ted Kremenek9c728dc2007-12-12 22:39:36 +0000220 Client.HandleDiagnostic(*this, DiagLevel, Pos, (diag::kind)DiagID,
Chris Lattner07506182007-11-30 22:53:43 +0000221 Strs, NumStrs, Ranges, NumRanges);
Reid Spencer5f016e22007-07-11 17:01:13 +0000222 ++NumDiagnostics;
223}
224
225DiagnosticClient::~DiagnosticClient() {}