1 //== PrintfFormatString.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/FormatString.h" 16 #include "FormatStringParsing.h" 17 18 using clang::analyze_format_string::ArgType; 19 using clang::analyze_format_string::FormatStringHandler; 20 using clang::analyze_format_string::LengthModifier; 21 using clang::analyze_format_string::OptionalAmount; 22 using clang::analyze_format_string::ConversionSpecifier; 23 using clang::analyze_printf::PrintfSpecifier; 24 25 using namespace clang; 26 27 typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier> 28 PrintfSpecifierResult; 29 30 //===----------------------------------------------------------------------===// 31 // Methods for parsing format strings. 32 //===----------------------------------------------------------------------===// 33 34 using analyze_format_string::ParseNonPositionAmount; 35 36 static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, 37 const char *Start, const char *&Beg, const char *E, 38 unsigned *argIndex) { 39 if (argIndex) { 40 FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex)); 41 } else { 42 const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, 43 analyze_format_string::PrecisionPos); 44 if (Amt.isInvalid()) 45 return true; 46 FS.setPrecision(Amt); 47 } 48 return false; 49 } 50 51 static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, 52 const char *&Beg, 53 const char *E, 54 unsigned &argIndex, 55 const LangOptions &LO) { 56 57 using namespace clang::analyze_format_string; 58 using namespace clang::analyze_printf; 59 60 const char *I = Beg; 61 const char *Start = 0; 62 UpdateOnReturn <const char*> UpdateBeg(Beg, I); 63 64 // Look for a '%' character that indicates the start of a format specifier. 65 for ( ; I != E ; ++I) { 66 char c = *I; 67 if (c == '\0') { 68 // Detect spurious null characters, which are likely errors. 69 H.HandleNullChar(I); 70 return true; 71 } 72 if (c == '%') { 73 Start = I++; // Record the start of the format specifier. 74 break; 75 } 76 } 77 78 // No format specifier found? 79 if (!Start) 80 return false; 81 82 if (I == E) { 83 // No more characters left? 84 H.HandleIncompleteSpecifier(Start, E - Start); 85 return true; 86 } 87 88 PrintfSpecifier FS; 89 if (ParseArgPosition(H, FS, Start, I, E)) 90 return true; 91 92 if (I == E) { 93 // No more characters left? 94 H.HandleIncompleteSpecifier(Start, E - Start); 95 return true; 96 } 97 98 // Look for flags (if any). 99 bool hasMore = true; 100 for ( ; I != E; ++I) { 101 switch (*I) { 102 default: hasMore = false; break; 103 case '\'': 104 // FIXME: POSIX specific. Always accept? 105 FS.setHasThousandsGrouping(I); 106 break; 107 case '-': FS.setIsLeftJustified(I); break; 108 case '+': FS.setHasPlusPrefix(I); break; 109 case ' ': FS.setHasSpacePrefix(I); break; 110 case '#': FS.setHasAlternativeForm(I); break; 111 case '0': FS.setHasLeadingZeros(I); break; 112 } 113 if (!hasMore) 114 break; 115 } 116 117 if (I == E) { 118 // No more characters left? 119 H.HandleIncompleteSpecifier(Start, E - Start); 120 return true; 121 } 122 123 // Look for the field width (if any). 124 if (ParseFieldWidth(H, FS, Start, I, E, 125 FS.usesPositionalArg() ? 0 : &argIndex)) 126 return true; 127 128 if (I == E) { 129 // No more characters left? 130 H.HandleIncompleteSpecifier(Start, E - Start); 131 return true; 132 } 133 134 // Look for the precision (if any). 135 if (*I == '.') { 136 ++I; 137 if (I == E) { 138 H.HandleIncompleteSpecifier(Start, E - Start); 139 return true; 140 } 141 142 if (ParsePrecision(H, FS, Start, I, E, 143 FS.usesPositionalArg() ? 0 : &argIndex)) 144 return true; 145 146 if (I == E) { 147 // No more characters left? 148 H.HandleIncompleteSpecifier(Start, E - Start); 149 return true; 150 } 151 } 152 153 // Look for the length modifier. 154 if (ParseLengthModifier(FS, I, E, LO) && I == E) { 155 // No more characters left? 156 H.HandleIncompleteSpecifier(Start, E - Start); 157 return true; 158 } 159 160 if (*I == '\0') { 161 // Detect spurious null characters, which are likely errors. 162 H.HandleNullChar(I); 163 return true; 164 } 165 166 // Finally, look for the conversion specifier. 167 const char *conversionPosition = I++; 168 ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; 169 switch (*conversionPosition) { 170 default: 171 break; 172 // C99: 7.19.6.1 (section 8). 173 case '%': k = ConversionSpecifier::PercentArg; break; 174 case 'A': k = ConversionSpecifier::AArg; break; 175 case 'E': k = ConversionSpecifier::EArg; break; 176 case 'F': k = ConversionSpecifier::FArg; break; 177 case 'G': k = ConversionSpecifier::GArg; break; 178 case 'X': k = ConversionSpecifier::XArg; break; 179 case 'a': k = ConversionSpecifier::aArg; break; 180 case 'c': k = ConversionSpecifier::cArg; break; 181 case 'd': k = ConversionSpecifier::dArg; break; 182 case 'e': k = ConversionSpecifier::eArg; break; 183 case 'f': k = ConversionSpecifier::fArg; break; 184 case 'g': k = ConversionSpecifier::gArg; break; 185 case 'i': k = ConversionSpecifier::iArg; break; 186 case 'n': k = ConversionSpecifier::nArg; break; 187 case 'o': k = ConversionSpecifier::oArg; break; 188 case 'p': k = ConversionSpecifier::pArg; break; 189 case 's': k = ConversionSpecifier::sArg; break; 190 case 'u': k = ConversionSpecifier::uArg; break; 191 case 'x': k = ConversionSpecifier::xArg; break; 192 // POSIX specific. 193 case 'C': k = ConversionSpecifier::CArg; break; 194 case 'S': k = ConversionSpecifier::SArg; break; 195 // Objective-C. 196 case '@': k = ConversionSpecifier::ObjCObjArg; break; 197 // Glibc specific. 198 case 'm': k = ConversionSpecifier::PrintErrno; break; 199 } 200 PrintfConversionSpecifier CS(conversionPosition, k); 201 FS.setConversionSpecifier(CS); 202 if (CS.consumesDataArgument() && !FS.usesPositionalArg()) 203 FS.setArgIndex(argIndex++); 204 205 if (k == ConversionSpecifier::InvalidSpecifier) { 206 // Assume the conversion takes one argument. 207 return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, I - Start); 208 } 209 return PrintfSpecifierResult(Start, FS); 210 } 211 212 bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, 213 const char *I, 214 const char *E, 215 const LangOptions &LO) { 216 217 unsigned argIndex = 0; 218 219 // Keep looking for a format specifier until we have exhausted the string. 220 while (I != E) { 221 const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, 222 LO); 223 // Did a fail-stop error of any kind occur when parsing the specifier? 224 // If so, don't do any more processing. 225 if (FSR.shouldStop()) 226 return true; 227 // Did we exhaust the string or encounter an error that 228 // we can recover from? 229 if (!FSR.hasValue()) 230 continue; 231 // We have a format specifier. Pass it to the callback. 232 if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(), 233 I - FSR.getStart())) 234 return true; 235 } 236 assert(I == E && "Format string not exhausted"); 237 return false; 238 } 239 240 //===----------------------------------------------------------------------===// 241 // Methods on PrintfSpecifier. 242 //===----------------------------------------------------------------------===// 243 244 ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, 245 bool IsObjCLiteral) const { 246 const PrintfConversionSpecifier &CS = getConversionSpecifier(); 247 248 if (!CS.consumesDataArgument()) 249 return ArgType::Invalid(); 250 251 if (CS.getKind() == ConversionSpecifier::cArg) 252 switch (LM.getKind()) { 253 case LengthModifier::None: return Ctx.IntTy; 254 case LengthModifier::AsLong: 255 return ArgType(ArgType::WIntTy, "wint_t"); 256 default: 257 return ArgType::Invalid(); 258 } 259 260 if (CS.isIntArg()) 261 switch (LM.getKind()) { 262 case LengthModifier::AsLongDouble: 263 // GNU extension. 264 return Ctx.LongLongTy; 265 case LengthModifier::None: return Ctx.IntTy; 266 case LengthModifier::AsChar: return ArgType::AnyCharTy; 267 case LengthModifier::AsShort: return Ctx.ShortTy; 268 case LengthModifier::AsLong: return Ctx.LongTy; 269 case LengthModifier::AsLongLong: 270 case LengthModifier::AsQuad: 271 return Ctx.LongLongTy; 272 case LengthModifier::AsIntMax: 273 return ArgType(Ctx.getIntMaxType(), "intmax_t"); 274 case LengthModifier::AsSizeT: 275 // FIXME: How to get the corresponding signed version of size_t? 276 return ArgType(); 277 case LengthModifier::AsPtrDiff: 278 return ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"); 279 case LengthModifier::AsAllocate: 280 case LengthModifier::AsMAllocate: 281 return ArgType::Invalid(); 282 } 283 284 if (CS.isUIntArg()) 285 switch (LM.getKind()) { 286 case LengthModifier::AsLongDouble: 287 // GNU extension. 288 return Ctx.UnsignedLongLongTy; 289 case LengthModifier::None: return Ctx.UnsignedIntTy; 290 case LengthModifier::AsChar: return Ctx.UnsignedCharTy; 291 case LengthModifier::AsShort: return Ctx.UnsignedShortTy; 292 case LengthModifier::AsLong: return Ctx.UnsignedLongTy; 293 case LengthModifier::AsLongLong: 294 case LengthModifier::AsQuad: 295 return Ctx.UnsignedLongLongTy; 296 case LengthModifier::AsIntMax: 297 return ArgType(Ctx.getUIntMaxType(), "uintmax_t"); 298 case LengthModifier::AsSizeT: 299 return ArgType(Ctx.getSizeType(), "size_t"); 300 case LengthModifier::AsPtrDiff: 301 // FIXME: How to get the corresponding unsigned 302 // version of ptrdiff_t? 303 return ArgType(); 304 case LengthModifier::AsAllocate: 305 case LengthModifier::AsMAllocate: 306 return ArgType::Invalid(); 307 } 308 309 if (CS.isDoubleArg()) { 310 if (LM.getKind() == LengthModifier::AsLongDouble) 311 return Ctx.LongDoubleTy; 312 return Ctx.DoubleTy; 313 } 314 315 if (CS.getKind() == ConversionSpecifier::nArg) { 316 switch (LM.getKind()) { 317 case LengthModifier::None: 318 return ArgType::PtrTo(Ctx.IntTy); 319 case LengthModifier::AsChar: 320 return ArgType::PtrTo(Ctx.SignedCharTy); 321 case LengthModifier::AsShort: 322 return ArgType::PtrTo(Ctx.ShortTy); 323 case LengthModifier::AsLong: 324 return ArgType::PtrTo(Ctx.LongTy); 325 case LengthModifier::AsLongLong: 326 case LengthModifier::AsQuad: 327 return ArgType::PtrTo(Ctx.LongLongTy); 328 case LengthModifier::AsIntMax: 329 return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); 330 case LengthModifier::AsSizeT: 331 return ArgType(); // FIXME: ssize_t 332 case LengthModifier::AsPtrDiff: 333 return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); 334 case LengthModifier::AsLongDouble: 335 return ArgType(); // FIXME: Is this a known extension? 336 case LengthModifier::AsAllocate: 337 case LengthModifier::AsMAllocate: 338 return ArgType::Invalid(); 339 } 340 } 341 342 switch (CS.getKind()) { 343 case ConversionSpecifier::sArg: 344 if (LM.getKind() == LengthModifier::AsWideChar) { 345 if (IsObjCLiteral) 346 return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()); 347 return ArgType(ArgType::WCStrTy, "wchar_t *"); 348 } 349 return ArgType::CStrTy; 350 case ConversionSpecifier::SArg: 351 if (IsObjCLiteral) 352 return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()); 353 return ArgType(ArgType::WCStrTy, "wchar_t *"); 354 case ConversionSpecifier::CArg: 355 if (IsObjCLiteral) 356 return Ctx.UnsignedShortTy; 357 return ArgType(Ctx.WCharTy, "wchar_t"); 358 case ConversionSpecifier::pArg: 359 return ArgType::CPointerTy; 360 case ConversionSpecifier::ObjCObjArg: 361 return ArgType::ObjCPointerTy; 362 default: 363 break; 364 } 365 366 // FIXME: Handle other cases. 367 return ArgType(); 368 } 369 370 bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, 371 ASTContext &Ctx, bool IsObjCLiteral) { 372 // %n is different from other conversion specifiers; don't try to fix it. 373 if (CS.getKind() == ConversionSpecifier::nArg) 374 return false; 375 376 // Handle Objective-C objects first. Note that while the '%@' specifier will 377 // not warn for structure pointer or void pointer arguments (because that's 378 // how CoreFoundation objects are implemented), we only show a fixit for '%@' 379 // if we know it's an object (block, id, class, or __attribute__((NSObject))). 380 if (QT->isObjCRetainableType()) { 381 if (!IsObjCLiteral) 382 return false; 383 384 CS.setKind(ConversionSpecifier::ObjCObjArg); 385 386 // Disable irrelevant flags 387 HasThousandsGrouping = false; 388 HasPlusPrefix = false; 389 HasSpacePrefix = false; 390 HasAlternativeForm = false; 391 HasLeadingZeroes = false; 392 Precision.setHowSpecified(OptionalAmount::NotSpecified); 393 LM.setKind(LengthModifier::None); 394 395 return true; 396 } 397 398 // Handle strings next (char *, wchar_t *) 399 if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { 400 CS.setKind(ConversionSpecifier::sArg); 401 402 // Disable irrelevant flags 403 HasAlternativeForm = 0; 404 HasLeadingZeroes = 0; 405 406 // Set the long length modifier for wide characters 407 if (QT->getPointeeType()->isWideCharType()) 408 LM.setKind(LengthModifier::AsWideChar); 409 else 410 LM.setKind(LengthModifier::None); 411 412 return true; 413 } 414 415 // If it's an enum, get its underlying type. 416 if (const EnumType *ETy = QT->getAs<EnumType>()) 417 QT = ETy->getDecl()->getIntegerType(); 418 419 // We can only work with builtin types. 420 const BuiltinType *BT = QT->getAs<BuiltinType>(); 421 if (!BT) 422 return false; 423 424 // Set length modifier 425 switch (BT->getKind()) { 426 case BuiltinType::Bool: 427 case BuiltinType::WChar_U: 428 case BuiltinType::WChar_S: 429 case BuiltinType::Char16: 430 case BuiltinType::Char32: 431 case BuiltinType::UInt128: 432 case BuiltinType::Int128: 433 case BuiltinType::Half: 434 // Various types which are non-trivial to correct. 435 return false; 436 437 #define SIGNED_TYPE(Id, SingletonId) 438 #define UNSIGNED_TYPE(Id, SingletonId) 439 #define FLOATING_TYPE(Id, SingletonId) 440 #define BUILTIN_TYPE(Id, SingletonId) \ 441 case BuiltinType::Id: 442 #include "clang/AST/BuiltinTypes.def" 443 // Misc other stuff which doesn't make sense here. 444 return false; 445 446 case BuiltinType::UInt: 447 case BuiltinType::Int: 448 case BuiltinType::Float: 449 case BuiltinType::Double: 450 LM.setKind(LengthModifier::None); 451 break; 452 453 case BuiltinType::Char_U: 454 case BuiltinType::UChar: 455 case BuiltinType::Char_S: 456 case BuiltinType::SChar: 457 LM.setKind(LengthModifier::AsChar); 458 break; 459 460 case BuiltinType::Short: 461 case BuiltinType::UShort: 462 LM.setKind(LengthModifier::AsShort); 463 break; 464 465 case BuiltinType::Long: 466 case BuiltinType::ULong: 467 LM.setKind(LengthModifier::AsLong); 468 break; 469 470 case BuiltinType::LongLong: 471 case BuiltinType::ULongLong: 472 LM.setKind(LengthModifier::AsLongLong); 473 break; 474 475 case BuiltinType::LongDouble: 476 LM.setKind(LengthModifier::AsLongDouble); 477 break; 478 } 479 480 // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. 481 if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus0x)) 482 namedTypeToLengthModifier(QT, LM); 483 484 // If fixing the length modifier was enough, we are done. 485 if (hasValidLengthModifier(Ctx.getTargetInfo())) { 486 const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral); 487 if (ATR.isValid() && ATR.matchesType(Ctx, QT)) 488 return true; 489 } 490 491 // Set conversion specifier and disable any flags which do not apply to it. 492 // Let typedefs to char fall through to int, as %c is silly for uint8_t. 493 if (isa<TypedefType>(QT) && QT->isAnyCharacterType()) { 494 CS.setKind(ConversionSpecifier::cArg); 495 LM.setKind(LengthModifier::None); 496 Precision.setHowSpecified(OptionalAmount::NotSpecified); 497 HasAlternativeForm = 0; 498 HasLeadingZeroes = 0; 499 HasPlusPrefix = 0; 500 } 501 // Test for Floating type first as LongDouble can pass isUnsignedIntegerType 502 else if (QT->isRealFloatingType()) { 503 CS.setKind(ConversionSpecifier::fArg); 504 } 505 else if (QT->isSignedIntegerType()) { 506 CS.setKind(ConversionSpecifier::dArg); 507 HasAlternativeForm = 0; 508 } 509 else if (QT->isUnsignedIntegerType()) { 510 CS.setKind(ConversionSpecifier::uArg); 511 HasAlternativeForm = 0; 512 HasPlusPrefix = 0; 513 } else { 514 llvm_unreachable("Unexpected type"); 515 } 516 517 return true; 518 } 519 520 void PrintfSpecifier::toString(raw_ostream &os) const { 521 // Whilst some features have no defined order, we are using the order 522 // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1) 523 os << "%"; 524 525 // Positional args 526 if (usesPositionalArg()) { 527 os << getPositionalArgIndex() << "$"; 528 } 529 530 // Conversion flags 531 if (IsLeftJustified) os << "-"; 532 if (HasPlusPrefix) os << "+"; 533 if (HasSpacePrefix) os << " "; 534 if (HasAlternativeForm) os << "#"; 535 if (HasLeadingZeroes) os << "0"; 536 537 // Minimum field width 538 FieldWidth.toString(os); 539 // Precision 540 Precision.toString(os); 541 // Length modifier 542 os << LM.toString(); 543 // Conversion specifier 544 os << CS.toString(); 545 } 546 547 bool PrintfSpecifier::hasValidPlusPrefix() const { 548 if (!HasPlusPrefix) 549 return true; 550 551 // The plus prefix only makes sense for signed conversions 552 switch (CS.getKind()) { 553 case ConversionSpecifier::dArg: 554 case ConversionSpecifier::iArg: 555 case ConversionSpecifier::fArg: 556 case ConversionSpecifier::FArg: 557 case ConversionSpecifier::eArg: 558 case ConversionSpecifier::EArg: 559 case ConversionSpecifier::gArg: 560 case ConversionSpecifier::GArg: 561 case ConversionSpecifier::aArg: 562 case ConversionSpecifier::AArg: 563 return true; 564 565 default: 566 return false; 567 } 568 } 569 570 bool PrintfSpecifier::hasValidAlternativeForm() const { 571 if (!HasAlternativeForm) 572 return true; 573 574 // Alternate form flag only valid with the oxXaAeEfFgG conversions 575 switch (CS.getKind()) { 576 case ConversionSpecifier::oArg: 577 case ConversionSpecifier::xArg: 578 case ConversionSpecifier::XArg: 579 case ConversionSpecifier::aArg: 580 case ConversionSpecifier::AArg: 581 case ConversionSpecifier::eArg: 582 case ConversionSpecifier::EArg: 583 case ConversionSpecifier::fArg: 584 case ConversionSpecifier::FArg: 585 case ConversionSpecifier::gArg: 586 case ConversionSpecifier::GArg: 587 return true; 588 589 default: 590 return false; 591 } 592 } 593 594 bool PrintfSpecifier::hasValidLeadingZeros() const { 595 if (!HasLeadingZeroes) 596 return true; 597 598 // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions 599 switch (CS.getKind()) { 600 case ConversionSpecifier::dArg: 601 case ConversionSpecifier::iArg: 602 case ConversionSpecifier::oArg: 603 case ConversionSpecifier::uArg: 604 case ConversionSpecifier::xArg: 605 case ConversionSpecifier::XArg: 606 case ConversionSpecifier::aArg: 607 case ConversionSpecifier::AArg: 608 case ConversionSpecifier::eArg: 609 case ConversionSpecifier::EArg: 610 case ConversionSpecifier::fArg: 611 case ConversionSpecifier::FArg: 612 case ConversionSpecifier::gArg: 613 case ConversionSpecifier::GArg: 614 return true; 615 616 default: 617 return false; 618 } 619 } 620 621 bool PrintfSpecifier::hasValidSpacePrefix() const { 622 if (!HasSpacePrefix) 623 return true; 624 625 // The space prefix only makes sense for signed conversions 626 switch (CS.getKind()) { 627 case ConversionSpecifier::dArg: 628 case ConversionSpecifier::iArg: 629 case ConversionSpecifier::fArg: 630 case ConversionSpecifier::FArg: 631 case ConversionSpecifier::eArg: 632 case ConversionSpecifier::EArg: 633 case ConversionSpecifier::gArg: 634 case ConversionSpecifier::GArg: 635 case ConversionSpecifier::aArg: 636 case ConversionSpecifier::AArg: 637 return true; 638 639 default: 640 return false; 641 } 642 } 643 644 bool PrintfSpecifier::hasValidLeftJustified() const { 645 if (!IsLeftJustified) 646 return true; 647 648 // The left justified flag is valid for all conversions except n 649 switch (CS.getKind()) { 650 case ConversionSpecifier::nArg: 651 return false; 652 653 default: 654 return true; 655 } 656 } 657 658 bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const { 659 if (!HasThousandsGrouping) 660 return true; 661 662 switch (CS.getKind()) { 663 case ConversionSpecifier::dArg: 664 case ConversionSpecifier::iArg: 665 case ConversionSpecifier::uArg: 666 case ConversionSpecifier::fArg: 667 case ConversionSpecifier::FArg: 668 case ConversionSpecifier::gArg: 669 case ConversionSpecifier::GArg: 670 return true; 671 default: 672 return false; 673 } 674 } 675 676 bool PrintfSpecifier::hasValidPrecision() const { 677 if (Precision.getHowSpecified() == OptionalAmount::NotSpecified) 678 return true; 679 680 // Precision is only valid with the diouxXaAeEfFgGs conversions 681 switch (CS.getKind()) { 682 case ConversionSpecifier::dArg: 683 case ConversionSpecifier::iArg: 684 case ConversionSpecifier::oArg: 685 case ConversionSpecifier::uArg: 686 case ConversionSpecifier::xArg: 687 case ConversionSpecifier::XArg: 688 case ConversionSpecifier::aArg: 689 case ConversionSpecifier::AArg: 690 case ConversionSpecifier::eArg: 691 case ConversionSpecifier::EArg: 692 case ConversionSpecifier::fArg: 693 case ConversionSpecifier::FArg: 694 case ConversionSpecifier::gArg: 695 case ConversionSpecifier::GArg: 696 case ConversionSpecifier::sArg: 697 return true; 698 699 default: 700 return false; 701 } 702 } 703 bool PrintfSpecifier::hasValidFieldWidth() const { 704 if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified) 705 return true; 706 707 // The field width is valid for all conversions except n 708 switch (CS.getKind()) { 709 case ConversionSpecifier::nArg: 710 return false; 711 712 default: 713 return true; 714 } 715 } 716