PrintfFormatString.cpp revision 234353
1212904Sdim//== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==// 2203955Srdivacky// 3203955Srdivacky// The LLVM Compiler Infrastructure 4203955Srdivacky// 5203955Srdivacky// This file is distributed under the University of Illinois Open Source 6203955Srdivacky// License. See LICENSE.TXT for details. 7203955Srdivacky// 8203955Srdivacky//===----------------------------------------------------------------------===// 9203955Srdivacky// 10203955Srdivacky// Handling of format string in printf and friends. The structure of format 11203955Srdivacky// strings for fprintf() are described in C99 7.19.6.1. 12203955Srdivacky// 13203955Srdivacky//===----------------------------------------------------------------------===// 14203955Srdivacky 15212904Sdim#include "clang/Analysis/Analyses/FormatString.h" 16212904Sdim#include "FormatStringParsing.h" 17203955Srdivacky 18212904Sdimusing clang::analyze_format_string::ArgTypeResult; 19212904Sdimusing clang::analyze_format_string::FormatStringHandler; 20212904Sdimusing clang::analyze_format_string::LengthModifier; 21212904Sdimusing clang::analyze_format_string::OptionalAmount; 22212904Sdimusing clang::analyze_format_string::ConversionSpecifier; 23212904Sdimusing clang::analyze_printf::PrintfSpecifier; 24204643Srdivacky 25203955Srdivackyusing namespace clang; 26203955Srdivacky 27212904Sdimtypedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier> 28212904Sdim PrintfSpecifierResult; 29203955Srdivacky 30203955Srdivacky//===----------------------------------------------------------------------===// 31203955Srdivacky// Methods for parsing format strings. 32203955Srdivacky//===----------------------------------------------------------------------===// 33203955Srdivacky 34212904Sdimusing analyze_format_string::ParseNonPositionAmount; 35203955Srdivacky 36212904Sdimstatic bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, 37204643Srdivacky const char *Start, const char *&Beg, const char *E, 38204643Srdivacky unsigned *argIndex) { 39204643Srdivacky if (argIndex) { 40204643Srdivacky FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex)); 41226633Sdim } else { 42204643Srdivacky const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, 43212904Sdim analyze_format_string::PrecisionPos); 44204643Srdivacky if (Amt.isInvalid()) 45204643Srdivacky return true; 46204643Srdivacky FS.setPrecision(Amt); 47204643Srdivacky } 48204643Srdivacky return false; 49204643Srdivacky} 50204643Srdivacky 51212904Sdimstatic PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, 52203955Srdivacky const char *&Beg, 53204643Srdivacky const char *E, 54208987Srdivacky unsigned &argIndex, 55212904Sdim const LangOptions &LO) { 56203955Srdivacky 57212904Sdim using namespace clang::analyze_format_string; 58203955Srdivacky using namespace clang::analyze_printf; 59203955Srdivacky 60203955Srdivacky const char *I = Beg; 61203955Srdivacky const char *Start = 0; 62203955Srdivacky UpdateOnReturn <const char*> UpdateBeg(Beg, I); 63203955Srdivacky 64203955Srdivacky // Look for a '%' character that indicates the start of a format specifier. 65203955Srdivacky for ( ; I != E ; ++I) { 66203955Srdivacky char c = *I; 67203955Srdivacky if (c == '\0') { 68203955Srdivacky // Detect spurious null characters, which are likely errors. 69203955Srdivacky H.HandleNullChar(I); 70203955Srdivacky return true; 71203955Srdivacky } 72203955Srdivacky if (c == '%') { 73203955Srdivacky Start = I++; // Record the start of the format specifier. 74203955Srdivacky break; 75203955Srdivacky } 76203955Srdivacky } 77203955Srdivacky 78203955Srdivacky // No format specifier found? 79203955Srdivacky if (!Start) 80203955Srdivacky return false; 81203955Srdivacky 82203955Srdivacky if (I == E) { 83203955Srdivacky // No more characters left? 84212904Sdim H.HandleIncompleteSpecifier(Start, E - Start); 85203955Srdivacky return true; 86203955Srdivacky } 87203955Srdivacky 88212904Sdim PrintfSpecifier FS; 89204643Srdivacky if (ParseArgPosition(H, FS, Start, I, E)) 90204643Srdivacky return true; 91203955Srdivacky 92204643Srdivacky if (I == E) { 93204643Srdivacky // No more characters left? 94212904Sdim H.HandleIncompleteSpecifier(Start, E - Start); 95204643Srdivacky return true; 96204643Srdivacky } 97204643Srdivacky 98203955Srdivacky // Look for flags (if any). 99203955Srdivacky bool hasMore = true; 100203955Srdivacky for ( ; I != E; ++I) { 101203955Srdivacky switch (*I) { 102203955Srdivacky default: hasMore = false; break; 103218893Sdim case '\'': 104218893Sdim // FIXME: POSIX specific. Always accept? 105218893Sdim FS.setHasThousandsGrouping(I); 106218893Sdim break; 107210299Sed case '-': FS.setIsLeftJustified(I); break; 108210299Sed case '+': FS.setHasPlusPrefix(I); break; 109210299Sed case ' ': FS.setHasSpacePrefix(I); break; 110210299Sed case '#': FS.setHasAlternativeForm(I); break; 111210299Sed case '0': FS.setHasLeadingZeros(I); break; 112203955Srdivacky } 113203955Srdivacky if (!hasMore) 114203955Srdivacky break; 115203955Srdivacky } 116203955Srdivacky 117203955Srdivacky if (I == E) { 118203955Srdivacky // No more characters left? 119212904Sdim H.HandleIncompleteSpecifier(Start, E - Start); 120203955Srdivacky return true; 121203955Srdivacky } 122203955Srdivacky 123203955Srdivacky // Look for the field width (if any). 124204643Srdivacky if (ParseFieldWidth(H, FS, Start, I, E, 125204643Srdivacky FS.usesPositionalArg() ? 0 : &argIndex)) 126204643Srdivacky return true; 127203955Srdivacky 128203955Srdivacky if (I == E) { 129203955Srdivacky // No more characters left? 130212904Sdim H.HandleIncompleteSpecifier(Start, E - Start); 131203955Srdivacky return true; 132203955Srdivacky } 133203955Srdivacky 134203955Srdivacky // Look for the precision (if any). 135203955Srdivacky if (*I == '.') { 136203955Srdivacky ++I; 137203955Srdivacky if (I == E) { 138212904Sdim H.HandleIncompleteSpecifier(Start, E - Start); 139203955Srdivacky return true; 140203955Srdivacky } 141203955Srdivacky 142204643Srdivacky if (ParsePrecision(H, FS, Start, I, E, 143204643Srdivacky FS.usesPositionalArg() ? 0 : &argIndex)) 144204643Srdivacky return true; 145203955Srdivacky 146203955Srdivacky if (I == E) { 147203955Srdivacky // No more characters left? 148212904Sdim H.HandleIncompleteSpecifier(Start, E - Start); 149203955Srdivacky return true; 150203955Srdivacky } 151203955Srdivacky } 152203955Srdivacky 153203955Srdivacky // Look for the length modifier. 154212904Sdim if (ParseLengthModifier(FS, I, E, LO) && I == E) { 155203955Srdivacky // No more characters left? 156212904Sdim H.HandleIncompleteSpecifier(Start, E - Start); 157203955Srdivacky return true; 158203955Srdivacky } 159203955Srdivacky 160203955Srdivacky if (*I == '\0') { 161203955Srdivacky // Detect spurious null characters, which are likely errors. 162203955Srdivacky H.HandleNullChar(I); 163203955Srdivacky return true; 164203955Srdivacky } 165203955Srdivacky 166203955Srdivacky // Finally, look for the conversion specifier. 167203955Srdivacky const char *conversionPosition = I++; 168203955Srdivacky ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; 169203955Srdivacky switch (*conversionPosition) { 170203955Srdivacky default: 171203955Srdivacky break; 172203955Srdivacky // C99: 7.19.6.1 (section 8). 173204643Srdivacky case '%': k = ConversionSpecifier::PercentArg; break; 174204643Srdivacky case 'A': k = ConversionSpecifier::AArg; break; 175204643Srdivacky case 'E': k = ConversionSpecifier::EArg; break; 176204643Srdivacky case 'F': k = ConversionSpecifier::FArg; break; 177204643Srdivacky case 'G': k = ConversionSpecifier::GArg; break; 178204643Srdivacky case 'X': k = ConversionSpecifier::XArg; break; 179204643Srdivacky case 'a': k = ConversionSpecifier::aArg; break; 180212904Sdim case 'c': k = ConversionSpecifier::cArg; break; 181203955Srdivacky case 'd': k = ConversionSpecifier::dArg; break; 182204643Srdivacky case 'e': k = ConversionSpecifier::eArg; break; 183204643Srdivacky case 'f': k = ConversionSpecifier::fArg; break; 184204643Srdivacky case 'g': k = ConversionSpecifier::gArg; break; 185203955Srdivacky case 'i': k = ConversionSpecifier::iArg; break; 186212904Sdim case 'n': k = ConversionSpecifier::nArg; break; 187203955Srdivacky case 'o': k = ConversionSpecifier::oArg; break; 188212904Sdim case 'p': k = ConversionSpecifier::pArg; break; 189212904Sdim case 's': k = ConversionSpecifier::sArg; break; 190203955Srdivacky case 'u': k = ConversionSpecifier::uArg; break; 191203955Srdivacky case 'x': k = ConversionSpecifier::xArg; break; 192218893Sdim // POSIX specific. 193204643Srdivacky case 'C': k = ConversionSpecifier::CArg; break; 194212904Sdim case 'S': k = ConversionSpecifier::SArg; break; 195203955Srdivacky // Objective-C. 196203955Srdivacky case '@': k = ConversionSpecifier::ObjCObjArg; break; 197203955Srdivacky // Glibc specific. 198203955Srdivacky case 'm': k = ConversionSpecifier::PrintErrno; break; 199208987Srdivacky // FreeBSD format extensions 200208987Srdivacky case 'b': if (LO.FormatExtensions) k = ConversionSpecifier::bArg; break; /* check for int and then char * */ 201213694Srpaulo case 'r': if (LO.FormatExtensions) k = ConversionSpecifier::rArg; break; 202213681Srpaulo case 'y': if (LO.FormatExtensions) k = ConversionSpecifier::iArg; break; 203208987Srdivacky case 'D': if (LO.FormatExtensions) k = ConversionSpecifier::DArg; break; /* check for u_char * pointer and a char * string */ 204203955Srdivacky } 205212904Sdim PrintfConversionSpecifier CS(conversionPosition, k); 206204643Srdivacky FS.setConversionSpecifier(CS); 207204643Srdivacky if (CS.consumesDataArgument() && !FS.usesPositionalArg()) 208204643Srdivacky FS.setArgIndex(argIndex++); 209208987Srdivacky // FreeBSD extension 210208987Srdivacky if (k == ConversionSpecifier::bArg || k == ConversionSpecifier::DArg) 211208987Srdivacky argIndex++; 212203955Srdivacky 213203955Srdivacky if (k == ConversionSpecifier::InvalidSpecifier) { 214204643Srdivacky // Assume the conversion takes one argument. 215218893Sdim return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, I - Start); 216203955Srdivacky } 217212904Sdim return PrintfSpecifierResult(Start, FS); 218203955Srdivacky} 219203955Srdivacky 220212904Sdimbool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, 221212904Sdim const char *I, 222212904Sdim const char *E, 223212904Sdim const LangOptions &LO) { 224204643Srdivacky 225204643Srdivacky unsigned argIndex = 0; 226204643Srdivacky 227203955Srdivacky // Keep looking for a format specifier until we have exhausted the string. 228203955Srdivacky while (I != E) { 229212904Sdim const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, 230212904Sdim LO); 231203955Srdivacky // Did a fail-stop error of any kind occur when parsing the specifier? 232203955Srdivacky // If so, don't do any more processing. 233203955Srdivacky if (FSR.shouldStop()) 234203955Srdivacky return true;; 235203955Srdivacky // Did we exhaust the string or encounter an error that 236203955Srdivacky // we can recover from? 237203955Srdivacky if (!FSR.hasValue()) 238203955Srdivacky continue; 239203955Srdivacky // We have a format specifier. Pass it to the callback. 240212904Sdim if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(), 241203955Srdivacky I - FSR.getStart())) 242203955Srdivacky return true; 243203955Srdivacky } 244203955Srdivacky assert(I == E && "Format string not exhausted"); 245203955Srdivacky return false; 246203955Srdivacky} 247203955Srdivacky 248203955Srdivacky//===----------------------------------------------------------------------===// 249210299Sed// Methods on PrintfSpecifier. 250210299Sed//===----------------------------------------------------------------------===// 251210299Sed 252210299SedArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx, 253210299Sed bool IsObjCLiteral) const { 254210299Sed const PrintfConversionSpecifier &CS = getConversionSpecifier(); 255210299Sed 256210299Sed if (!CS.consumesDataArgument()) 257210299Sed return ArgTypeResult::Invalid(); 258210299Sed 259210299Sed if (CS.getKind() == ConversionSpecifier::cArg) 260210299Sed switch (LM.getKind()) { 261210299Sed case LengthModifier::None: return Ctx.IntTy; 262210299Sed case LengthModifier::AsLong: 263210299Sed return ArgTypeResult(ArgTypeResult::WIntTy, "wint_t"); 264210299Sed default: 265210299Sed return ArgTypeResult::Invalid(); 266210299Sed } 267212904Sdim 268212904Sdim if (CS.isIntArg()) 269212904Sdim switch (LM.getKind()) { 270212904Sdim case LengthModifier::AsLongDouble: 271212904Sdim // GNU extension. 272212904Sdim return Ctx.LongLongTy; 273210299Sed case LengthModifier::None: return Ctx.IntTy; 274210299Sed case LengthModifier::AsChar: return ArgTypeResult::AnyCharTy; 275210299Sed case LengthModifier::AsShort: return Ctx.ShortTy; 276212904Sdim case LengthModifier::AsLong: return Ctx.LongTy; 277212904Sdim case LengthModifier::AsLongLong: 278210299Sed case LengthModifier::AsQuad: 279210299Sed return Ctx.LongLongTy; 280210299Sed case LengthModifier::AsIntMax: 281210299Sed return ArgTypeResult(Ctx.getIntMaxType(), "intmax_t"); 282212904Sdim case LengthModifier::AsSizeT: 283212904Sdim // FIXME: How to get the corresponding signed version of size_t? 284212904Sdim return ArgTypeResult(); 285213694Srpaulo case LengthModifier::AsPtrDiff: 286212904Sdim return ArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t"); 287210299Sed case LengthModifier::AsAllocate: 288210299Sed case LengthModifier::AsMAllocate: 289210299Sed return ArgTypeResult::Invalid(); 290210299Sed } 291210299Sed 292210299Sed if (CS.isUIntArg()) 293210299Sed switch (LM.getKind()) { 294212904Sdim case LengthModifier::AsLongDouble: 295210299Sed // GNU extension. 296210299Sed return Ctx.UnsignedLongLongTy; 297212904Sdim case LengthModifier::None: return Ctx.UnsignedIntTy; 298212904Sdim case LengthModifier::AsChar: return Ctx.UnsignedCharTy; 299218893Sdim case LengthModifier::AsShort: return Ctx.UnsignedShortTy; 300203955Srdivacky case LengthModifier::AsLong: return Ctx.UnsignedLongTy; 301203955Srdivacky case LengthModifier::AsLongLong: 302203955Srdivacky case LengthModifier::AsQuad: 303212904Sdim return Ctx.UnsignedLongLongTy; 304212904Sdim case LengthModifier::AsIntMax: 305212904Sdim return ArgTypeResult(Ctx.getUIntMaxType(), "uintmax_t"); 306212904Sdim case LengthModifier::AsSizeT: 307212904Sdim return ArgTypeResult(Ctx.getSizeType(), "size_t"); 308212904Sdim case LengthModifier::AsPtrDiff: 309212904Sdim // FIXME: How to get the corresponding unsigned 310218893Sdim // version of ptrdiff_t? 311203955Srdivacky return ArgTypeResult(); 312210299Sed case LengthModifier::AsAllocate: 313210299Sed case LengthModifier::AsMAllocate: 314203955Srdivacky return ArgTypeResult::Invalid(); 315210299Sed } 316210299Sed 317210299Sed if (CS.isDoubleArg()) { 318210299Sed if (LM.getKind() == LengthModifier::AsLongDouble) 319210299Sed return Ctx.LongDoubleTy; 320210299Sed return Ctx.DoubleTy; 321203955Srdivacky } 322203955Srdivacky 323210299Sed switch (CS.getKind()) { 324210299Sed case ConversionSpecifier::sArg: 325203955Srdivacky if (LM.getKind() == LengthModifier::AsWideChar) { 326203955Srdivacky if (IsObjCLiteral) 327203955Srdivacky return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()); 328210299Sed return ArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t *"); 329210299Sed } 330203955Srdivacky return ArgTypeResult::CStrTy; 331210299Sed case ConversionSpecifier::SArg: 332210299Sed if (IsObjCLiteral) 333210299Sed return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()); 334210299Sed return ArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t *"); 335210299Sed case ConversionSpecifier::CArg: 336210299Sed if (IsObjCLiteral) 337203955Srdivacky return Ctx.UnsignedShortTy; 338203955Srdivacky return ArgTypeResult(Ctx.WCharTy, "wchar_t"); 339210299Sed case ConversionSpecifier::pArg: 340203955Srdivacky return ArgTypeResult::CPointerTy; 341203955Srdivacky case ConversionSpecifier::ObjCObjArg: 342203955Srdivacky return ArgTypeResult::ObjCPointerTy; 343210299Sed default: 344203955Srdivacky break; 345203955Srdivacky } 346203955Srdivacky 347203955Srdivacky // FIXME: Handle other cases. 348203955Srdivacky return ArgTypeResult(); 349203955Srdivacky} 350210299Sed 351203955Srdivackybool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, 352203955Srdivacky ASTContext &Ctx, bool IsObjCLiteral) { 353203955Srdivacky // Handle strings first (char *, wchar_t *) 354203955Srdivacky if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { 355204643Srdivacky CS.setKind(ConversionSpecifier::sArg); 356212904Sdim 357210299Sed // Disable irrelevant flags 358210299Sed HasAlternativeForm = 0; 359212904Sdim HasLeadingZeroes = 0; 360204643Srdivacky 361204643Srdivacky // Set the long length modifier for wide characters 362204643Srdivacky if (QT->getPointeeType()->isWideCharType()) 363204643Srdivacky LM.setKind(LengthModifier::AsWideChar); 364212904Sdim else 365210299Sed LM.setKind(LengthModifier::None); 366204643Srdivacky 367204643Srdivacky return true; 368204643Srdivacky } 369203955Srdivacky 370203955Srdivacky // We can only work with builtin types. 371203955Srdivacky const BuiltinType *BT = QT->getAs<BuiltinType>(); 372203955Srdivacky if (!BT) 373203955Srdivacky return false; 374212904Sdim 375210299Sed // Set length modifier 376210299Sed switch (BT->getKind()) { 377212904Sdim case BuiltinType::Bool: 378210299Sed case BuiltinType::WChar_U: 379210299Sed case BuiltinType::WChar_S: 380210299Sed case BuiltinType::Char16: 381210299Sed case BuiltinType::Char32: 382210299Sed case BuiltinType::UInt128: 383210299Sed case BuiltinType::Int128: 384210299Sed case BuiltinType::Half: 385210299Sed // Various types which are non-trivial to correct. 386210299Sed return false; 387210299Sed 388210299Sed#define SIGNED_TYPE(Id, SingletonId) 389210299Sed#define UNSIGNED_TYPE(Id, SingletonId) 390210299Sed#define FLOATING_TYPE(Id, SingletonId) 391210299Sed#define BUILTIN_TYPE(Id, SingletonId) \ 392210299Sed case BuiltinType::Id: 393210299Sed#include "clang/AST/BuiltinTypes.def" 394210299Sed // Misc other stuff which doesn't make sense here. 395210299Sed return false; 396210299Sed 397210299Sed case BuiltinType::UInt: 398210299Sed case BuiltinType::Int: 399221345Sdim case BuiltinType::Float: 400221345Sdim case BuiltinType::Double: 401221345Sdim LM.setKind(LengthModifier::None); 402221345Sdim break; 403221345Sdim 404221345Sdim case BuiltinType::Char_U: 405221345Sdim case BuiltinType::UChar: 406226633Sdim case BuiltinType::Char_S: 407221345Sdim case BuiltinType::SChar: 408221345Sdim LM.setKind(LengthModifier::AsChar); 409221345Sdim break; 410221345Sdim 411221345Sdim case BuiltinType::Short: 412221345Sdim case BuiltinType::UShort: 413221345Sdim LM.setKind(LengthModifier::AsShort); 414221345Sdim break; 415221345Sdim 416221345Sdim case BuiltinType::Long: 417221345Sdim case BuiltinType::ULong: 418221345Sdim LM.setKind(LengthModifier::AsLong); 419221345Sdim break; 420221345Sdim 421221345Sdim case BuiltinType::LongLong: 422221345Sdim case BuiltinType::ULongLong: 423221345Sdim LM.setKind(LengthModifier::AsLongLong); 424221345Sdim break; 425221345Sdim 426210299Sed case BuiltinType::LongDouble: 427210299Sed LM.setKind(LengthModifier::AsLongDouble); 428210299Sed break; 429218893Sdim } 430218893Sdim 431218893Sdim // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. 432218893Sdim if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus0x)) { 433218893Sdim const IdentifierInfo *Identifier = QT.getBaseTypeIdentifier(); 434218893Sdim if (Identifier->getName() == "size_t") { 435218893Sdim LM.setKind(LengthModifier::AsSizeT); 436218893Sdim } else if (Identifier->getName() == "ssize_t") { 437218893Sdim // Not C99, but common in Unix. 438218893Sdim LM.setKind(LengthModifier::AsSizeT); 439218893Sdim } else if (Identifier->getName() == "intmax_t") { 440218893Sdim LM.setKind(LengthModifier::AsIntMax); 441210299Sed } else if (Identifier->getName() == "uintmax_t") { 442210299Sed LM.setKind(LengthModifier::AsIntMax); 443210299Sed } else if (Identifier->getName() == "ptrdiff_t") { 444210299Sed LM.setKind(LengthModifier::AsPtrDiff); 445210299Sed } 446210299Sed } 447210299Sed 448210299Sed // If fixing the length modifier was enough, we are done. 449210299Sed const analyze_printf::ArgTypeResult &ATR = getArgType(Ctx, IsObjCLiteral); 450210299Sed if (hasValidLengthModifier() && ATR.isValid() && ATR.matchesType(Ctx, QT)) 451210299Sed return true; 452210299Sed 453210299Sed // Set conversion specifier and disable any flags which do not apply to it. 454210299Sed // Let typedefs to char fall through to int, as %c is silly for uint8_t. 455210299Sed if (isa<TypedefType>(QT) && QT->isAnyCharacterType()) { 456210299Sed CS.setKind(ConversionSpecifier::cArg); 457218893Sdim LM.setKind(LengthModifier::None); 458218893Sdim Precision.setHowSpecified(OptionalAmount::NotSpecified); 459212904Sdim HasAlternativeForm = 0; 460218893Sdim HasLeadingZeroes = 0; 461210299Sed HasPlusPrefix = 0; 462210299Sed } 463210299Sed // Test for Floating type first as LongDouble can pass isUnsignedIntegerType 464210299Sed else if (QT->isRealFloatingType()) { 465210299Sed CS.setKind(ConversionSpecifier::fArg); 466210299Sed } 467210299Sed else if (QT->isSignedIntegerType()) { 468210299Sed CS.setKind(ConversionSpecifier::dArg); 469210299Sed HasAlternativeForm = 0; 470210299Sed } 471210299Sed else if (QT->isUnsignedIntegerType()) { 472210299Sed CS.setKind(ConversionSpecifier::uArg); 473210299Sed HasAlternativeForm = 0; 474210299Sed HasPlusPrefix = 0; 475221345Sdim } else { 476221345Sdim llvm_unreachable("Unexpected type"); 477221345Sdim } 478210299Sed 479210299Sed return true; 480226633Sdim} 481226633Sdim 482210299Sedvoid PrintfSpecifier::toString(raw_ostream &os) const { 483210299Sed // Whilst some features have no defined order, we are using the order 484210299Sed // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1) 485210299Sed os << "%"; 486210299Sed 487226633Sdim // Positional args 488210299Sed if (usesPositionalArg()) { 489218893Sdim os << getPositionalArgIndex() << "$"; 490210299Sed } 491210299Sed 492210299Sed // Conversion flags 493210299Sed if (IsLeftJustified) os << "-"; 494210299Sed if (HasPlusPrefix) os << "+"; 495210299Sed if (HasSpacePrefix) os << " "; 496210299Sed if (HasAlternativeForm) os << "#"; 497210299Sed if (HasLeadingZeroes) os << "0"; 498210299Sed 499210299Sed // Minimum field width 500210299Sed FieldWidth.toString(os); 501210299Sed // Precision 502210299Sed Precision.toString(os); 503210299Sed // Length modifier 504210299Sed os << LM.toString(); 505210299Sed // Conversion specifier 506210299Sed os << CS.toString(); 507210299Sed} 508210299Sed 509210299Sedbool PrintfSpecifier::hasValidPlusPrefix() const { 510210299Sed if (!HasPlusPrefix) 511210299Sed return true; 512210299Sed 513210299Sed // The plus prefix only makes sense for signed conversions 514212904Sdim switch (CS.getKind()) { 515210299Sed case ConversionSpecifier::dArg: 516210299Sed case ConversionSpecifier::iArg: 517210299Sed case ConversionSpecifier::fArg: 518210299Sed case ConversionSpecifier::FArg: 519210299Sed case ConversionSpecifier::eArg: 520210299Sed case ConversionSpecifier::EArg: 521210299Sed case ConversionSpecifier::gArg: 522210299Sed case ConversionSpecifier::GArg: 523210299Sed case ConversionSpecifier::aArg: 524210299Sed case ConversionSpecifier::AArg: 525210299Sed case ConversionSpecifier::rArg: 526210299Sed return true; 527210299Sed 528210299Sed default: 529210299Sed return false; 530213694Srpaulo } 531210299Sed} 532210299Sed 533210299Sedbool PrintfSpecifier::hasValidAlternativeForm() const { 534210299Sed if (!HasAlternativeForm) 535210299Sed return true; 536210299Sed 537210299Sed // Alternate form flag only valid with the oxXaAeEfFgG conversions 538212904Sdim switch (CS.getKind()) { 539210299Sed case ConversionSpecifier::oArg: 540210299Sed case ConversionSpecifier::xArg: 541210299Sed case ConversionSpecifier::XArg: 542218893Sdim case ConversionSpecifier::aArg: 543210299Sed case ConversionSpecifier::AArg: 544210299Sed case ConversionSpecifier::eArg: 545210299Sed case ConversionSpecifier::EArg: 546218893Sdim case ConversionSpecifier::fArg: 547210299Sed case ConversionSpecifier::FArg: 548210299Sed case ConversionSpecifier::gArg: 549210299Sed case ConversionSpecifier::GArg: 550210299Sed case ConversionSpecifier::rArg: 551210299Sed return true; 552210299Sed 553210299Sed default: 554210299Sed return false; 555213694Srpaulo } 556210299Sed} 557210299Sed 558210299Sedbool PrintfSpecifier::hasValidLeadingZeros() const { 559210299Sed if (!HasLeadingZeroes) 560210299Sed return true; 561210299Sed 562210299Sed // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions 563212904Sdim switch (CS.getKind()) { 564210299Sed case ConversionSpecifier::dArg: 565210299Sed case ConversionSpecifier::iArg: 566210299Sed case ConversionSpecifier::oArg: 567210299Sed case ConversionSpecifier::uArg: 568210299Sed case ConversionSpecifier::xArg: 569210299Sed case ConversionSpecifier::XArg: 570210299Sed case ConversionSpecifier::aArg: 571210299Sed case ConversionSpecifier::AArg: 572210299Sed case ConversionSpecifier::eArg: 573210299Sed case ConversionSpecifier::EArg: 574210299Sed case ConversionSpecifier::fArg: 575210299Sed case ConversionSpecifier::FArg: 576210299Sed case ConversionSpecifier::gArg: 577210299Sed case ConversionSpecifier::GArg: 578210299Sed return true; 579210299Sed 580210299Sed default: 581210299Sed return false; 582210299Sed } 583210299Sed} 584210299Sed 585210299Sedbool PrintfSpecifier::hasValidSpacePrefix() const { 586210299Sed if (!HasSpacePrefix) 587210299Sed return true; 588210299Sed 589210299Sed // The space prefix only makes sense for signed conversions 590212904Sdim switch (CS.getKind()) { 591210299Sed case ConversionSpecifier::dArg: 592210299Sed case ConversionSpecifier::iArg: 593210299Sed case ConversionSpecifier::fArg: 594210299Sed case ConversionSpecifier::FArg: 595210299Sed case ConversionSpecifier::eArg: 596210299Sed case ConversionSpecifier::EArg: 597210299Sed case ConversionSpecifier::gArg: 598210299Sed case ConversionSpecifier::GArg: 599210299Sed case ConversionSpecifier::aArg: 600210299Sed case ConversionSpecifier::AArg: 601210299Sed return true; 602210299Sed 603210299Sed default: 604210299Sed return false; 605210299Sed } 606210299Sed} 607210299Sed 608210299Sedbool PrintfSpecifier::hasValidLeftJustified() const { 609210299Sed if (!IsLeftJustified) 610210299Sed return true; 611210299Sed 612210299Sed // The left justified flag is valid for all conversions except n 613212904Sdim switch (CS.getKind()) { 614210299Sed case ConversionSpecifier::nArg: 615210299Sed return false; 616210299Sed 617210299Sed default: 618210299Sed return true; 619212904Sdim } 620210299Sed} 621210299Sed 622210299Sedbool PrintfSpecifier::hasValidThousandsGroupingPrefix() const { 623210299Sed if (!HasThousandsGrouping) 624210299Sed return true; 625210299Sed 626210299Sed switch (CS.getKind()) { 627218893Sdim case ConversionSpecifier::dArg: 628218893Sdim case ConversionSpecifier::iArg: 629218893Sdim case ConversionSpecifier::uArg: 630218893Sdim case ConversionSpecifier::fArg: 631218893Sdim case ConversionSpecifier::FArg: 632218893Sdim case ConversionSpecifier::gArg: 633218893Sdim case ConversionSpecifier::GArg: 634218893Sdim return true; 635218893Sdim default: 636218893Sdim return false; 637218893Sdim } 638218893Sdim} 639218893Sdim 640218893Sdimbool PrintfSpecifier::hasValidPrecision() const { 641218893Sdim if (Precision.getHowSpecified() == OptionalAmount::NotSpecified) 642218893Sdim return true; 643218893Sdim 644218893Sdim // Precision is only valid with the diouxXaAeEfFgGs conversions 645212904Sdim switch (CS.getKind()) { 646210299Sed case ConversionSpecifier::dArg: 647210299Sed case ConversionSpecifier::iArg: 648210299Sed case ConversionSpecifier::oArg: 649210299Sed case ConversionSpecifier::uArg: 650210299Sed case ConversionSpecifier::xArg: 651210299Sed case ConversionSpecifier::XArg: 652210299Sed case ConversionSpecifier::aArg: 653210299Sed case ConversionSpecifier::AArg: 654210299Sed case ConversionSpecifier::eArg: 655210299Sed case ConversionSpecifier::EArg: 656210299Sed case ConversionSpecifier::fArg: 657210299Sed case ConversionSpecifier::FArg: 658210299Sed case ConversionSpecifier::gArg: 659210299Sed case ConversionSpecifier::GArg: 660210299Sed case ConversionSpecifier::sArg: 661210299Sed return true; 662210299Sed 663210299Sed default: 664210299Sed return false; 665212904Sdim } 666210299Sed} 667210299Sedbool PrintfSpecifier::hasValidFieldWidth() const { 668210299Sed if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified) 669210299Sed return true; 670210299Sed 671210299Sed // The field width is valid for all conversions except n 672212904Sdim switch (CS.getKind()) { 673210299Sed case ConversionSpecifier::nArg: 674210299Sed return false; 675210299Sed 676210299Sed default: 677210299Sed return true; 678212904Sdim } 679210299Sed} 680210299Sed