PrintfFormatString.cpp revision 36be1a672ff7f0d7c8e4ab725e9e084ab52b048a
1//= PrintfFormatStrings.cpp - Analysis of printf format strings --*- C++ -*-==// 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// Handling of format string in printf and friends. The structure of format 11// strings for fprintf() are described in C99 7.19.6.1. 12// 13//===----------------------------------------------------------------------===// 14 15#include "clang/Analysis/Analyses/PrintfFormatString.h" 16#include "clang/AST/ASTContext.h" 17#include "clang/AST/Type.h" 18#include "llvm/Support/raw_ostream.h" 19 20using clang::analyze_printf::ArgTypeResult; 21using clang::analyze_printf::FormatSpecifier; 22using clang::analyze_printf::FormatStringHandler; 23using clang::analyze_printf::OptionalAmount; 24using clang::analyze_printf::PositionContext; 25using clang::analyze_printf::ConversionSpecifier; 26using clang::analyze_printf::LengthModifier; 27 28using namespace clang; 29 30namespace { 31class FormatSpecifierResult { 32 FormatSpecifier FS; 33 const char *Start; 34 bool Stop; 35public: 36 FormatSpecifierResult(bool stop = false) 37 : Start(0), Stop(stop) {} 38 FormatSpecifierResult(const char *start, 39 const FormatSpecifier &fs) 40 : FS(fs), Start(start), Stop(false) {} 41 42 const char *getStart() const { return Start; } 43 bool shouldStop() const { return Stop; } 44 bool hasValue() const { return Start != 0; } 45 const FormatSpecifier &getValue() const { 46 assert(hasValue()); 47 return FS; 48 } 49 const FormatSpecifier &getValue() { return FS; } 50}; 51} // end anonymous namespace 52 53template <typename T> 54class UpdateOnReturn { 55 T &ValueToUpdate; 56 const T &ValueToCopy; 57public: 58 UpdateOnReturn(T &valueToUpdate, const T &valueToCopy) 59 : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {} 60 61 ~UpdateOnReturn() { 62 ValueToUpdate = ValueToCopy; 63 } 64}; 65 66//===----------------------------------------------------------------------===// 67// Methods for parsing format strings. 68//===----------------------------------------------------------------------===// 69 70static OptionalAmount ParseAmount(const char *&Beg, const char *E) { 71 const char *I = Beg; 72 UpdateOnReturn <const char*> UpdateBeg(Beg, I); 73 74 unsigned accumulator = 0; 75 bool hasDigits = false; 76 77 for ( ; I != E; ++I) { 78 char c = *I; 79 if (c >= '0' && c <= '9') { 80 hasDigits = true; 81 accumulator = (accumulator * 10) + (c - '0'); 82 continue; 83 } 84 85 if (hasDigits) 86 return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, 0); 87 88 break; 89 } 90 91 return OptionalAmount(); 92} 93 94static OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E, 95 unsigned &argIndex) { 96 if (*Beg == '*') { 97 ++Beg; 98 return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0); 99 } 100 101 return ParseAmount(Beg, E); 102} 103 104static OptionalAmount ParsePositionAmount(FormatStringHandler &H, 105 const char *Start, 106 const char *&Beg, const char *E, 107 PositionContext p) { 108 if (*Beg == '*') { 109 const char *I = Beg + 1; 110 const OptionalAmount &Amt = ParseAmount(I, E); 111 112 if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) { 113 H.HandleInvalidPosition(Beg, I - Beg, p); 114 return OptionalAmount(false); 115 } 116 117 if (I== E) { 118 // No more characters left? 119 H.HandleIncompleteFormatSpecifier(Start, E - Start); 120 return OptionalAmount(false); 121 } 122 123 assert(Amt.getHowSpecified() == OptionalAmount::Constant); 124 125 if (*I == '$') { 126 // Handle positional arguments 127 128 // Special case: '*0$', since this is an easy mistake. 129 if (Amt.getConstantAmount() == 0) { 130 H.HandleZeroPosition(Beg, I - Beg + 1); 131 return OptionalAmount(false); 132 } 133 134 const char *Tmp = Beg; 135 Beg = ++I; 136 137 return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1, 138 Tmp, 1); 139 } 140 141 H.HandleInvalidPosition(Beg, I - Beg, p); 142 return OptionalAmount(false); 143 } 144 145 return ParseAmount(Beg, E); 146} 147 148static bool ParsePrecision(FormatStringHandler &H, FormatSpecifier &FS, 149 const char *Start, const char *&Beg, const char *E, 150 unsigned *argIndex) { 151 if (argIndex) { 152 FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex)); 153 } 154 else { 155 const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, 156 analyze_printf::PrecisionPos); 157 if (Amt.isInvalid()) 158 return true; 159 FS.setPrecision(Amt); 160 } 161 return false; 162} 163 164static bool ParseFieldWidth(FormatStringHandler &H, FormatSpecifier &FS, 165 const char *Start, const char *&Beg, const char *E, 166 unsigned *argIndex) { 167 // FIXME: Support negative field widths. 168 if (argIndex) { 169 FS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex)); 170 } 171 else { 172 const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, 173 analyze_printf::FieldWidthPos); 174 if (Amt.isInvalid()) 175 return true; 176 FS.setFieldWidth(Amt); 177 } 178 return false; 179} 180 181static bool ParseArgPosition(FormatStringHandler &H, 182 FormatSpecifier &FS, const char *Start, 183 const char *&Beg, const char *E) { 184 185 using namespace clang::analyze_printf; 186 const char *I = Beg; 187 188 const OptionalAmount &Amt = ParseAmount(I, E); 189 190 if (I == E) { 191 // No more characters left? 192 H.HandleIncompleteFormatSpecifier(Start, E - Start); 193 return true; 194 } 195 196 if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') { 197 // Special case: '%0$', since this is an easy mistake. 198 if (Amt.getConstantAmount() == 0) { 199 H.HandleZeroPosition(Start, I - Start); 200 return true; 201 } 202 203 FS.setArgIndex(Amt.getConstantAmount() - 1); 204 FS.setUsesPositionalArg(); 205 // Update the caller's pointer if we decided to consume 206 // these characters. 207 Beg = I; 208 return false; 209 } 210 211 return false; 212} 213 214static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, 215 const char *&Beg, 216 const char *E, 217 unsigned &argIndex) { 218 219 using namespace clang::analyze_printf; 220 221 const char *I = Beg; 222 const char *Start = 0; 223 UpdateOnReturn <const char*> UpdateBeg(Beg, I); 224 225 // Look for a '%' character that indicates the start of a format specifier. 226 for ( ; I != E ; ++I) { 227 char c = *I; 228 if (c == '\0') { 229 // Detect spurious null characters, which are likely errors. 230 H.HandleNullChar(I); 231 return true; 232 } 233 if (c == '%') { 234 Start = I++; // Record the start of the format specifier. 235 break; 236 } 237 } 238 239 // No format specifier found? 240 if (!Start) 241 return false; 242 243 if (I == E) { 244 // No more characters left? 245 H.HandleIncompleteFormatSpecifier(Start, E - Start); 246 return true; 247 } 248 249 FormatSpecifier FS; 250 if (ParseArgPosition(H, FS, Start, I, E)) 251 return true; 252 253 if (I == E) { 254 // No more characters left? 255 H.HandleIncompleteFormatSpecifier(Start, E - Start); 256 return true; 257 } 258 259 // Look for flags (if any). 260 bool hasMore = true; 261 for ( ; I != E; ++I) { 262 switch (*I) { 263 default: hasMore = false; break; 264 case '-': FS.setIsLeftJustified(); break; 265 case '+': FS.setHasPlusPrefix(); break; 266 case ' ': FS.setHasSpacePrefix(); break; 267 case '#': FS.setHasAlternativeForm(); break; 268 case '0': FS.setHasLeadingZeros(); break; 269 } 270 if (!hasMore) 271 break; 272 } 273 274 if (I == E) { 275 // No more characters left? 276 H.HandleIncompleteFormatSpecifier(Start, E - Start); 277 return true; 278 } 279 280 // Look for the field width (if any). 281 if (ParseFieldWidth(H, FS, Start, I, E, 282 FS.usesPositionalArg() ? 0 : &argIndex)) 283 return true; 284 285 if (I == E) { 286 // No more characters left? 287 H.HandleIncompleteFormatSpecifier(Start, E - Start); 288 return true; 289 } 290 291 // Look for the precision (if any). 292 if (*I == '.') { 293 ++I; 294 if (I == E) { 295 H.HandleIncompleteFormatSpecifier(Start, E - Start); 296 return true; 297 } 298 299 if (ParsePrecision(H, FS, Start, I, E, 300 FS.usesPositionalArg() ? 0 : &argIndex)) 301 return true; 302 303 if (I == E) { 304 // No more characters left? 305 H.HandleIncompleteFormatSpecifier(Start, E - Start); 306 return true; 307 } 308 } 309 310 // Look for the length modifier. 311 LengthModifier::Kind lmKind = LengthModifier::None; 312 const char *lmPosition = I; 313 switch (*I) { 314 default: 315 break; 316 case 'h': 317 ++I; 318 lmKind = (I != E && *I == 'h') ? 319 ++I, LengthModifier::AsChar : LengthModifier::AsShort; 320 break; 321 case 'l': 322 ++I; 323 lmKind = (I != E && *I == 'l') ? 324 ++I, LengthModifier::AsLongLong : LengthModifier::AsLong; 325 break; 326 case 'j': lmKind = LengthModifier::AsIntMax; ++I; break; 327 case 'z': lmKind = LengthModifier::AsSizeT; ++I; break; 328 case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break; 329 case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break; 330 case 'q': lmKind = LengthModifier::AsLongLong; ++I; break; 331 } 332 LengthModifier lm(lmPosition, lmKind); 333 FS.setLengthModifier(lm); 334 335 if (I == E) { 336 // No more characters left? 337 H.HandleIncompleteFormatSpecifier(Start, E - Start); 338 return true; 339 } 340 341 if (*I == '\0') { 342 // Detect spurious null characters, which are likely errors. 343 H.HandleNullChar(I); 344 return true; 345 } 346 347 // Finally, look for the conversion specifier. 348 const char *conversionPosition = I++; 349 ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; 350 switch (*conversionPosition) { 351 default: 352 break; 353 // C99: 7.19.6.1 (section 8). 354 case '%': k = ConversionSpecifier::PercentArg; break; 355 case 'A': k = ConversionSpecifier::AArg; break; 356 case 'E': k = ConversionSpecifier::EArg; break; 357 case 'F': k = ConversionSpecifier::FArg; break; 358 case 'G': k = ConversionSpecifier::GArg; break; 359 case 'X': k = ConversionSpecifier::XArg; break; 360 case 'a': k = ConversionSpecifier::aArg; break; 361 case 'c': k = ConversionSpecifier::IntAsCharArg; break; 362 case 'd': k = ConversionSpecifier::dArg; break; 363 case 'e': k = ConversionSpecifier::eArg; break; 364 case 'f': k = ConversionSpecifier::fArg; break; 365 case 'g': k = ConversionSpecifier::gArg; break; 366 case 'i': k = ConversionSpecifier::iArg; break; 367 case 'n': k = ConversionSpecifier::OutIntPtrArg; break; 368 case 'o': k = ConversionSpecifier::oArg; break; 369 case 'p': k = ConversionSpecifier::VoidPtrArg; break; 370 case 's': k = ConversionSpecifier::CStrArg; break; 371 case 'u': k = ConversionSpecifier::uArg; break; 372 case 'x': k = ConversionSpecifier::xArg; break; 373 // Mac OS X (unicode) specific 374 case 'C': k = ConversionSpecifier::CArg; break; 375 case 'S': k = ConversionSpecifier::UnicodeStrArg; break; 376 // Objective-C. 377 case '@': k = ConversionSpecifier::ObjCObjArg; break; 378 // Glibc specific. 379 case 'm': k = ConversionSpecifier::PrintErrno; break; 380 } 381 ConversionSpecifier CS(conversionPosition, k); 382 FS.setConversionSpecifier(CS); 383 if (CS.consumesDataArgument() && !FS.usesPositionalArg()) 384 FS.setArgIndex(argIndex++); 385 386 if (k == ConversionSpecifier::InvalidSpecifier) { 387 // Assume the conversion takes one argument. 388 return !H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg); 389 } 390 return FormatSpecifierResult(Start, FS); 391} 392 393bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H, 394 const char *I, const char *E) { 395 396 unsigned argIndex = 0; 397 398 // Keep looking for a format specifier until we have exhausted the string. 399 while (I != E) { 400 const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E, argIndex); 401 // Did a fail-stop error of any kind occur when parsing the specifier? 402 // If so, don't do any more processing. 403 if (FSR.shouldStop()) 404 return true;; 405 // Did we exhaust the string or encounter an error that 406 // we can recover from? 407 if (!FSR.hasValue()) 408 continue; 409 // We have a format specifier. Pass it to the callback. 410 if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(), 411 I - FSR.getStart())) 412 return true; 413 } 414 assert(I == E && "Format string not exhausted"); 415 return false; 416} 417 418FormatStringHandler::~FormatStringHandler() {} 419 420//===----------------------------------------------------------------------===// 421// Methods on ArgTypeResult. 422//===----------------------------------------------------------------------===// 423 424bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const { 425 switch (K) { 426 case InvalidTy: 427 assert(false && "ArgTypeResult must be valid"); 428 return true; 429 430 case UnknownTy: 431 return true; 432 433 case SpecificTy: { 434 argTy = C.getCanonicalType(argTy).getUnqualifiedType(); 435 if (T == argTy) 436 return true; 437 if (const BuiltinType *BT = argTy->getAs<BuiltinType>()) 438 switch (BT->getKind()) { 439 default: 440 break; 441 case BuiltinType::Char_S: 442 case BuiltinType::SChar: 443 return T == C.UnsignedCharTy; 444 case BuiltinType::Char_U: 445 case BuiltinType::UChar: 446 return T == C.SignedCharTy; 447 case BuiltinType::Short: 448 return T == C.UnsignedShortTy; 449 case BuiltinType::UShort: 450 return T == C.ShortTy; 451 case BuiltinType::Int: 452 return T == C.UnsignedIntTy; 453 case BuiltinType::UInt: 454 return T == C.IntTy; 455 case BuiltinType::Long: 456 return T == C.UnsignedLongTy; 457 case BuiltinType::ULong: 458 return T == C.LongTy; 459 case BuiltinType::LongLong: 460 return T == C.UnsignedLongLongTy; 461 case BuiltinType::ULongLong: 462 return T == C.LongLongTy; 463 } 464 return false; 465 } 466 467 case CStrTy: { 468 const PointerType *PT = argTy->getAs<PointerType>(); 469 if (!PT) 470 return false; 471 QualType pointeeTy = PT->getPointeeType(); 472 if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>()) 473 switch (BT->getKind()) { 474 case BuiltinType::Void: 475 case BuiltinType::Char_U: 476 case BuiltinType::UChar: 477 case BuiltinType::Char_S: 478 case BuiltinType::SChar: 479 return true; 480 default: 481 break; 482 } 483 484 return false; 485 } 486 487 case WCStrTy: { 488 const PointerType *PT = argTy->getAs<PointerType>(); 489 if (!PT) 490 return false; 491 QualType pointeeTy = 492 C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType(); 493 return pointeeTy == C.getWCharType(); 494 } 495 496 case CPointerTy: 497 return argTy->getAs<PointerType>() != NULL || 498 argTy->getAs<ObjCObjectPointerType>() != NULL; 499 500 case ObjCPointerTy: 501 return argTy->getAs<ObjCObjectPointerType>() != NULL; 502 } 503 504 // FIXME: Should be unreachable, but Clang is currently emitting 505 // a warning. 506 return false; 507} 508 509QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const { 510 switch (K) { 511 case InvalidTy: 512 assert(false && "No representative type for Invalid ArgTypeResult"); 513 // Fall-through. 514 case UnknownTy: 515 return QualType(); 516 case SpecificTy: 517 return T; 518 case CStrTy: 519 return C.getPointerType(C.CharTy); 520 case WCStrTy: 521 return C.getPointerType(C.getWCharType()); 522 case ObjCPointerTy: 523 return C.ObjCBuiltinIdTy; 524 case CPointerTy: 525 return C.VoidPtrTy; 526 } 527 528 // FIXME: Should be unreachable, but Clang is currently emitting 529 // a warning. 530 return QualType(); 531} 532 533//===----------------------------------------------------------------------===// 534// Methods on OptionalAmount. 535//===----------------------------------------------------------------------===// 536 537ArgTypeResult OptionalAmount::getArgType(ASTContext &Ctx) const { 538 return Ctx.IntTy; 539} 540 541//===----------------------------------------------------------------------===// 542// Methods on ConversionSpecifier. 543//===----------------------------------------------------------------------===// 544const char *ConversionSpecifier::toString() const { 545 switch (kind) { 546 case dArg: return "d"; 547 case iArg: return "i"; 548 case oArg: return "o"; 549 case uArg: return "u"; 550 case xArg: return "x"; 551 case XArg: return "X"; 552 case fArg: return "f"; 553 case FArg: return "F"; 554 case eArg: return "e"; 555 case EArg: return "E"; 556 case gArg: return "g"; 557 case GArg: return "G"; 558 case aArg: return "a"; 559 case AArg: return "A"; 560 case IntAsCharArg: return "c"; 561 case CStrArg: return "s"; 562 case VoidPtrArg: return "p"; 563 case OutIntPtrArg: return "n"; 564 case PercentArg: return "%"; 565 case InvalidSpecifier: return NULL; 566 567 // MacOS X unicode extensions. 568 case CArg: return "C"; 569 case UnicodeStrArg: return "S"; 570 571 // Objective-C specific specifiers. 572 case ObjCObjArg: return "@"; 573 574 // GlibC specific specifiers. 575 case PrintErrno: return "m"; 576 } 577 return NULL; 578} 579 580//===----------------------------------------------------------------------===// 581// Methods on LengthModifier. 582//===----------------------------------------------------------------------===// 583 584const char *LengthModifier::toString() const { 585 switch (kind) { 586 case AsChar: 587 return "hh"; 588 case AsShort: 589 return "h"; 590 case AsLong: // or AsWideChar 591 return "l"; 592 case AsLongLong: 593 return "ll"; 594 case AsIntMax: 595 return "j"; 596 case AsSizeT: 597 return "z"; 598 case AsPtrDiff: 599 return "t"; 600 case AsLongDouble: 601 return "L"; 602 case None: 603 return ""; 604 } 605 return NULL; 606} 607 608//===----------------------------------------------------------------------===// 609// Methods on OptionalAmount. 610//===----------------------------------------------------------------------===// 611 612void OptionalAmount::toString(llvm::raw_ostream &os) const { 613 switch (hs) { 614 case Invalid: 615 case NotSpecified: 616 return; 617 case Arg: 618 if (usesPositionalArg()) 619 os << ".*" << getPositionalArgIndex() << "$"; 620 else 621 os << ".*"; 622 break; 623 case Constant: 624 os << "." << amt; 625 break; 626 } 627} 628 629//===----------------------------------------------------------------------===// 630// Methods on FormatSpecifier. 631//===----------------------------------------------------------------------===// 632 633ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const { 634 if (!CS.consumesDataArgument()) 635 return ArgTypeResult::Invalid(); 636 637 if (CS.isIntArg()) 638 switch (LM.getKind()) { 639 case LengthModifier::AsLongDouble: 640 return ArgTypeResult::Invalid(); 641 case LengthModifier::None: return Ctx.IntTy; 642 case LengthModifier::AsChar: return Ctx.SignedCharTy; 643 case LengthModifier::AsShort: return Ctx.ShortTy; 644 case LengthModifier::AsLong: return Ctx.LongTy; 645 case LengthModifier::AsLongLong: return Ctx.LongLongTy; 646 case LengthModifier::AsIntMax: 647 // FIXME: Return unknown for now. 648 return ArgTypeResult(); 649 case LengthModifier::AsSizeT: return Ctx.getSizeType(); 650 case LengthModifier::AsPtrDiff: return Ctx.getPointerDiffType(); 651 } 652 653 if (CS.isUIntArg()) 654 switch (LM.getKind()) { 655 case LengthModifier::AsLongDouble: 656 return ArgTypeResult::Invalid(); 657 case LengthModifier::None: return Ctx.UnsignedIntTy; 658 case LengthModifier::AsChar: return Ctx.UnsignedCharTy; 659 case LengthModifier::AsShort: return Ctx.UnsignedShortTy; 660 case LengthModifier::AsLong: return Ctx.UnsignedLongTy; 661 case LengthModifier::AsLongLong: return Ctx.UnsignedLongLongTy; 662 case LengthModifier::AsIntMax: 663 // FIXME: Return unknown for now. 664 return ArgTypeResult(); 665 case LengthModifier::AsSizeT: 666 // FIXME: How to get the corresponding unsigned 667 // version of size_t? 668 return ArgTypeResult(); 669 case LengthModifier::AsPtrDiff: 670 // FIXME: How to get the corresponding unsigned 671 // version of ptrdiff_t? 672 return ArgTypeResult(); 673 } 674 675 if (CS.isDoubleArg()) { 676 if (LM.getKind() == LengthModifier::AsLongDouble) 677 return Ctx.LongDoubleTy; 678 return Ctx.DoubleTy; 679 } 680 681 switch (CS.getKind()) { 682 case ConversionSpecifier::CStrArg: 683 return ArgTypeResult(LM.getKind() == LengthModifier::AsWideChar ? 684 ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy); 685 case ConversionSpecifier::UnicodeStrArg: 686 // FIXME: This appears to be Mac OS X specific. 687 return ArgTypeResult::WCStrTy; 688 case ConversionSpecifier::CArg: 689 return Ctx.WCharTy; 690 case ConversionSpecifier::VoidPtrArg: 691 return ArgTypeResult::CPointerTy; 692 default: 693 break; 694 } 695 696 // FIXME: Handle other cases. 697 return ArgTypeResult(); 698} 699 700bool FormatSpecifier::fixType(QualType QT) { 701 // Handle strings first (char *, wchar_t *) 702 if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { 703 CS.setKind(ConversionSpecifier::CStrArg); 704 705 // Disable irrelevant flags 706 HasAlternativeForm = 0; 707 HasLeadingZeroes = 0; 708 709 // Set the long length modifier for wide characters 710 if (QT->getPointeeType()->isWideCharType()) 711 LM.setKind(LengthModifier::AsWideChar); 712 713 return true; 714 } 715 716 // We can only work with builtin types. 717 if (!QT->isBuiltinType()) 718 return false; 719 720 // Everything else should be a base type 721 const BuiltinType *BT = QT->getAs<BuiltinType>(); 722 723 // Set length modifier 724 switch (BT->getKind()) { 725 default: 726 // The rest of the conversions are either optional or for non-builtin types 727 LM.setKind(LengthModifier::None); 728 break; 729 730 case BuiltinType::WChar: 731 case BuiltinType::Long: 732 case BuiltinType::ULong: 733 LM.setKind(LengthModifier::AsLong); 734 break; 735 736 case BuiltinType::LongLong: 737 case BuiltinType::ULongLong: 738 LM.setKind(LengthModifier::AsLongLong); 739 break; 740 741 case BuiltinType::LongDouble: 742 LM.setKind(LengthModifier::AsLongDouble); 743 break; 744 } 745 746 // Set conversion specifier and disable any flags which do not apply to it. 747 if (QT->isAnyCharacterType()) { 748 CS.setKind(ConversionSpecifier::IntAsCharArg); 749 Precision.setHowSpecified(OptionalAmount::NotSpecified); 750 HasAlternativeForm = 0; 751 HasLeadingZeroes = 0; 752 } 753 // Test for Floating type first as LongDouble can pass isUnsignedIntegerType 754 else if (QT->isFloatingType()) { 755 CS.setKind(ConversionSpecifier::fArg); 756 } 757 else if (QT->isPointerType()) { 758 CS.setKind(ConversionSpecifier::VoidPtrArg); 759 Precision.setHowSpecified(OptionalAmount::NotSpecified); 760 HasAlternativeForm = 0; 761 HasLeadingZeroes = 0; 762 } 763 else if (QT->isSignedIntegerType()) { 764 CS.setKind(ConversionSpecifier::dArg); 765 HasAlternativeForm = 0; 766 } 767 else if (QT->isUnsignedIntegerType()) { 768 CS.setKind(ConversionSpecifier::uArg); 769 HasAlternativeForm = 0; 770 } 771 else { 772 return false; 773 } 774 775 return true; 776} 777 778void FormatSpecifier::toString(llvm::raw_ostream &os) const { 779 // Whilst some features have no defined order, we are using the order 780 // appearing in the C99 standard (ISO/IEC 9899:1999 (E) �7.19.6.1) 781 os << "%"; 782 783 // Positional args 784 if (usesPositionalArg()) { 785 os << getPositionalArgIndex() << "$"; 786 } 787 788 // Conversion flags 789 if (IsLeftJustified) os << "-"; 790 if (HasPlusPrefix) os << "+"; 791 if (HasSpacePrefix) os << " "; 792 if (HasAlternativeForm) os << "#"; 793 if (HasLeadingZeroes) os << "0"; 794 795 // Minimum field width 796 FieldWidth.toString(os); 797 // Precision 798 Precision.toString(os); 799 // Length modifier 800 os << LM.toString(); 801 // Conversion specifier 802 os << CS.toString(); 803} 804