blob: 16bdd4a6c22574dc59870e62030cec6352e57860 [file] [log] [blame]
Chris Lattner4b009652007-07-25 00:24:17 +00001//===--- Diagnostic.cpp - C Language Family Diagnostic Handling -----------===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner959e5be2007-12-29 19:59:25 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Chris Lattner4b009652007-07-25 00:24:17 +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 Lattner217df512007-12-02 01:09:57 +000017#include <vector>
18#include <map>
Chris Lattner8b8720f2008-03-10 17:04:53 +000019#include <cstring>
Chris Lattner4b009652007-07-25 00:24:17 +000020using namespace clang;
21
Chris Lattner217df512007-12-02 01:09:57 +000022//===----------------------------------------------------------------------===//
23// Builtin Diagnostic information
24//===----------------------------------------------------------------------===//
25
Chris Lattner4b009652007-07-25 00:24:17 +000026/// Flag values for diagnostics.
27enum {
28 // Diagnostic classes.
29 NOTE = 0x01,
30 WARNING = 0x02,
31 EXTENSION = 0x03,
Daniel Dunbar103baef2008-08-05 00:07:51 +000032 EXTWARN = 0x04,
33 ERROR = 0x05,
Chris Lattner4b009652007-07-25 00:24:17 +000034 class_mask = 0x07
35};
36
37/// DiagnosticFlags - A set of flags, or'd together, that describe the
38/// diagnostic.
39static unsigned char DiagnosticFlags[] = {
40#define DIAG(ENUM,FLAGS,DESC) FLAGS,
41#include "clang/Basic/DiagnosticKinds.def"
42 0
43};
44
45/// getDiagClass - Return the class field of the diagnostic.
46///
Chris Lattner4478db92007-11-30 22:53:43 +000047static unsigned getBuiltinDiagClass(unsigned DiagID) {
48 assert(DiagID < diag::NUM_BUILTIN_DIAGNOSTICS &&
49 "Diagnostic ID out of range!");
Chris Lattner4b009652007-07-25 00:24:17 +000050 return DiagnosticFlags[DiagID] & class_mask;
51}
52
53/// DiagnosticText - An english message to print for the diagnostic. These
54/// should be localized.
55static const char * const DiagnosticText[] = {
56#define DIAG(ENUM,FLAGS,DESC) DESC,
57#include "clang/Basic/DiagnosticKinds.def"
58 0
59};
60
Chris Lattner217df512007-12-02 01:09:57 +000061//===----------------------------------------------------------------------===//
62// Custom Diagnostic information
63//===----------------------------------------------------------------------===//
64
65namespace clang {
66 namespace diag {
67 class CustomDiagInfo {
68 typedef std::pair<Diagnostic::Level, std::string> DiagDesc;
69 std::vector<DiagDesc> DiagInfo;
70 std::map<DiagDesc, unsigned> DiagIDs;
71 public:
72
73 /// getDescription - Return the description of the specified custom
74 /// diagnostic.
75 const char *getDescription(unsigned DiagID) const {
76 assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() &&
77 "Invalid diagnosic ID");
78 return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].second.c_str();
79 }
80
81 /// getLevel - Return the level of the specified custom diagnostic.
82 Diagnostic::Level getLevel(unsigned DiagID) const {
83 assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() &&
84 "Invalid diagnosic ID");
85 return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].first;
86 }
87
88 unsigned getOrCreateDiagID(Diagnostic::Level L, const char *Message) {
89 DiagDesc D(L, Message);
90 // Check to see if it already exists.
91 std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
92 if (I != DiagIDs.end() && I->first == D)
93 return I->second;
94
95 // If not, assign a new ID.
96 unsigned ID = DiagInfo.size()+diag::NUM_BUILTIN_DIAGNOSTICS;
97 DiagIDs.insert(std::make_pair(D, ID));
98 DiagInfo.push_back(D);
99 return ID;
100 }
101 };
102
103 } // end diag namespace
104} // end clang namespace
105
106
107//===----------------------------------------------------------------------===//
108// Common Diagnostic implementation
109//===----------------------------------------------------------------------===//
110
Ted Kremenek5c341732008-08-07 17:49:57 +0000111Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
Chris Lattner3a22b7c2008-05-29 15:36:45 +0000112 IgnoreAllWarnings = false;
Chris Lattner4b009652007-07-25 00:24:17 +0000113 WarningsAsErrors = false;
114 WarnOnExtensions = false;
115 ErrorOnExtensions = false;
116 // Clear all mappings, setting them to MAP_DEFAULT.
117 memset(DiagMappings, 0, sizeof(DiagMappings));
118
119 ErrorOccurred = false;
120 NumDiagnostics = 0;
121 NumErrors = 0;
Chris Lattner217df512007-12-02 01:09:57 +0000122 CustomDiagInfo = 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000123}
124
Chris Lattner217df512007-12-02 01:09:57 +0000125Diagnostic::~Diagnostic() {
126 delete CustomDiagInfo;
127}
128
129/// getCustomDiagID - Return an ID for a diagnostic with the specified message
130/// and level. If this is the first request for this diagnosic, it is
131/// registered and created, otherwise the existing ID is returned.
132unsigned Diagnostic::getCustomDiagID(Level L, const char *Message) {
133 if (CustomDiagInfo == 0)
134 CustomDiagInfo = new diag::CustomDiagInfo();
135 return CustomDiagInfo->getOrCreateDiagID(L, Message);
136}
137
138
Chris Lattner4478db92007-11-30 22:53:43 +0000139/// isBuiltinNoteWarningOrExtension - Return true if the unmapped diagnostic
140/// level of the specified diagnostic ID is a Note, Warning, or Extension.
141/// Note that this only works on builtin diagnostics, not custom ones.
142bool Diagnostic::isBuiltinNoteWarningOrExtension(unsigned DiagID) {
143 return DiagID < diag::NUM_BUILTIN_DIAGNOSTICS &&
144 getBuiltinDiagClass(DiagID) < ERROR;
Chris Lattner4b009652007-07-25 00:24:17 +0000145}
146
147
148/// getDescription - Given a diagnostic ID, return a description of the
149/// issue.
150const char *Diagnostic::getDescription(unsigned DiagID) {
Chris Lattner4478db92007-11-30 22:53:43 +0000151 if (DiagID < diag::NUM_BUILTIN_DIAGNOSTICS)
152 return DiagnosticText[DiagID];
153 else
Chris Lattner217df512007-12-02 01:09:57 +0000154 return CustomDiagInfo->getDescription(DiagID);
Chris Lattner4b009652007-07-25 00:24:17 +0000155}
156
157/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
158/// object, classify the specified diagnostic ID into a Level, consumable by
159/// the DiagnosticClient.
160Diagnostic::Level Diagnostic::getDiagnosticLevel(unsigned DiagID) const {
Chris Lattner217df512007-12-02 01:09:57 +0000161 // Handle custom diagnostics, which cannot be mapped.
162 if (DiagID >= diag::NUM_BUILTIN_DIAGNOSTICS)
163 return CustomDiagInfo->getLevel(DiagID);
Chris Lattner4478db92007-11-30 22:53:43 +0000164
165 unsigned DiagClass = getBuiltinDiagClass(DiagID);
Chris Lattner4b009652007-07-25 00:24:17 +0000166
167 // Specific non-error diagnostics may be mapped to various levels from ignored
168 // to error.
169 if (DiagClass < ERROR) {
170 switch (getDiagnosticMapping((diag::kind)DiagID)) {
171 case diag::MAP_DEFAULT: break;
Chris Lattner3a22b7c2008-05-29 15:36:45 +0000172 case diag::MAP_IGNORE: return Diagnostic::Ignored;
Chris Lattner4b009652007-07-25 00:24:17 +0000173 case diag::MAP_WARNING: DiagClass = WARNING; break;
174 case diag::MAP_ERROR: DiagClass = ERROR; break;
175 }
176 }
177
178 // Map diagnostic classes based on command line argument settings.
179 if (DiagClass == EXTENSION) {
180 if (ErrorOnExtensions)
181 DiagClass = ERROR;
182 else if (WarnOnExtensions)
183 DiagClass = WARNING;
184 else
185 return Ignored;
Daniel Dunbar103baef2008-08-05 00:07:51 +0000186 } else if (DiagClass == EXTWARN) {
187 DiagClass = ErrorOnExtensions ? ERROR : WARNING;
Chris Lattner4b009652007-07-25 00:24:17 +0000188 }
189
Chris Lattner3a22b7c2008-05-29 15:36:45 +0000190 // If warnings are globally mapped to ignore or error, do it.
191 if (DiagClass == WARNING) {
192 if (IgnoreAllWarnings)
193 return Diagnostic::Ignored;
194 if (WarningsAsErrors)
195 DiagClass = ERROR;
196 }
Chris Lattner4b009652007-07-25 00:24:17 +0000197
198 switch (DiagClass) {
199 default: assert(0 && "Unknown diagnostic class!");
200 case NOTE: return Diagnostic::Note;
201 case WARNING: return Diagnostic::Warning;
202 case ERROR: return Diagnostic::Error;
Chris Lattner4b009652007-07-25 00:24:17 +0000203 }
204}
205
206/// Report - Issue the message to the client. If the client wants us to stop
207/// compilation, return true, otherwise return false. DiagID is a member of
208/// the diag::kind enum.
Ted Kremenek7877f2b2008-03-31 18:23:15 +0000209void Diagnostic::Report(DiagnosticClient* C,
210 FullSourceLoc Pos, unsigned DiagID,
Chris Lattner4b009652007-07-25 00:24:17 +0000211 const std::string *Strs, unsigned NumStrs,
212 const SourceRange *Ranges, unsigned NumRanges) {
Chris Lattner84602d72008-02-03 09:00:04 +0000213
Chris Lattner4b009652007-07-25 00:24:17 +0000214 // Figure out the diagnostic level of this message.
215 Diagnostic::Level DiagLevel = getDiagnosticLevel(DiagID);
216
217 // If the client doesn't care about this message, don't issue it.
218 if (DiagLevel == Diagnostic::Ignored)
219 return;
Ted Kremenek265a3a02008-04-14 21:21:38 +0000220
221 // Set the diagnostic client if it isn't set already.
Ted Kremenek5c341732008-08-07 17:49:57 +0000222 if (!C) C = Client;
Chris Lattner84602d72008-02-03 09:00:04 +0000223
224 // If this is not an error and we are in a system header, ignore it. We have
225 // to check on the original class here, because we also want to ignore
226 // extensions and warnings in -Werror and -pedantic-errors modes, which *map*
227 // warnings/extensions to errors.
228 if (DiagID < diag::NUM_BUILTIN_DIAGNOSTICS &&
229 getBuiltinDiagClass(DiagID) != ERROR &&
Ted Kremenek5c341732008-08-07 17:49:57 +0000230 Client->isInSystemHeader(Pos))
Chris Lattner84602d72008-02-03 09:00:04 +0000231 return;
Chris Lattner4b009652007-07-25 00:24:17 +0000232
233 if (DiagLevel >= Diagnostic::Error) {
234 ErrorOccurred = true;
Ted Kremenek051fe9d2008-04-14 19:56:12 +0000235
Ted Kremenek5c341732008-08-07 17:49:57 +0000236 if (C == Client)
Ted Kremenek051fe9d2008-04-14 19:56:12 +0000237 ++NumErrors;
Chris Lattner4b009652007-07-25 00:24:17 +0000238 }
239
Chris Lattner4b009652007-07-25 00:24:17 +0000240 // Finally, report it.
Ted Kremenek7877f2b2008-03-31 18:23:15 +0000241
Ted Kremenek7877f2b2008-03-31 18:23:15 +0000242 C->HandleDiagnostic(*this, DiagLevel, Pos, (diag::kind)DiagID,
243 Strs, NumStrs, Ranges, NumRanges);
Ted Kremenek051fe9d2008-04-14 19:56:12 +0000244
Ted Kremenek5c341732008-08-07 17:49:57 +0000245 if (C == Client)
Ted Kremenek051fe9d2008-04-14 19:56:12 +0000246 ++NumDiagnostics;
Chris Lattner4b009652007-07-25 00:24:17 +0000247}
248
249DiagnosticClient::~DiagnosticClient() {}