Diagnostic.cpp revision 20c6b3b85e186cd52d5d99489132d71d498159eb
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/IdentifierTable.h" 16#include "clang/Basic/SourceLocation.h" 17#include "llvm/ADT/SmallVector.h" 18#include "llvm/ADT/StringExtras.h" 19#include <vector> 20#include <map> 21#include <cstring> 22using namespace clang; 23 24//===----------------------------------------------------------------------===// 25// Builtin Diagnostic information 26//===----------------------------------------------------------------------===// 27 28/// Flag values for diagnostics. 29enum { 30 // Diagnostic classes. 31 NOTE = 0x01, 32 WARNING = 0x02, 33 EXTENSION = 0x03, 34 EXTWARN = 0x04, 35 ERROR = 0x05, 36 class_mask = 0x07 37}; 38 39namespace clang { 40 namespace diag { 41 enum _kind{ 42#define DIAG(ENUM,FLAGS,DESC) ENUM, 43#define LEXSTART 44#define PARSESTART 45#define ASTSTART 46#define SEMASTART 47#define ANALYSISSTART 48#include "clang/Basic/DiagnosticKinds.def" 49 NUM_BUILTIN_DIAGNOSTICS = DIAG_UPPER_LIMIT 50 }; 51 } 52} 53 54/// DiagnosticFlags - A set of flags, or'd together, that describe the 55/// diagnostic. 56#define DIAG(ENUM,FLAGS,DESC) FLAGS, 57static unsigned char DiagnosticFlagsCommon[] = { 58#include "clang/Basic/DiagnosticCommonKinds.def" 59 0 60}; 61static unsigned char DiagnosticFlagsLex[] = { 62#include "clang/Basic/DiagnosticLexKinds.def" 63 0 64}; 65static unsigned char DiagnosticFlagsParse[] = { 66#include "clang/Basic/DiagnosticParseKinds.def" 67 0 68}; 69static unsigned char DiagnosticFlagsAST[] = { 70#include "clang/Basic/DiagnosticASTKinds.def" 71 0 72}; 73static unsigned char DiagnosticFlagsSema[] = { 74#include "clang/Basic/DiagnosticSemaKinds.def" 75 0 76}; 77static unsigned char DiagnosticFlagsAnalysis[] = { 78#include "clang/Basic/DiagnosticAnalysisKinds.def" 79 0 80}; 81#undef DIAG 82 83/// getDiagClass - Return the class field of the diagnostic. 84/// 85static unsigned getBuiltinDiagClass(unsigned DiagID) { 86 assert(DiagID < diag::NUM_BUILTIN_DIAGNOSTICS && 87 "Diagnostic ID out of range!"); 88 unsigned res; 89 if (DiagID < DIAG_START_LEX) 90 res = DiagnosticFlagsCommon[DiagID]; 91 else if (DiagID < DIAG_START_PARSE) 92 res = DiagnosticFlagsLex[DiagID - DIAG_START_LEX - 1]; 93 else if (DiagID < DIAG_START_AST) 94 res = DiagnosticFlagsParse[DiagID - DIAG_START_PARSE - 1]; 95 else if (DiagID < DIAG_START_SEMA) 96 res = DiagnosticFlagsAST[DiagID - DIAG_START_AST - 1]; 97 else if (DiagID < DIAG_START_ANALYSIS) 98 res = DiagnosticFlagsSema[DiagID - DIAG_START_SEMA - 1]; 99 else 100 res = DiagnosticFlagsAnalysis[DiagID - DIAG_START_ANALYSIS - 1]; 101 return res & class_mask; 102} 103 104/// DiagnosticText - An english message to print for the diagnostic. These 105/// should be localized. 106#define DIAG(ENUM,FLAGS,DESC) DESC, 107static const char * const DiagnosticTextCommon[] = { 108#include "clang/Basic/DiagnosticCommonKinds.def" 109 0 110}; 111static const char * const DiagnosticTextLex[] = { 112#include "clang/Basic/DiagnosticLexKinds.def" 113 0 114}; 115static const char * const DiagnosticTextParse[] = { 116#include "clang/Basic/DiagnosticParseKinds.def" 117 0 118}; 119static const char * const DiagnosticTextAST[] = { 120#include "clang/Basic/DiagnosticASTKinds.def" 121 0 122}; 123static const char * const DiagnosticTextSema[] = { 124#include "clang/Basic/DiagnosticSemaKinds.def" 125 0 126}; 127static const char * const DiagnosticTextAnalysis[] = { 128#include "clang/Basic/DiagnosticAnalysisKinds.def" 129 0 130}; 131#undef DIAG 132 133//===----------------------------------------------------------------------===// 134// Custom Diagnostic information 135//===----------------------------------------------------------------------===// 136 137namespace clang { 138 namespace diag { 139 class CustomDiagInfo { 140 typedef std::pair<Diagnostic::Level, std::string> DiagDesc; 141 std::vector<DiagDesc> DiagInfo; 142 std::map<DiagDesc, unsigned> DiagIDs; 143 public: 144 145 /// getDescription - Return the description of the specified custom 146 /// diagnostic. 147 const char *getDescription(unsigned DiagID) const { 148 assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() && 149 "Invalid diagnosic ID"); 150 return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].second.c_str(); 151 } 152 153 /// getLevel - Return the level of the specified custom diagnostic. 154 Diagnostic::Level getLevel(unsigned DiagID) const { 155 assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() && 156 "Invalid diagnosic ID"); 157 return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].first; 158 } 159 160 unsigned getOrCreateDiagID(Diagnostic::Level L, const char *Message, 161 Diagnostic &Diags) { 162 DiagDesc D(L, Message); 163 // Check to see if it already exists. 164 std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D); 165 if (I != DiagIDs.end() && I->first == D) 166 return I->second; 167 168 // If not, assign a new ID. 169 unsigned ID = DiagInfo.size()+diag::NUM_BUILTIN_DIAGNOSTICS; 170 DiagIDs.insert(std::make_pair(D, ID)); 171 DiagInfo.push_back(D); 172 173 // If this is a warning, and all warnings are supposed to map to errors, 174 // insert the mapping now. 175 if (L == Diagnostic::Warning && Diags.getWarningsAsErrors()) 176 Diags.setDiagnosticMapping((diag::kind)ID, diag::MAP_ERROR); 177 return ID; 178 } 179 }; 180 181 } // end diag namespace 182} // end clang namespace 183 184 185//===----------------------------------------------------------------------===// 186// Common Diagnostic implementation 187//===----------------------------------------------------------------------===// 188 189static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT, 190 const char *Modifier, unsigned ML, 191 const char *Argument, unsigned ArgLen, 192 llvm::SmallVectorImpl<char> &Output) { 193 const char *Str = "<can't format argument>"; 194 Output.append(Str, Str+strlen(Str)); 195} 196 197 198Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) { 199 IgnoreAllWarnings = false; 200 WarningsAsErrors = false; 201 WarnOnExtensions = false; 202 ErrorOnExtensions = false; 203 SuppressSystemWarnings = false; 204 // Clear all mappings, setting them to MAP_DEFAULT. 205 memset(DiagMappings, 0, sizeof(DiagMappings)); 206 207 ErrorOccurred = false; 208 NumDiagnostics = 0; 209 NumErrors = 0; 210 CustomDiagInfo = 0; 211 CurDiagID = ~0U; 212 213 ArgToStringFn = DummyArgToStringFn; 214} 215 216Diagnostic::~Diagnostic() { 217 delete CustomDiagInfo; 218} 219 220/// getCustomDiagID - Return an ID for a diagnostic with the specified message 221/// and level. If this is the first request for this diagnosic, it is 222/// registered and created, otherwise the existing ID is returned. 223unsigned Diagnostic::getCustomDiagID(Level L, const char *Message) { 224 if (CustomDiagInfo == 0) 225 CustomDiagInfo = new diag::CustomDiagInfo(); 226 return CustomDiagInfo->getOrCreateDiagID(L, Message, *this); 227} 228 229 230/// isBuiltinNoteWarningOrExtension - Return true if the unmapped diagnostic 231/// level of the specified diagnostic ID is a Note, Warning, or Extension. 232/// Note that this only works on builtin diagnostics, not custom ones. 233bool Diagnostic::isBuiltinNoteWarningOrExtension(unsigned DiagID) { 234 return DiagID < diag::NUM_BUILTIN_DIAGNOSTICS && 235 getBuiltinDiagClass(DiagID) < ERROR; 236} 237 238 239/// getDescription - Given a diagnostic ID, return a description of the 240/// issue. 241const char *Diagnostic::getDescription(unsigned DiagID) const { 242 if (DiagID < diag::NUM_BUILTIN_DIAGNOSTICS) 243 { 244 if (DiagID < DIAG_START_LEX) 245 return DiagnosticTextCommon[DiagID]; 246 else if (DiagID < DIAG_START_PARSE) 247 return DiagnosticTextLex[DiagID - DIAG_START_LEX - 1]; 248 else if (DiagID < DIAG_START_AST) 249 return DiagnosticTextParse[DiagID - DIAG_START_PARSE - 1]; 250 else if (DiagID < DIAG_START_SEMA) 251 return DiagnosticTextAST[DiagID - DIAG_START_AST - 1]; 252 else if (DiagID < DIAG_START_ANALYSIS) 253 return DiagnosticTextSema[DiagID - DIAG_START_SEMA - 1]; 254 else if (DiagID < DIAG_UPPER_LIMIT) 255 return DiagnosticTextAnalysis[DiagID - DIAG_START_ANALYSIS - 1]; 256 } 257 258 return CustomDiagInfo->getDescription(DiagID); 259} 260 261/// getDiagnosticLevel - Based on the way the client configured the Diagnostic 262/// object, classify the specified diagnostic ID into a Level, consumable by 263/// the DiagnosticClient. 264Diagnostic::Level Diagnostic::getDiagnosticLevel(unsigned DiagID) const { 265 // Handle custom diagnostics, which cannot be mapped. 266 if (DiagID >= diag::NUM_BUILTIN_DIAGNOSTICS) 267 return CustomDiagInfo->getLevel(DiagID); 268 269 unsigned DiagClass = getBuiltinDiagClass(DiagID); 270 271 // Specific non-error diagnostics may be mapped to various levels from ignored 272 // to error. 273 if (DiagClass < ERROR) { 274 switch (getDiagnosticMapping((diag::kind)DiagID)) { 275 case diag::MAP_DEFAULT: break; 276 case diag::MAP_IGNORE: return Diagnostic::Ignored; 277 case diag::MAP_WARNING: DiagClass = WARNING; break; 278 case diag::MAP_ERROR: DiagClass = ERROR; break; 279 } 280 } 281 282 // Map diagnostic classes based on command line argument settings. 283 if (DiagClass == EXTENSION) { 284 if (ErrorOnExtensions) 285 DiagClass = ERROR; 286 else if (WarnOnExtensions) 287 DiagClass = WARNING; 288 else 289 return Ignored; 290 } else if (DiagClass == EXTWARN) { 291 DiagClass = ErrorOnExtensions ? ERROR : WARNING; 292 } 293 294 // If warnings are globally mapped to ignore or error, do it. 295 if (DiagClass == WARNING) { 296 if (IgnoreAllWarnings) 297 return Diagnostic::Ignored; 298 if (WarningsAsErrors) 299 DiagClass = ERROR; 300 } 301 302 switch (DiagClass) { 303 default: assert(0 && "Unknown diagnostic class!"); 304 case NOTE: return Diagnostic::Note; 305 case WARNING: return Diagnostic::Warning; 306 case ERROR: return Diagnostic::Error; 307 } 308} 309 310/// ProcessDiag - This is the method used to report a diagnostic that is 311/// finally fully formed. 312void Diagnostic::ProcessDiag() { 313 DiagnosticInfo Info(this); 314 315 // Figure out the diagnostic level of this message. 316 Diagnostic::Level DiagLevel = getDiagnosticLevel(Info.getID()); 317 318 // If the client doesn't care about this message, don't issue it. 319 if (DiagLevel == Diagnostic::Ignored) 320 return; 321 322 // If this is not an error and we are in a system header, ignore it. We 323 // have to check on the original Diag ID here, because we also want to 324 // ignore extensions and warnings in -Werror and -pedantic-errors modes, 325 // which *map* warnings/extensions to errors. 326 if (SuppressSystemWarnings && 327 Info.getID() < diag::NUM_BUILTIN_DIAGNOSTICS && 328 getBuiltinDiagClass(Info.getID()) != ERROR && 329 Info.getLocation().isValid() && 330 Info.getLocation().getSpellingLoc().isInSystemHeader()) 331 return; 332 333 if (DiagLevel >= Diagnostic::Error) { 334 ErrorOccurred = true; 335 336 ++NumErrors; 337 } 338 339 // Finally, report it. 340 Client->HandleDiagnostic(DiagLevel, Info); 341 if (Client->IncludeInDiagnosticCounts()) ++NumDiagnostics; 342} 343 344 345DiagnosticClient::~DiagnosticClient() {} 346 347 348/// ModifierIs - Return true if the specified modifier matches specified string. 349template <std::size_t StrLen> 350static bool ModifierIs(const char *Modifier, unsigned ModifierLen, 351 const char (&Str)[StrLen]) { 352 return StrLen-1 == ModifierLen && !memcmp(Modifier, Str, StrLen-1); 353} 354 355/// HandleSelectModifier - Handle the integer 'select' modifier. This is used 356/// like this: %select{foo|bar|baz}2. This means that the integer argument 357/// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'. 358/// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'. 359/// This is very useful for certain classes of variant diagnostics. 360static void HandleSelectModifier(unsigned ValNo, 361 const char *Argument, unsigned ArgumentLen, 362 llvm::SmallVectorImpl<char> &OutStr) { 363 const char *ArgumentEnd = Argument+ArgumentLen; 364 365 // Skip over 'ValNo' |'s. 366 while (ValNo) { 367 const char *NextVal = std::find(Argument, ArgumentEnd, '|'); 368 assert(NextVal != ArgumentEnd && "Value for integer select modifier was" 369 " larger than the number of options in the diagnostic string!"); 370 Argument = NextVal+1; // Skip this string. 371 --ValNo; 372 } 373 374 // Get the end of the value. This is either the } or the |. 375 const char *EndPtr = std::find(Argument, ArgumentEnd, '|'); 376 // Add the value to the output string. 377 OutStr.append(Argument, EndPtr); 378} 379 380/// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the 381/// letter 's' to the string if the value is not 1. This is used in cases like 382/// this: "you idiot, you have %4 parameter%s4!". 383static void HandleIntegerSModifier(unsigned ValNo, 384 llvm::SmallVectorImpl<char> &OutStr) { 385 if (ValNo != 1) 386 OutStr.push_back('s'); 387} 388 389 390/// PluralNumber - Parse an unsigned integer and advance Start. 391static unsigned PluralNumber(const char *&Start, const char *End) 392{ 393 // Programming 101: Parse a decimal number :-) 394 unsigned Val = 0; 395 while (Start != End && *Start >= '0' && *Start <= '9') { 396 Val *= 10; 397 Val += *Start - '0'; 398 ++Start; 399 } 400 return Val; 401} 402 403/// TestPluralRange - Test if Val is in the parsed range. Modifies Start. 404static bool TestPluralRange(unsigned Val, const char *&Start, const char *End) 405{ 406 if (*Start != '[') { 407 unsigned Ref = PluralNumber(Start, End); 408 return Ref == Val; 409 } 410 411 ++Start; 412 unsigned Low = PluralNumber(Start, End); 413 assert(*Start == ',' && "Bad plural expression syntax: expected ,"); 414 ++Start; 415 unsigned High = PluralNumber(Start, End); 416 assert(*Start == ']' && "Bad plural expression syntax: expected )"); 417 ++Start; 418 return Low <= Val && Val <= High; 419} 420 421/// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier. 422static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) 423{ 424 // Empty condition? 425 if (*Start == ':') 426 return true; 427 428 while (1) { 429 char C = *Start; 430 if (C == '%') { 431 // Modulo expression 432 ++Start; 433 unsigned Arg = PluralNumber(Start, End); 434 assert(*Start == '=' && "Bad plural expression syntax: expected ="); 435 ++Start; 436 unsigned ValMod = ValNo % Arg; 437 if (TestPluralRange(ValMod, Start, End)) 438 return true; 439 } else { 440 assert((C == '[' || (C >= '0' && C <= '9')) && 441 "Bad plural expression syntax: unexpected character"); 442 // Range expression 443 if (TestPluralRange(ValNo, Start, End)) 444 return true; 445 } 446 447 // Scan for next or-expr part. 448 Start = std::find(Start, End, ','); 449 if(Start == End) 450 break; 451 ++Start; 452 } 453 return false; 454} 455 456/// HandlePluralModifier - Handle the integer 'plural' modifier. This is used 457/// for complex plural forms, or in languages where all plurals are complex. 458/// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are 459/// conditions that are tested in order, the form corresponding to the first 460/// that applies being emitted. The empty condition is always true, making the 461/// last form a default case. 462/// Conditions are simple boolean expressions, where n is the number argument. 463/// Here are the rules. 464/// condition := expression | empty 465/// empty := -> always true 466/// expression := numeric [',' expression] -> logical or 467/// numeric := range -> true if n in range 468/// | '%' number '=' range -> true if n % number in range 469/// range := number 470/// | '[' number ',' number ']' -> ranges are inclusive both ends 471/// 472/// Here are some examples from the GNU gettext manual written in this form: 473/// English: 474/// {1:form0|:form1} 475/// Latvian: 476/// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0} 477/// Gaeilge: 478/// {1:form0|2:form1|:form2} 479/// Romanian: 480/// {1:form0|0,%100=[1,19]:form1|:form2} 481/// Lithuanian: 482/// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1} 483/// Russian (requires repeated form): 484/// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2} 485/// Slovak 486/// {1:form0|[2,4]:form1|:form2} 487/// Polish (requires repeated form): 488/// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2} 489static void HandlePluralModifier(unsigned ValNo, 490 const char *Argument, unsigned ArgumentLen, 491 llvm::SmallVectorImpl<char> &OutStr) 492{ 493 const char *ArgumentEnd = Argument + ArgumentLen; 494 while (1) { 495 assert(Argument < ArgumentEnd && "Plural expression didn't match."); 496 const char *ExprEnd = Argument; 497 while (*ExprEnd != ':') { 498 assert(ExprEnd != ArgumentEnd && "Plural missing expression end"); 499 ++ExprEnd; 500 } 501 if (EvalPluralExpr(ValNo, Argument, ExprEnd)) { 502 Argument = ExprEnd + 1; 503 ExprEnd = std::find(Argument, ArgumentEnd, '|'); 504 OutStr.append(Argument, ExprEnd); 505 return; 506 } 507 Argument = std::find(Argument, ArgumentEnd - 1, '|') + 1; 508 } 509} 510 511 512/// FormatDiagnostic - Format this diagnostic into a string, substituting the 513/// formal arguments into the %0 slots. The result is appended onto the Str 514/// array. 515void DiagnosticInfo:: 516FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { 517 const char *DiagStr = getDiags()->getDescription(getID()); 518 const char *DiagEnd = DiagStr+strlen(DiagStr); 519 520 while (DiagStr != DiagEnd) { 521 if (DiagStr[0] != '%') { 522 // Append non-%0 substrings to Str if we have one. 523 const char *StrEnd = std::find(DiagStr, DiagEnd, '%'); 524 OutStr.append(DiagStr, StrEnd); 525 DiagStr = StrEnd; 526 continue; 527 } else if (DiagStr[1] == '%') { 528 OutStr.push_back('%'); // %% -> %. 529 DiagStr += 2; 530 continue; 531 } 532 533 // Skip the %. 534 ++DiagStr; 535 536 // This must be a placeholder for a diagnostic argument. The format for a 537 // placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0". 538 // The digit is a number from 0-9 indicating which argument this comes from. 539 // The modifier is a string of digits from the set [-a-z]+, arguments is a 540 // brace enclosed string. 541 const char *Modifier = 0, *Argument = 0; 542 unsigned ModifierLen = 0, ArgumentLen = 0; 543 544 // Check to see if we have a modifier. If so eat it. 545 if (!isdigit(DiagStr[0])) { 546 Modifier = DiagStr; 547 while (DiagStr[0] == '-' || 548 (DiagStr[0] >= 'a' && DiagStr[0] <= 'z')) 549 ++DiagStr; 550 ModifierLen = DiagStr-Modifier; 551 552 // If we have an argument, get it next. 553 if (DiagStr[0] == '{') { 554 ++DiagStr; // Skip {. 555 Argument = DiagStr; 556 557 for (; DiagStr[0] != '}'; ++DiagStr) 558 assert(DiagStr[0] && "Mismatched {}'s in diagnostic string!"); 559 ArgumentLen = DiagStr-Argument; 560 ++DiagStr; // Skip }. 561 } 562 } 563 564 assert(isdigit(*DiagStr) && "Invalid format for argument in diagnostic"); 565 unsigned ArgNo = *DiagStr++ - '0'; 566 567 switch (getArgKind(ArgNo)) { 568 // ---- STRINGS ---- 569 case Diagnostic::ak_std_string: { 570 const std::string &S = getArgStdStr(ArgNo); 571 assert(ModifierLen == 0 && "No modifiers for strings yet"); 572 OutStr.append(S.begin(), S.end()); 573 break; 574 } 575 case Diagnostic::ak_c_string: { 576 const char *S = getArgCStr(ArgNo); 577 assert(ModifierLen == 0 && "No modifiers for strings yet"); 578 OutStr.append(S, S + strlen(S)); 579 break; 580 } 581 // ---- INTEGERS ---- 582 case Diagnostic::ak_sint: { 583 int Val = getArgSInt(ArgNo); 584 585 if (ModifierIs(Modifier, ModifierLen, "select")) { 586 HandleSelectModifier((unsigned)Val, Argument, ArgumentLen, OutStr); 587 } else if (ModifierIs(Modifier, ModifierLen, "s")) { 588 HandleIntegerSModifier(Val, OutStr); 589 } else if (ModifierIs(Modifier, ModifierLen, "plural")) { 590 HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr); 591 } else { 592 assert(ModifierLen == 0 && "Unknown integer modifier"); 593 // FIXME: Optimize 594 std::string S = llvm::itostr(Val); 595 OutStr.append(S.begin(), S.end()); 596 } 597 break; 598 } 599 case Diagnostic::ak_uint: { 600 unsigned Val = getArgUInt(ArgNo); 601 602 if (ModifierIs(Modifier, ModifierLen, "select")) { 603 HandleSelectModifier(Val, Argument, ArgumentLen, OutStr); 604 } else if (ModifierIs(Modifier, ModifierLen, "s")) { 605 HandleIntegerSModifier(Val, OutStr); 606 } else if (ModifierIs(Modifier, ModifierLen, "plural")) { 607 HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr); 608 } else { 609 assert(ModifierLen == 0 && "Unknown integer modifier"); 610 611 // FIXME: Optimize 612 std::string S = llvm::utostr_32(Val); 613 OutStr.append(S.begin(), S.end()); 614 } 615 break; 616 } 617 // ---- NAMES and TYPES ---- 618 case Diagnostic::ak_identifierinfo: { 619 OutStr.push_back('\''); 620 const IdentifierInfo *II = getArgIdentifier(ArgNo); 621 assert(ModifierLen == 0 && "No modifiers for strings yet"); 622 OutStr.append(II->getName(), II->getName() + II->getLength()); 623 OutStr.push_back('\''); 624 break; 625 } 626 case Diagnostic::ak_qualtype: 627 case Diagnostic::ak_declarationname: 628 OutStr.push_back('\''); 629 getDiags()->ConvertArgToString(getArgKind(ArgNo), getRawArg(ArgNo), 630 Modifier, ModifierLen, 631 Argument, ArgumentLen, OutStr); 632 OutStr.push_back('\''); 633 break; 634 } 635 } 636} 637 638/// IncludeInDiagnosticCounts - This method (whose default implementation 639/// returns true) indicates whether the diagnostics handled by this 640/// DiagnosticClient should be included in the number of diagnostics 641/// reported by Diagnostic. 642bool DiagnosticClient::IncludeInDiagnosticCounts() const { return true; } 643