Diagnostic.cpp revision 5b4681c8ef65808ec4d72ab6081efd24d53d4969
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 ERROR = 0x04, 33 class_mask = 0x07 34}; 35 36/// DiagnosticFlags - A set of flags, or'd together, that describe the 37/// diagnostic. 38static unsigned char DiagnosticFlags[] = { 39#define DIAG(ENUM,FLAGS,DESC) FLAGS, 40#include "clang/Basic/DiagnosticKinds.def" 41 0 42}; 43 44/// getDiagClass - Return the class field of the diagnostic. 45/// 46static unsigned getBuiltinDiagClass(unsigned DiagID) { 47 assert(DiagID < diag::NUM_BUILTIN_DIAGNOSTICS && 48 "Diagnostic ID out of range!"); 49 return DiagnosticFlags[DiagID] & class_mask; 50} 51 52/// DiagnosticText - An english message to print for the diagnostic. These 53/// should be localized. 54static const char * const DiagnosticText[] = { 55#define DIAG(ENUM,FLAGS,DESC) DESC, 56#include "clang/Basic/DiagnosticKinds.def" 57 0 58}; 59 60//===----------------------------------------------------------------------===// 61// Custom Diagnostic information 62//===----------------------------------------------------------------------===// 63 64namespace clang { 65 namespace diag { 66 class CustomDiagInfo { 67 typedef std::pair<Diagnostic::Level, std::string> DiagDesc; 68 std::vector<DiagDesc> DiagInfo; 69 std::map<DiagDesc, unsigned> DiagIDs; 70 public: 71 72 /// getDescription - Return the description of the specified custom 73 /// diagnostic. 74 const char *getDescription(unsigned DiagID) const { 75 assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() && 76 "Invalid diagnosic ID"); 77 return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].second.c_str(); 78 } 79 80 /// getLevel - Return the level of the specified custom diagnostic. 81 Diagnostic::Level getLevel(unsigned DiagID) const { 82 assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() && 83 "Invalid diagnosic ID"); 84 return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].first; 85 } 86 87 unsigned getOrCreateDiagID(Diagnostic::Level L, const char *Message) { 88 DiagDesc D(L, Message); 89 // Check to see if it already exists. 90 std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D); 91 if (I != DiagIDs.end() && I->first == D) 92 return I->second; 93 94 // If not, assign a new ID. 95 unsigned ID = DiagInfo.size()+diag::NUM_BUILTIN_DIAGNOSTICS; 96 DiagIDs.insert(std::make_pair(D, ID)); 97 DiagInfo.push_back(D); 98 return ID; 99 } 100 }; 101 102 } // end diag namespace 103} // end clang namespace 104 105 106//===----------------------------------------------------------------------===// 107// Common Diagnostic implementation 108//===----------------------------------------------------------------------===// 109 110Diagnostic::Diagnostic(DiagnosticClient &client) : Client(client) { 111 IgnoreAllWarnings = false; 112 WarningsAsErrors = false; 113 WarnOnExtensions = false; 114 ErrorOnExtensions = false; 115 // Clear all mappings, setting them to MAP_DEFAULT. 116 memset(DiagMappings, 0, sizeof(DiagMappings)); 117 118 ErrorOccurred = false; 119 NumDiagnostics = 0; 120 NumErrors = 0; 121 CustomDiagInfo = 0; 122} 123 124Diagnostic::~Diagnostic() { 125 delete CustomDiagInfo; 126} 127 128/// getCustomDiagID - Return an ID for a diagnostic with the specified message 129/// and level. If this is the first request for this diagnosic, it is 130/// registered and created, otherwise the existing ID is returned. 131unsigned Diagnostic::getCustomDiagID(Level L, const char *Message) { 132 if (CustomDiagInfo == 0) 133 CustomDiagInfo = new diag::CustomDiagInfo(); 134 return CustomDiagInfo->getOrCreateDiagID(L, Message); 135} 136 137 138/// isBuiltinNoteWarningOrExtension - Return true if the unmapped diagnostic 139/// level of the specified diagnostic ID is a Note, Warning, or Extension. 140/// Note that this only works on builtin diagnostics, not custom ones. 141bool Diagnostic::isBuiltinNoteWarningOrExtension(unsigned DiagID) { 142 return DiagID < diag::NUM_BUILTIN_DIAGNOSTICS && 143 getBuiltinDiagClass(DiagID) < ERROR; 144} 145 146 147/// getDescription - Given a diagnostic ID, return a description of the 148/// issue. 149const char *Diagnostic::getDescription(unsigned DiagID) { 150 if (DiagID < diag::NUM_BUILTIN_DIAGNOSTICS) 151 return DiagnosticText[DiagID]; 152 else 153 return CustomDiagInfo->getDescription(DiagID); 154} 155 156/// getDiagnosticLevel - Based on the way the client configured the Diagnostic 157/// object, classify the specified diagnostic ID into a Level, consumable by 158/// the DiagnosticClient. 159Diagnostic::Level Diagnostic::getDiagnosticLevel(unsigned DiagID) const { 160 // Handle custom diagnostics, which cannot be mapped. 161 if (DiagID >= diag::NUM_BUILTIN_DIAGNOSTICS) 162 return CustomDiagInfo->getLevel(DiagID); 163 164 unsigned DiagClass = getBuiltinDiagClass(DiagID); 165 166 // Specific non-error diagnostics may be mapped to various levels from ignored 167 // to error. 168 if (DiagClass < ERROR) { 169 switch (getDiagnosticMapping((diag::kind)DiagID)) { 170 case diag::MAP_DEFAULT: break; 171 case diag::MAP_IGNORE: return Diagnostic::Ignored; 172 case diag::MAP_WARNING: DiagClass = WARNING; break; 173 case diag::MAP_ERROR: DiagClass = ERROR; break; 174 } 175 } 176 177 // Map diagnostic classes based on command line argument settings. 178 if (DiagClass == EXTENSION) { 179 if (ErrorOnExtensions) 180 DiagClass = ERROR; 181 else if (WarnOnExtensions) 182 DiagClass = WARNING; 183 else 184 return Ignored; 185 } 186 187 // If warnings are globally mapped to ignore or error, do it. 188 if (DiagClass == WARNING) { 189 if (IgnoreAllWarnings) 190 return Diagnostic::Ignored; 191 if (WarningsAsErrors) 192 DiagClass = ERROR; 193 } 194 195 switch (DiagClass) { 196 default: assert(0 && "Unknown diagnostic class!"); 197 case NOTE: return Diagnostic::Note; 198 case WARNING: return Diagnostic::Warning; 199 case ERROR: return Diagnostic::Error; 200 } 201} 202 203/// Report - Issue the message to the client. If the client wants us to stop 204/// compilation, return true, otherwise return false. DiagID is a member of 205/// the diag::kind enum. 206void Diagnostic::Report(DiagnosticClient* C, 207 FullSourceLoc Pos, unsigned DiagID, 208 const std::string *Strs, unsigned NumStrs, 209 const SourceRange *Ranges, unsigned NumRanges) { 210 211 // Figure out the diagnostic level of this message. 212 Diagnostic::Level DiagLevel = getDiagnosticLevel(DiagID); 213 214 // If the client doesn't care about this message, don't issue it. 215 if (DiagLevel == Diagnostic::Ignored) 216 return; 217 218 // Set the diagnostic client if it isn't set already. 219 if (!C) C = &Client; 220 221 // If this is not an error and we are in a system header, ignore it. We have 222 // to check on the original class here, because we also want to ignore 223 // extensions and warnings in -Werror and -pedantic-errors modes, which *map* 224 // warnings/extensions to errors. 225 if (DiagID < diag::NUM_BUILTIN_DIAGNOSTICS && 226 getBuiltinDiagClass(DiagID) != ERROR && 227 Client.isInSystemHeader(Pos)) 228 return; 229 230 if (DiagLevel >= Diagnostic::Error) { 231 ErrorOccurred = true; 232 233 if (C == &Client) 234 ++NumErrors; 235 } 236 237 // Finally, report it. 238 239 C->HandleDiagnostic(*this, DiagLevel, Pos, (diag::kind)DiagID, 240 Strs, NumStrs, Ranges, NumRanges); 241 242 if (C == &Client) 243 ++NumDiagnostics; 244} 245 246DiagnosticClient::~DiagnosticClient() {} 247