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