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