Diagnostic.cpp revision 4489fe10fa073eb326e2c8906db170f009050911
1//===--- Diagnostic.cpp - C Language Family Diagnostic Handling -----------===// 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// 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> 17#include <vector> 18#include <map> 19#include <cstring> 20using namespace clang; 21 22//===----------------------------------------------------------------------===// 23// Builtin Diagnostic information 24//===----------------------------------------------------------------------===// 25 26/// Flag values for diagnostics. 27enum { 28 // Diagnostic classes. 29 NOTE = 0x01, 30 WARNING = 0x02, 31 EXTENSION = 0x03, 32 EXTWARN = 0x04, 33 ERROR = 0x05, 34 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/// 47static unsigned getBuiltinDiagClass(unsigned DiagID) { 48 assert(DiagID < diag::NUM_BUILTIN_DIAGNOSTICS && 49 "Diagnostic ID out of range!"); 50 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 61//===----------------------------------------------------------------------===// 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 111Diagnostic::Diagnostic(DiagnosticClient &client) : Client(client) { 112 IgnoreAllWarnings = false; 113 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; 122 CustomDiagInfo = 0; 123} 124 125Diagnostic::~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 139/// 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; 145} 146 147 148/// getDescription - Given a diagnostic ID, return a description of the 149/// issue. 150const char *Diagnostic::getDescription(unsigned DiagID) { 151 if (DiagID < diag::NUM_BUILTIN_DIAGNOSTICS) 152 return DiagnosticText[DiagID]; 153 else 154 return CustomDiagInfo->getDescription(DiagID); 155} 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 { 161 // Handle custom diagnostics, which cannot be mapped. 162 if (DiagID >= diag::NUM_BUILTIN_DIAGNOSTICS) 163 return CustomDiagInfo->getLevel(DiagID); 164 165 unsigned DiagClass = getBuiltinDiagClass(DiagID); 166 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; 172 case diag::MAP_IGNORE: return Diagnostic::Ignored; 173 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; 186 } else if (DiagClass == EXTWARN) { 187 DiagClass = ErrorOnExtensions ? ERROR : WARNING; 188 } 189 190 // 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 } 197 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; 203 } 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. 209void Diagnostic::Report(DiagnosticClient* C, 210 FullSourceLoc Pos, unsigned DiagID, 211 const std::string *Strs, unsigned NumStrs, 212 const SourceRange *Ranges, unsigned NumRanges) { 213 214 // 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; 220 221 // Set the diagnostic client if it isn't set already. 222 if (!C) C = &Client; 223 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 && 230 Client.isInSystemHeader(Pos)) 231 return; 232 233 if (DiagLevel >= Diagnostic::Error) { 234 ErrorOccurred = true; 235 236 if (C == &Client) 237 ++NumErrors; 238 } 239 240 // Finally, report it. 241 242 C->HandleDiagnostic(*this, DiagLevel, Pos, (diag::kind)DiagID, 243 Strs, NumStrs, Ranges, NumRanges); 244 245 if (C == &Client) 246 ++NumDiagnostics; 247} 248 249DiagnosticClient::~DiagnosticClient() {} 250