1*0b57cec5SDimitry Andric //== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // Handling of format string in printf and friends. The structure of format 10*0b57cec5SDimitry Andric // strings for fprintf() are described in C99 7.19.6.1. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "clang/AST/FormatString.h" 15*0b57cec5SDimitry Andric #include "clang/AST/OSLog.h" 16*0b57cec5SDimitry Andric #include "FormatStringParsing.h" 17*0b57cec5SDimitry Andric #include "clang/Basic/TargetInfo.h" 18*0b57cec5SDimitry Andric 19*0b57cec5SDimitry Andric using clang::analyze_format_string::ArgType; 20*0b57cec5SDimitry Andric using clang::analyze_format_string::FormatStringHandler; 21*0b57cec5SDimitry Andric using clang::analyze_format_string::LengthModifier; 22*0b57cec5SDimitry Andric using clang::analyze_format_string::OptionalAmount; 23*0b57cec5SDimitry Andric using clang::analyze_format_string::ConversionSpecifier; 24*0b57cec5SDimitry Andric using clang::analyze_printf::PrintfSpecifier; 25*0b57cec5SDimitry Andric 26*0b57cec5SDimitry Andric using namespace clang; 27*0b57cec5SDimitry Andric 28*0b57cec5SDimitry Andric typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier> 29*0b57cec5SDimitry Andric PrintfSpecifierResult; 30*0b57cec5SDimitry Andric 31*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 32*0b57cec5SDimitry Andric // Methods for parsing format strings. 33*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 34*0b57cec5SDimitry Andric 35*0b57cec5SDimitry Andric using analyze_format_string::ParseNonPositionAmount; 36*0b57cec5SDimitry Andric 37*0b57cec5SDimitry Andric static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, 38*0b57cec5SDimitry Andric const char *Start, const char *&Beg, const char *E, 39*0b57cec5SDimitry Andric unsigned *argIndex) { 40*0b57cec5SDimitry Andric if (argIndex) { 41*0b57cec5SDimitry Andric FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex)); 42*0b57cec5SDimitry Andric } else { 43*0b57cec5SDimitry Andric const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, 44*0b57cec5SDimitry Andric analyze_format_string::PrecisionPos); 45*0b57cec5SDimitry Andric if (Amt.isInvalid()) 46*0b57cec5SDimitry Andric return true; 47*0b57cec5SDimitry Andric FS.setPrecision(Amt); 48*0b57cec5SDimitry Andric } 49*0b57cec5SDimitry Andric return false; 50*0b57cec5SDimitry Andric } 51*0b57cec5SDimitry Andric 52*0b57cec5SDimitry Andric static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS, 53*0b57cec5SDimitry Andric const char *FlagBeg, const char *E, bool Warn) { 54*0b57cec5SDimitry Andric StringRef Flag(FlagBeg, E - FlagBeg); 55*0b57cec5SDimitry Andric // Currently there is only one flag. 56*0b57cec5SDimitry Andric if (Flag == "tt") { 57*0b57cec5SDimitry Andric FS.setHasObjCTechnicalTerm(FlagBeg); 58*0b57cec5SDimitry Andric return false; 59*0b57cec5SDimitry Andric } 60*0b57cec5SDimitry Andric // Handle either the case of no flag or an invalid flag. 61*0b57cec5SDimitry Andric if (Warn) { 62*0b57cec5SDimitry Andric if (Flag == "") 63*0b57cec5SDimitry Andric H.HandleEmptyObjCModifierFlag(FlagBeg, E - FlagBeg); 64*0b57cec5SDimitry Andric else 65*0b57cec5SDimitry Andric H.HandleInvalidObjCModifierFlag(FlagBeg, E - FlagBeg); 66*0b57cec5SDimitry Andric } 67*0b57cec5SDimitry Andric return true; 68*0b57cec5SDimitry Andric } 69*0b57cec5SDimitry Andric 70*0b57cec5SDimitry Andric static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, 71*0b57cec5SDimitry Andric const char *&Beg, 72*0b57cec5SDimitry Andric const char *E, 73*0b57cec5SDimitry Andric unsigned &argIndex, 74*0b57cec5SDimitry Andric const LangOptions &LO, 75*0b57cec5SDimitry Andric const TargetInfo &Target, 76*0b57cec5SDimitry Andric bool Warn, 77*0b57cec5SDimitry Andric bool isFreeBSDKPrintf) { 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric using namespace clang::analyze_format_string; 80*0b57cec5SDimitry Andric using namespace clang::analyze_printf; 81*0b57cec5SDimitry Andric 82*0b57cec5SDimitry Andric const char *I = Beg; 83*0b57cec5SDimitry Andric const char *Start = nullptr; 84*0b57cec5SDimitry Andric UpdateOnReturn <const char*> UpdateBeg(Beg, I); 85*0b57cec5SDimitry Andric 86*0b57cec5SDimitry Andric // Look for a '%' character that indicates the start of a format specifier. 87*0b57cec5SDimitry Andric for ( ; I != E ; ++I) { 88*0b57cec5SDimitry Andric char c = *I; 89*0b57cec5SDimitry Andric if (c == '\0') { 90*0b57cec5SDimitry Andric // Detect spurious null characters, which are likely errors. 91*0b57cec5SDimitry Andric H.HandleNullChar(I); 92*0b57cec5SDimitry Andric return true; 93*0b57cec5SDimitry Andric } 94*0b57cec5SDimitry Andric if (c == '%') { 95*0b57cec5SDimitry Andric Start = I++; // Record the start of the format specifier. 96*0b57cec5SDimitry Andric break; 97*0b57cec5SDimitry Andric } 98*0b57cec5SDimitry Andric } 99*0b57cec5SDimitry Andric 100*0b57cec5SDimitry Andric // No format specifier found? 101*0b57cec5SDimitry Andric if (!Start) 102*0b57cec5SDimitry Andric return false; 103*0b57cec5SDimitry Andric 104*0b57cec5SDimitry Andric if (I == E) { 105*0b57cec5SDimitry Andric // No more characters left? 106*0b57cec5SDimitry Andric if (Warn) 107*0b57cec5SDimitry Andric H.HandleIncompleteSpecifier(Start, E - Start); 108*0b57cec5SDimitry Andric return true; 109*0b57cec5SDimitry Andric } 110*0b57cec5SDimitry Andric 111*0b57cec5SDimitry Andric PrintfSpecifier FS; 112*0b57cec5SDimitry Andric if (ParseArgPosition(H, FS, Start, I, E)) 113*0b57cec5SDimitry Andric return true; 114*0b57cec5SDimitry Andric 115*0b57cec5SDimitry Andric if (I == E) { 116*0b57cec5SDimitry Andric // No more characters left? 117*0b57cec5SDimitry Andric if (Warn) 118*0b57cec5SDimitry Andric H.HandleIncompleteSpecifier(Start, E - Start); 119*0b57cec5SDimitry Andric return true; 120*0b57cec5SDimitry Andric } 121*0b57cec5SDimitry Andric 122*0b57cec5SDimitry Andric if (*I == '{') { 123*0b57cec5SDimitry Andric ++I; 124*0b57cec5SDimitry Andric unsigned char PrivacyFlags = 0; 125*0b57cec5SDimitry Andric StringRef MatchedStr; 126*0b57cec5SDimitry Andric 127*0b57cec5SDimitry Andric do { 128*0b57cec5SDimitry Andric StringRef Str(I, E - I); 129*0b57cec5SDimitry Andric std::string Match = "^[[:space:]]*" 130*0b57cec5SDimitry Andric "(private|public|sensitive|mask\\.[^[:space:],}]*)" 131*0b57cec5SDimitry Andric "[[:space:]]*(,|})"; 132*0b57cec5SDimitry Andric llvm::Regex R(Match); 133*0b57cec5SDimitry Andric SmallVector<StringRef, 2> Matches; 134*0b57cec5SDimitry Andric 135*0b57cec5SDimitry Andric if (R.match(Str, &Matches)) { 136*0b57cec5SDimitry Andric MatchedStr = Matches[1]; 137*0b57cec5SDimitry Andric I += Matches[0].size(); 138*0b57cec5SDimitry Andric 139*0b57cec5SDimitry Andric // Set the privacy flag if the privacy annotation in the 140*0b57cec5SDimitry Andric // comma-delimited segment is at least as strict as the privacy 141*0b57cec5SDimitry Andric // annotations in previous comma-delimited segments. 142*0b57cec5SDimitry Andric if (MatchedStr.startswith("mask")) { 143*0b57cec5SDimitry Andric StringRef MaskType = MatchedStr.substr(sizeof("mask.") - 1); 144*0b57cec5SDimitry Andric unsigned Size = MaskType.size(); 145*0b57cec5SDimitry Andric if (Warn && (Size == 0 || Size > 8)) 146*0b57cec5SDimitry Andric H.handleInvalidMaskType(MaskType); 147*0b57cec5SDimitry Andric FS.setMaskType(MaskType); 148*0b57cec5SDimitry Andric } else if (MatchedStr.equals("sensitive")) 149*0b57cec5SDimitry Andric PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsSensitive; 150*0b57cec5SDimitry Andric else if (PrivacyFlags != 151*0b57cec5SDimitry Andric clang::analyze_os_log::OSLogBufferItem::IsSensitive && 152*0b57cec5SDimitry Andric MatchedStr.equals("private")) 153*0b57cec5SDimitry Andric PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate; 154*0b57cec5SDimitry Andric else if (PrivacyFlags == 0 && MatchedStr.equals("public")) 155*0b57cec5SDimitry Andric PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic; 156*0b57cec5SDimitry Andric } else { 157*0b57cec5SDimitry Andric size_t CommaOrBracePos = 158*0b57cec5SDimitry Andric Str.find_if([](char c) { return c == ',' || c == '}'; }); 159*0b57cec5SDimitry Andric 160*0b57cec5SDimitry Andric if (CommaOrBracePos == StringRef::npos) { 161*0b57cec5SDimitry Andric // Neither a comma nor the closing brace was found. 162*0b57cec5SDimitry Andric if (Warn) 163*0b57cec5SDimitry Andric H.HandleIncompleteSpecifier(Start, E - Start); 164*0b57cec5SDimitry Andric return true; 165*0b57cec5SDimitry Andric } 166*0b57cec5SDimitry Andric 167*0b57cec5SDimitry Andric I += CommaOrBracePos + 1; 168*0b57cec5SDimitry Andric } 169*0b57cec5SDimitry Andric // Continue until the closing brace is found. 170*0b57cec5SDimitry Andric } while (*(I - 1) == ','); 171*0b57cec5SDimitry Andric 172*0b57cec5SDimitry Andric // Set the privacy flag. 173*0b57cec5SDimitry Andric switch (PrivacyFlags) { 174*0b57cec5SDimitry Andric case 0: 175*0b57cec5SDimitry Andric break; 176*0b57cec5SDimitry Andric case clang::analyze_os_log::OSLogBufferItem::IsPrivate: 177*0b57cec5SDimitry Andric FS.setIsPrivate(MatchedStr.data()); 178*0b57cec5SDimitry Andric break; 179*0b57cec5SDimitry Andric case clang::analyze_os_log::OSLogBufferItem::IsPublic: 180*0b57cec5SDimitry Andric FS.setIsPublic(MatchedStr.data()); 181*0b57cec5SDimitry Andric break; 182*0b57cec5SDimitry Andric case clang::analyze_os_log::OSLogBufferItem::IsSensitive: 183*0b57cec5SDimitry Andric FS.setIsSensitive(MatchedStr.data()); 184*0b57cec5SDimitry Andric break; 185*0b57cec5SDimitry Andric default: 186*0b57cec5SDimitry Andric llvm_unreachable("Unexpected privacy flag value"); 187*0b57cec5SDimitry Andric } 188*0b57cec5SDimitry Andric } 189*0b57cec5SDimitry Andric 190*0b57cec5SDimitry Andric // Look for flags (if any). 191*0b57cec5SDimitry Andric bool hasMore = true; 192*0b57cec5SDimitry Andric for ( ; I != E; ++I) { 193*0b57cec5SDimitry Andric switch (*I) { 194*0b57cec5SDimitry Andric default: hasMore = false; break; 195*0b57cec5SDimitry Andric case '\'': 196*0b57cec5SDimitry Andric // FIXME: POSIX specific. Always accept? 197*0b57cec5SDimitry Andric FS.setHasThousandsGrouping(I); 198*0b57cec5SDimitry Andric break; 199*0b57cec5SDimitry Andric case '-': FS.setIsLeftJustified(I); break; 200*0b57cec5SDimitry Andric case '+': FS.setHasPlusPrefix(I); break; 201*0b57cec5SDimitry Andric case ' ': FS.setHasSpacePrefix(I); break; 202*0b57cec5SDimitry Andric case '#': FS.setHasAlternativeForm(I); break; 203*0b57cec5SDimitry Andric case '0': FS.setHasLeadingZeros(I); break; 204*0b57cec5SDimitry Andric } 205*0b57cec5SDimitry Andric if (!hasMore) 206*0b57cec5SDimitry Andric break; 207*0b57cec5SDimitry Andric } 208*0b57cec5SDimitry Andric 209*0b57cec5SDimitry Andric if (I == E) { 210*0b57cec5SDimitry Andric // No more characters left? 211*0b57cec5SDimitry Andric if (Warn) 212*0b57cec5SDimitry Andric H.HandleIncompleteSpecifier(Start, E - Start); 213*0b57cec5SDimitry Andric return true; 214*0b57cec5SDimitry Andric } 215*0b57cec5SDimitry Andric 216*0b57cec5SDimitry Andric // Look for the field width (if any). 217*0b57cec5SDimitry Andric if (ParseFieldWidth(H, FS, Start, I, E, 218*0b57cec5SDimitry Andric FS.usesPositionalArg() ? nullptr : &argIndex)) 219*0b57cec5SDimitry Andric return true; 220*0b57cec5SDimitry Andric 221*0b57cec5SDimitry Andric if (I == E) { 222*0b57cec5SDimitry Andric // No more characters left? 223*0b57cec5SDimitry Andric if (Warn) 224*0b57cec5SDimitry Andric H.HandleIncompleteSpecifier(Start, E - Start); 225*0b57cec5SDimitry Andric return true; 226*0b57cec5SDimitry Andric } 227*0b57cec5SDimitry Andric 228*0b57cec5SDimitry Andric // Look for the precision (if any). 229*0b57cec5SDimitry Andric if (*I == '.') { 230*0b57cec5SDimitry Andric ++I; 231*0b57cec5SDimitry Andric if (I == E) { 232*0b57cec5SDimitry Andric if (Warn) 233*0b57cec5SDimitry Andric H.HandleIncompleteSpecifier(Start, E - Start); 234*0b57cec5SDimitry Andric return true; 235*0b57cec5SDimitry Andric } 236*0b57cec5SDimitry Andric 237*0b57cec5SDimitry Andric if (ParsePrecision(H, FS, Start, I, E, 238*0b57cec5SDimitry Andric FS.usesPositionalArg() ? nullptr : &argIndex)) 239*0b57cec5SDimitry Andric return true; 240*0b57cec5SDimitry Andric 241*0b57cec5SDimitry Andric if (I == E) { 242*0b57cec5SDimitry Andric // No more characters left? 243*0b57cec5SDimitry Andric if (Warn) 244*0b57cec5SDimitry Andric H.HandleIncompleteSpecifier(Start, E - Start); 245*0b57cec5SDimitry Andric return true; 246*0b57cec5SDimitry Andric } 247*0b57cec5SDimitry Andric } 248*0b57cec5SDimitry Andric 249*0b57cec5SDimitry Andric if (ParseVectorModifier(H, FS, I, E, LO)) 250*0b57cec5SDimitry Andric return true; 251*0b57cec5SDimitry Andric 252*0b57cec5SDimitry Andric // Look for the length modifier. 253*0b57cec5SDimitry Andric if (ParseLengthModifier(FS, I, E, LO) && I == E) { 254*0b57cec5SDimitry Andric // No more characters left? 255*0b57cec5SDimitry Andric if (Warn) 256*0b57cec5SDimitry Andric H.HandleIncompleteSpecifier(Start, E - Start); 257*0b57cec5SDimitry Andric return true; 258*0b57cec5SDimitry Andric } 259*0b57cec5SDimitry Andric 260*0b57cec5SDimitry Andric // Look for the Objective-C modifier flags, if any. 261*0b57cec5SDimitry Andric // We parse these here, even if they don't apply to 262*0b57cec5SDimitry Andric // the conversion specifier, and then emit an error 263*0b57cec5SDimitry Andric // later if the conversion specifier isn't '@'. This 264*0b57cec5SDimitry Andric // enables better recovery, and we don't know if 265*0b57cec5SDimitry Andric // these flags are applicable until later. 266*0b57cec5SDimitry Andric const char *ObjCModifierFlagsStart = nullptr, 267*0b57cec5SDimitry Andric *ObjCModifierFlagsEnd = nullptr; 268*0b57cec5SDimitry Andric if (*I == '[') { 269*0b57cec5SDimitry Andric ObjCModifierFlagsStart = I; 270*0b57cec5SDimitry Andric ++I; 271*0b57cec5SDimitry Andric auto flagStart = I; 272*0b57cec5SDimitry Andric for (;; ++I) { 273*0b57cec5SDimitry Andric ObjCModifierFlagsEnd = I; 274*0b57cec5SDimitry Andric if (I == E) { 275*0b57cec5SDimitry Andric if (Warn) 276*0b57cec5SDimitry Andric H.HandleIncompleteSpecifier(Start, E - Start); 277*0b57cec5SDimitry Andric return true; 278*0b57cec5SDimitry Andric } 279*0b57cec5SDimitry Andric // Did we find the closing ']'? 280*0b57cec5SDimitry Andric if (*I == ']') { 281*0b57cec5SDimitry Andric if (ParseObjCFlags(H, FS, flagStart, I, Warn)) 282*0b57cec5SDimitry Andric return true; 283*0b57cec5SDimitry Andric ++I; 284*0b57cec5SDimitry Andric break; 285*0b57cec5SDimitry Andric } 286*0b57cec5SDimitry Andric // There are no separators defined yet for multiple 287*0b57cec5SDimitry Andric // Objective-C modifier flags. When those are 288*0b57cec5SDimitry Andric // defined, this is the place to check. 289*0b57cec5SDimitry Andric } 290*0b57cec5SDimitry Andric } 291*0b57cec5SDimitry Andric 292*0b57cec5SDimitry Andric if (*I == '\0') { 293*0b57cec5SDimitry Andric // Detect spurious null characters, which are likely errors. 294*0b57cec5SDimitry Andric H.HandleNullChar(I); 295*0b57cec5SDimitry Andric return true; 296*0b57cec5SDimitry Andric } 297*0b57cec5SDimitry Andric 298*0b57cec5SDimitry Andric // Finally, look for the conversion specifier. 299*0b57cec5SDimitry Andric const char *conversionPosition = I++; 300*0b57cec5SDimitry Andric ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; 301*0b57cec5SDimitry Andric switch (*conversionPosition) { 302*0b57cec5SDimitry Andric default: 303*0b57cec5SDimitry Andric break; 304*0b57cec5SDimitry Andric // C99: 7.19.6.1 (section 8). 305*0b57cec5SDimitry Andric case '%': k = ConversionSpecifier::PercentArg; break; 306*0b57cec5SDimitry Andric case 'A': k = ConversionSpecifier::AArg; break; 307*0b57cec5SDimitry Andric case 'E': k = ConversionSpecifier::EArg; break; 308*0b57cec5SDimitry Andric case 'F': k = ConversionSpecifier::FArg; break; 309*0b57cec5SDimitry Andric case 'G': k = ConversionSpecifier::GArg; break; 310*0b57cec5SDimitry Andric case 'X': k = ConversionSpecifier::XArg; break; 311*0b57cec5SDimitry Andric case 'a': k = ConversionSpecifier::aArg; break; 312*0b57cec5SDimitry Andric case 'c': k = ConversionSpecifier::cArg; break; 313*0b57cec5SDimitry Andric case 'd': k = ConversionSpecifier::dArg; break; 314*0b57cec5SDimitry Andric case 'e': k = ConversionSpecifier::eArg; break; 315*0b57cec5SDimitry Andric case 'f': k = ConversionSpecifier::fArg; break; 316*0b57cec5SDimitry Andric case 'g': k = ConversionSpecifier::gArg; break; 317*0b57cec5SDimitry Andric case 'i': k = ConversionSpecifier::iArg; break; 318*0b57cec5SDimitry Andric case 'n': 319*0b57cec5SDimitry Andric // Not handled, but reserved in OpenCL. 320*0b57cec5SDimitry Andric if (!LO.OpenCL) 321*0b57cec5SDimitry Andric k = ConversionSpecifier::nArg; 322*0b57cec5SDimitry Andric break; 323*0b57cec5SDimitry Andric case 'o': k = ConversionSpecifier::oArg; break; 324*0b57cec5SDimitry Andric case 'p': k = ConversionSpecifier::pArg; break; 325*0b57cec5SDimitry Andric case 's': k = ConversionSpecifier::sArg; break; 326*0b57cec5SDimitry Andric case 'u': k = ConversionSpecifier::uArg; break; 327*0b57cec5SDimitry Andric case 'x': k = ConversionSpecifier::xArg; break; 328*0b57cec5SDimitry Andric // POSIX specific. 329*0b57cec5SDimitry Andric case 'C': k = ConversionSpecifier::CArg; break; 330*0b57cec5SDimitry Andric case 'S': k = ConversionSpecifier::SArg; break; 331*0b57cec5SDimitry Andric // Apple extension for os_log 332*0b57cec5SDimitry Andric case 'P': 333*0b57cec5SDimitry Andric k = ConversionSpecifier::PArg; 334*0b57cec5SDimitry Andric break; 335*0b57cec5SDimitry Andric // Objective-C. 336*0b57cec5SDimitry Andric case '@': k = ConversionSpecifier::ObjCObjArg; break; 337*0b57cec5SDimitry Andric // Glibc specific. 338*0b57cec5SDimitry Andric case 'm': k = ConversionSpecifier::PrintErrno; break; 339*0b57cec5SDimitry Andric // FreeBSD kernel specific. 340*0b57cec5SDimitry Andric case 'b': 341*0b57cec5SDimitry Andric if (isFreeBSDKPrintf) 342*0b57cec5SDimitry Andric k = ConversionSpecifier::FreeBSDbArg; // int followed by char * 343*0b57cec5SDimitry Andric break; 344*0b57cec5SDimitry Andric case 'r': 345*0b57cec5SDimitry Andric if (isFreeBSDKPrintf) 346*0b57cec5SDimitry Andric k = ConversionSpecifier::FreeBSDrArg; // int 347*0b57cec5SDimitry Andric break; 348*0b57cec5SDimitry Andric case 'y': 349*0b57cec5SDimitry Andric if (isFreeBSDKPrintf) 350*0b57cec5SDimitry Andric k = ConversionSpecifier::FreeBSDyArg; // int 351*0b57cec5SDimitry Andric break; 352*0b57cec5SDimitry Andric // Apple-specific. 353*0b57cec5SDimitry Andric case 'D': 354*0b57cec5SDimitry Andric if (isFreeBSDKPrintf) 355*0b57cec5SDimitry Andric k = ConversionSpecifier::FreeBSDDArg; // void * followed by char * 356*0b57cec5SDimitry Andric else if (Target.getTriple().isOSDarwin()) 357*0b57cec5SDimitry Andric k = ConversionSpecifier::DArg; 358*0b57cec5SDimitry Andric break; 359*0b57cec5SDimitry Andric case 'O': 360*0b57cec5SDimitry Andric if (Target.getTriple().isOSDarwin()) 361*0b57cec5SDimitry Andric k = ConversionSpecifier::OArg; 362*0b57cec5SDimitry Andric break; 363*0b57cec5SDimitry Andric case 'U': 364*0b57cec5SDimitry Andric if (Target.getTriple().isOSDarwin()) 365*0b57cec5SDimitry Andric k = ConversionSpecifier::UArg; 366*0b57cec5SDimitry Andric break; 367*0b57cec5SDimitry Andric // MS specific. 368*0b57cec5SDimitry Andric case 'Z': 369*0b57cec5SDimitry Andric if (Target.getTriple().isOSMSVCRT()) 370*0b57cec5SDimitry Andric k = ConversionSpecifier::ZArg; 371*0b57cec5SDimitry Andric break; 372*0b57cec5SDimitry Andric } 373*0b57cec5SDimitry Andric 374*0b57cec5SDimitry Andric // Check to see if we used the Objective-C modifier flags with 375*0b57cec5SDimitry Andric // a conversion specifier other than '@'. 376*0b57cec5SDimitry Andric if (k != ConversionSpecifier::ObjCObjArg && 377*0b57cec5SDimitry Andric k != ConversionSpecifier::InvalidSpecifier && 378*0b57cec5SDimitry Andric ObjCModifierFlagsStart) { 379*0b57cec5SDimitry Andric H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart, 380*0b57cec5SDimitry Andric ObjCModifierFlagsEnd + 1, 381*0b57cec5SDimitry Andric conversionPosition); 382*0b57cec5SDimitry Andric return true; 383*0b57cec5SDimitry Andric } 384*0b57cec5SDimitry Andric 385*0b57cec5SDimitry Andric PrintfConversionSpecifier CS(conversionPosition, k); 386*0b57cec5SDimitry Andric FS.setConversionSpecifier(CS); 387*0b57cec5SDimitry Andric if (CS.consumesDataArgument() && !FS.usesPositionalArg()) 388*0b57cec5SDimitry Andric FS.setArgIndex(argIndex++); 389*0b57cec5SDimitry Andric // FreeBSD kernel specific. 390*0b57cec5SDimitry Andric if (k == ConversionSpecifier::FreeBSDbArg || 391*0b57cec5SDimitry Andric k == ConversionSpecifier::FreeBSDDArg) 392*0b57cec5SDimitry Andric argIndex++; 393*0b57cec5SDimitry Andric 394*0b57cec5SDimitry Andric if (k == ConversionSpecifier::InvalidSpecifier) { 395*0b57cec5SDimitry Andric unsigned Len = I - Start; 396*0b57cec5SDimitry Andric if (ParseUTF8InvalidSpecifier(Start, E, Len)) { 397*0b57cec5SDimitry Andric CS.setEndScanList(Start + Len); 398*0b57cec5SDimitry Andric FS.setConversionSpecifier(CS); 399*0b57cec5SDimitry Andric } 400*0b57cec5SDimitry Andric // Assume the conversion takes one argument. 401*0b57cec5SDimitry Andric return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len); 402*0b57cec5SDimitry Andric } 403*0b57cec5SDimitry Andric return PrintfSpecifierResult(Start, FS); 404*0b57cec5SDimitry Andric } 405*0b57cec5SDimitry Andric 406*0b57cec5SDimitry Andric bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, 407*0b57cec5SDimitry Andric const char *I, 408*0b57cec5SDimitry Andric const char *E, 409*0b57cec5SDimitry Andric const LangOptions &LO, 410*0b57cec5SDimitry Andric const TargetInfo &Target, 411*0b57cec5SDimitry Andric bool isFreeBSDKPrintf) { 412*0b57cec5SDimitry Andric 413*0b57cec5SDimitry Andric unsigned argIndex = 0; 414*0b57cec5SDimitry Andric 415*0b57cec5SDimitry Andric // Keep looking for a format specifier until we have exhausted the string. 416*0b57cec5SDimitry Andric while (I != E) { 417*0b57cec5SDimitry Andric const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, 418*0b57cec5SDimitry Andric LO, Target, true, 419*0b57cec5SDimitry Andric isFreeBSDKPrintf); 420*0b57cec5SDimitry Andric // Did a fail-stop error of any kind occur when parsing the specifier? 421*0b57cec5SDimitry Andric // If so, don't do any more processing. 422*0b57cec5SDimitry Andric if (FSR.shouldStop()) 423*0b57cec5SDimitry Andric return true; 424*0b57cec5SDimitry Andric // Did we exhaust the string or encounter an error that 425*0b57cec5SDimitry Andric // we can recover from? 426*0b57cec5SDimitry Andric if (!FSR.hasValue()) 427*0b57cec5SDimitry Andric continue; 428*0b57cec5SDimitry Andric // We have a format specifier. Pass it to the callback. 429*0b57cec5SDimitry Andric if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(), 430*0b57cec5SDimitry Andric I - FSR.getStart())) 431*0b57cec5SDimitry Andric return true; 432*0b57cec5SDimitry Andric } 433*0b57cec5SDimitry Andric assert(I == E && "Format string not exhausted"); 434*0b57cec5SDimitry Andric return false; 435*0b57cec5SDimitry Andric } 436*0b57cec5SDimitry Andric 437*0b57cec5SDimitry Andric bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I, 438*0b57cec5SDimitry Andric const char *E, 439*0b57cec5SDimitry Andric const LangOptions &LO, 440*0b57cec5SDimitry Andric const TargetInfo &Target) { 441*0b57cec5SDimitry Andric 442*0b57cec5SDimitry Andric unsigned argIndex = 0; 443*0b57cec5SDimitry Andric 444*0b57cec5SDimitry Andric // Keep looking for a %s format specifier until we have exhausted the string. 445*0b57cec5SDimitry Andric FormatStringHandler H; 446*0b57cec5SDimitry Andric while (I != E) { 447*0b57cec5SDimitry Andric const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, 448*0b57cec5SDimitry Andric LO, Target, false, 449*0b57cec5SDimitry Andric false); 450*0b57cec5SDimitry Andric // Did a fail-stop error of any kind occur when parsing the specifier? 451*0b57cec5SDimitry Andric // If so, don't do any more processing. 452*0b57cec5SDimitry Andric if (FSR.shouldStop()) 453*0b57cec5SDimitry Andric return false; 454*0b57cec5SDimitry Andric // Did we exhaust the string or encounter an error that 455*0b57cec5SDimitry Andric // we can recover from? 456*0b57cec5SDimitry Andric if (!FSR.hasValue()) 457*0b57cec5SDimitry Andric continue; 458*0b57cec5SDimitry Andric const analyze_printf::PrintfSpecifier &FS = FSR.getValue(); 459*0b57cec5SDimitry Andric // Return true if this a %s format specifier. 460*0b57cec5SDimitry Andric if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg) 461*0b57cec5SDimitry Andric return true; 462*0b57cec5SDimitry Andric } 463*0b57cec5SDimitry Andric return false; 464*0b57cec5SDimitry Andric } 465*0b57cec5SDimitry Andric 466*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 467*0b57cec5SDimitry Andric // Methods on PrintfSpecifier. 468*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 469*0b57cec5SDimitry Andric 470*0b57cec5SDimitry Andric ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, 471*0b57cec5SDimitry Andric bool IsObjCLiteral) const { 472*0b57cec5SDimitry Andric if (CS.getKind() == ConversionSpecifier::cArg) 473*0b57cec5SDimitry Andric switch (LM.getKind()) { 474*0b57cec5SDimitry Andric case LengthModifier::None: 475*0b57cec5SDimitry Andric return Ctx.IntTy; 476*0b57cec5SDimitry Andric case LengthModifier::AsLong: 477*0b57cec5SDimitry Andric case LengthModifier::AsWide: 478*0b57cec5SDimitry Andric return ArgType(ArgType::WIntTy, "wint_t"); 479*0b57cec5SDimitry Andric case LengthModifier::AsShort: 480*0b57cec5SDimitry Andric if (Ctx.getTargetInfo().getTriple().isOSMSVCRT()) 481*0b57cec5SDimitry Andric return Ctx.IntTy; 482*0b57cec5SDimitry Andric LLVM_FALLTHROUGH; 483*0b57cec5SDimitry Andric default: 484*0b57cec5SDimitry Andric return ArgType::Invalid(); 485*0b57cec5SDimitry Andric } 486*0b57cec5SDimitry Andric 487*0b57cec5SDimitry Andric if (CS.isIntArg()) 488*0b57cec5SDimitry Andric switch (LM.getKind()) { 489*0b57cec5SDimitry Andric case LengthModifier::AsLongDouble: 490*0b57cec5SDimitry Andric // GNU extension. 491*0b57cec5SDimitry Andric return Ctx.LongLongTy; 492*0b57cec5SDimitry Andric case LengthModifier::None: 493*0b57cec5SDimitry Andric case LengthModifier::AsShortLong: 494*0b57cec5SDimitry Andric return Ctx.IntTy; 495*0b57cec5SDimitry Andric case LengthModifier::AsInt32: 496*0b57cec5SDimitry Andric return ArgType(Ctx.IntTy, "__int32"); 497*0b57cec5SDimitry Andric case LengthModifier::AsChar: 498*0b57cec5SDimitry Andric return ArgType::AnyCharTy; 499*0b57cec5SDimitry Andric case LengthModifier::AsShort: return Ctx.ShortTy; 500*0b57cec5SDimitry Andric case LengthModifier::AsLong: return Ctx.LongTy; 501*0b57cec5SDimitry Andric case LengthModifier::AsLongLong: 502*0b57cec5SDimitry Andric case LengthModifier::AsQuad: 503*0b57cec5SDimitry Andric return Ctx.LongLongTy; 504*0b57cec5SDimitry Andric case LengthModifier::AsInt64: 505*0b57cec5SDimitry Andric return ArgType(Ctx.LongLongTy, "__int64"); 506*0b57cec5SDimitry Andric case LengthModifier::AsIntMax: 507*0b57cec5SDimitry Andric return ArgType(Ctx.getIntMaxType(), "intmax_t"); 508*0b57cec5SDimitry Andric case LengthModifier::AsSizeT: 509*0b57cec5SDimitry Andric return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(), "ssize_t")); 510*0b57cec5SDimitry Andric case LengthModifier::AsInt3264: 511*0b57cec5SDimitry Andric return Ctx.getTargetInfo().getTriple().isArch64Bit() 512*0b57cec5SDimitry Andric ? ArgType(Ctx.LongLongTy, "__int64") 513*0b57cec5SDimitry Andric : ArgType(Ctx.IntTy, "__int32"); 514*0b57cec5SDimitry Andric case LengthModifier::AsPtrDiff: 515*0b57cec5SDimitry Andric return ArgType::makePtrdiffT( 516*0b57cec5SDimitry Andric ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); 517*0b57cec5SDimitry Andric case LengthModifier::AsAllocate: 518*0b57cec5SDimitry Andric case LengthModifier::AsMAllocate: 519*0b57cec5SDimitry Andric case LengthModifier::AsWide: 520*0b57cec5SDimitry Andric return ArgType::Invalid(); 521*0b57cec5SDimitry Andric } 522*0b57cec5SDimitry Andric 523*0b57cec5SDimitry Andric if (CS.isUIntArg()) 524*0b57cec5SDimitry Andric switch (LM.getKind()) { 525*0b57cec5SDimitry Andric case LengthModifier::AsLongDouble: 526*0b57cec5SDimitry Andric // GNU extension. 527*0b57cec5SDimitry Andric return Ctx.UnsignedLongLongTy; 528*0b57cec5SDimitry Andric case LengthModifier::None: 529*0b57cec5SDimitry Andric case LengthModifier::AsShortLong: 530*0b57cec5SDimitry Andric return Ctx.UnsignedIntTy; 531*0b57cec5SDimitry Andric case LengthModifier::AsInt32: 532*0b57cec5SDimitry Andric return ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); 533*0b57cec5SDimitry Andric case LengthModifier::AsChar: return Ctx.UnsignedCharTy; 534*0b57cec5SDimitry Andric case LengthModifier::AsShort: return Ctx.UnsignedShortTy; 535*0b57cec5SDimitry Andric case LengthModifier::AsLong: return Ctx.UnsignedLongTy; 536*0b57cec5SDimitry Andric case LengthModifier::AsLongLong: 537*0b57cec5SDimitry Andric case LengthModifier::AsQuad: 538*0b57cec5SDimitry Andric return Ctx.UnsignedLongLongTy; 539*0b57cec5SDimitry Andric case LengthModifier::AsInt64: 540*0b57cec5SDimitry Andric return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"); 541*0b57cec5SDimitry Andric case LengthModifier::AsIntMax: 542*0b57cec5SDimitry Andric return ArgType(Ctx.getUIntMaxType(), "uintmax_t"); 543*0b57cec5SDimitry Andric case LengthModifier::AsSizeT: 544*0b57cec5SDimitry Andric return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t")); 545*0b57cec5SDimitry Andric case LengthModifier::AsInt3264: 546*0b57cec5SDimitry Andric return Ctx.getTargetInfo().getTriple().isArch64Bit() 547*0b57cec5SDimitry Andric ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64") 548*0b57cec5SDimitry Andric : ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); 549*0b57cec5SDimitry Andric case LengthModifier::AsPtrDiff: 550*0b57cec5SDimitry Andric return ArgType::makePtrdiffT( 551*0b57cec5SDimitry Andric ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t")); 552*0b57cec5SDimitry Andric case LengthModifier::AsAllocate: 553*0b57cec5SDimitry Andric case LengthModifier::AsMAllocate: 554*0b57cec5SDimitry Andric case LengthModifier::AsWide: 555*0b57cec5SDimitry Andric return ArgType::Invalid(); 556*0b57cec5SDimitry Andric } 557*0b57cec5SDimitry Andric 558*0b57cec5SDimitry Andric if (CS.isDoubleArg()) { 559*0b57cec5SDimitry Andric if (!VectorNumElts.isInvalid()) { 560*0b57cec5SDimitry Andric switch (LM.getKind()) { 561*0b57cec5SDimitry Andric case LengthModifier::AsShort: 562*0b57cec5SDimitry Andric return Ctx.HalfTy; 563*0b57cec5SDimitry Andric case LengthModifier::AsShortLong: 564*0b57cec5SDimitry Andric return Ctx.FloatTy; 565*0b57cec5SDimitry Andric case LengthModifier::AsLong: 566*0b57cec5SDimitry Andric default: 567*0b57cec5SDimitry Andric return Ctx.DoubleTy; 568*0b57cec5SDimitry Andric } 569*0b57cec5SDimitry Andric } 570*0b57cec5SDimitry Andric 571*0b57cec5SDimitry Andric if (LM.getKind() == LengthModifier::AsLongDouble) 572*0b57cec5SDimitry Andric return Ctx.LongDoubleTy; 573*0b57cec5SDimitry Andric return Ctx.DoubleTy; 574*0b57cec5SDimitry Andric } 575*0b57cec5SDimitry Andric 576*0b57cec5SDimitry Andric if (CS.getKind() == ConversionSpecifier::nArg) { 577*0b57cec5SDimitry Andric switch (LM.getKind()) { 578*0b57cec5SDimitry Andric case LengthModifier::None: 579*0b57cec5SDimitry Andric return ArgType::PtrTo(Ctx.IntTy); 580*0b57cec5SDimitry Andric case LengthModifier::AsChar: 581*0b57cec5SDimitry Andric return ArgType::PtrTo(Ctx.SignedCharTy); 582*0b57cec5SDimitry Andric case LengthModifier::AsShort: 583*0b57cec5SDimitry Andric return ArgType::PtrTo(Ctx.ShortTy); 584*0b57cec5SDimitry Andric case LengthModifier::AsLong: 585*0b57cec5SDimitry Andric return ArgType::PtrTo(Ctx.LongTy); 586*0b57cec5SDimitry Andric case LengthModifier::AsLongLong: 587*0b57cec5SDimitry Andric case LengthModifier::AsQuad: 588*0b57cec5SDimitry Andric return ArgType::PtrTo(Ctx.LongLongTy); 589*0b57cec5SDimitry Andric case LengthModifier::AsIntMax: 590*0b57cec5SDimitry Andric return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); 591*0b57cec5SDimitry Andric case LengthModifier::AsSizeT: 592*0b57cec5SDimitry Andric return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t")); 593*0b57cec5SDimitry Andric case LengthModifier::AsPtrDiff: 594*0b57cec5SDimitry Andric return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); 595*0b57cec5SDimitry Andric case LengthModifier::AsLongDouble: 596*0b57cec5SDimitry Andric return ArgType(); // FIXME: Is this a known extension? 597*0b57cec5SDimitry Andric case LengthModifier::AsAllocate: 598*0b57cec5SDimitry Andric case LengthModifier::AsMAllocate: 599*0b57cec5SDimitry Andric case LengthModifier::AsInt32: 600*0b57cec5SDimitry Andric case LengthModifier::AsInt3264: 601*0b57cec5SDimitry Andric case LengthModifier::AsInt64: 602*0b57cec5SDimitry Andric case LengthModifier::AsWide: 603*0b57cec5SDimitry Andric return ArgType::Invalid(); 604*0b57cec5SDimitry Andric case LengthModifier::AsShortLong: 605*0b57cec5SDimitry Andric llvm_unreachable("only used for OpenCL which doesn not handle nArg"); 606*0b57cec5SDimitry Andric } 607*0b57cec5SDimitry Andric } 608*0b57cec5SDimitry Andric 609*0b57cec5SDimitry Andric switch (CS.getKind()) { 610*0b57cec5SDimitry Andric case ConversionSpecifier::sArg: 611*0b57cec5SDimitry Andric if (LM.getKind() == LengthModifier::AsWideChar) { 612*0b57cec5SDimitry Andric if (IsObjCLiteral) 613*0b57cec5SDimitry Andric return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), 614*0b57cec5SDimitry Andric "const unichar *"); 615*0b57cec5SDimitry Andric return ArgType(ArgType::WCStrTy, "wchar_t *"); 616*0b57cec5SDimitry Andric } 617*0b57cec5SDimitry Andric if (LM.getKind() == LengthModifier::AsWide) 618*0b57cec5SDimitry Andric return ArgType(ArgType::WCStrTy, "wchar_t *"); 619*0b57cec5SDimitry Andric return ArgType::CStrTy; 620*0b57cec5SDimitry Andric case ConversionSpecifier::SArg: 621*0b57cec5SDimitry Andric if (IsObjCLiteral) 622*0b57cec5SDimitry Andric return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), 623*0b57cec5SDimitry Andric "const unichar *"); 624*0b57cec5SDimitry Andric if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() && 625*0b57cec5SDimitry Andric LM.getKind() == LengthModifier::AsShort) 626*0b57cec5SDimitry Andric return ArgType::CStrTy; 627*0b57cec5SDimitry Andric return ArgType(ArgType::WCStrTy, "wchar_t *"); 628*0b57cec5SDimitry Andric case ConversionSpecifier::CArg: 629*0b57cec5SDimitry Andric if (IsObjCLiteral) 630*0b57cec5SDimitry Andric return ArgType(Ctx.UnsignedShortTy, "unichar"); 631*0b57cec5SDimitry Andric if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() && 632*0b57cec5SDimitry Andric LM.getKind() == LengthModifier::AsShort) 633*0b57cec5SDimitry Andric return Ctx.IntTy; 634*0b57cec5SDimitry Andric return ArgType(Ctx.WideCharTy, "wchar_t"); 635*0b57cec5SDimitry Andric case ConversionSpecifier::pArg: 636*0b57cec5SDimitry Andric case ConversionSpecifier::PArg: 637*0b57cec5SDimitry Andric return ArgType::CPointerTy; 638*0b57cec5SDimitry Andric case ConversionSpecifier::ObjCObjArg: 639*0b57cec5SDimitry Andric return ArgType::ObjCPointerTy; 640*0b57cec5SDimitry Andric default: 641*0b57cec5SDimitry Andric break; 642*0b57cec5SDimitry Andric } 643*0b57cec5SDimitry Andric 644*0b57cec5SDimitry Andric // FIXME: Handle other cases. 645*0b57cec5SDimitry Andric return ArgType(); 646*0b57cec5SDimitry Andric } 647*0b57cec5SDimitry Andric 648*0b57cec5SDimitry Andric 649*0b57cec5SDimitry Andric ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, 650*0b57cec5SDimitry Andric bool IsObjCLiteral) const { 651*0b57cec5SDimitry Andric const PrintfConversionSpecifier &CS = getConversionSpecifier(); 652*0b57cec5SDimitry Andric 653*0b57cec5SDimitry Andric if (!CS.consumesDataArgument()) 654*0b57cec5SDimitry Andric return ArgType::Invalid(); 655*0b57cec5SDimitry Andric 656*0b57cec5SDimitry Andric ArgType ScalarTy = getScalarArgType(Ctx, IsObjCLiteral); 657*0b57cec5SDimitry Andric if (!ScalarTy.isValid() || VectorNumElts.isInvalid()) 658*0b57cec5SDimitry Andric return ScalarTy; 659*0b57cec5SDimitry Andric 660*0b57cec5SDimitry Andric return ScalarTy.makeVectorType(Ctx, VectorNumElts.getConstantAmount()); 661*0b57cec5SDimitry Andric } 662*0b57cec5SDimitry Andric 663*0b57cec5SDimitry Andric bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, 664*0b57cec5SDimitry Andric ASTContext &Ctx, bool IsObjCLiteral) { 665*0b57cec5SDimitry Andric // %n is different from other conversion specifiers; don't try to fix it. 666*0b57cec5SDimitry Andric if (CS.getKind() == ConversionSpecifier::nArg) 667*0b57cec5SDimitry Andric return false; 668*0b57cec5SDimitry Andric 669*0b57cec5SDimitry Andric // Handle Objective-C objects first. Note that while the '%@' specifier will 670*0b57cec5SDimitry Andric // not warn for structure pointer or void pointer arguments (because that's 671*0b57cec5SDimitry Andric // how CoreFoundation objects are implemented), we only show a fixit for '%@' 672*0b57cec5SDimitry Andric // if we know it's an object (block, id, class, or __attribute__((NSObject))). 673*0b57cec5SDimitry Andric if (QT->isObjCRetainableType()) { 674*0b57cec5SDimitry Andric if (!IsObjCLiteral) 675*0b57cec5SDimitry Andric return false; 676*0b57cec5SDimitry Andric 677*0b57cec5SDimitry Andric CS.setKind(ConversionSpecifier::ObjCObjArg); 678*0b57cec5SDimitry Andric 679*0b57cec5SDimitry Andric // Disable irrelevant flags 680*0b57cec5SDimitry Andric HasThousandsGrouping = false; 681*0b57cec5SDimitry Andric HasPlusPrefix = false; 682*0b57cec5SDimitry Andric HasSpacePrefix = false; 683*0b57cec5SDimitry Andric HasAlternativeForm = false; 684*0b57cec5SDimitry Andric HasLeadingZeroes = false; 685*0b57cec5SDimitry Andric Precision.setHowSpecified(OptionalAmount::NotSpecified); 686*0b57cec5SDimitry Andric LM.setKind(LengthModifier::None); 687*0b57cec5SDimitry Andric 688*0b57cec5SDimitry Andric return true; 689*0b57cec5SDimitry Andric } 690*0b57cec5SDimitry Andric 691*0b57cec5SDimitry Andric // Handle strings next (char *, wchar_t *) 692*0b57cec5SDimitry Andric if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { 693*0b57cec5SDimitry Andric CS.setKind(ConversionSpecifier::sArg); 694*0b57cec5SDimitry Andric 695*0b57cec5SDimitry Andric // Disable irrelevant flags 696*0b57cec5SDimitry Andric HasAlternativeForm = 0; 697*0b57cec5SDimitry Andric HasLeadingZeroes = 0; 698*0b57cec5SDimitry Andric 699*0b57cec5SDimitry Andric // Set the long length modifier for wide characters 700*0b57cec5SDimitry Andric if (QT->getPointeeType()->isWideCharType()) 701*0b57cec5SDimitry Andric LM.setKind(LengthModifier::AsWideChar); 702*0b57cec5SDimitry Andric else 703*0b57cec5SDimitry Andric LM.setKind(LengthModifier::None); 704*0b57cec5SDimitry Andric 705*0b57cec5SDimitry Andric return true; 706*0b57cec5SDimitry Andric } 707*0b57cec5SDimitry Andric 708*0b57cec5SDimitry Andric // If it's an enum, get its underlying type. 709*0b57cec5SDimitry Andric if (const EnumType *ETy = QT->getAs<EnumType>()) 710*0b57cec5SDimitry Andric QT = ETy->getDecl()->getIntegerType(); 711*0b57cec5SDimitry Andric 712*0b57cec5SDimitry Andric const BuiltinType *BT = QT->getAs<BuiltinType>(); 713*0b57cec5SDimitry Andric if (!BT) { 714*0b57cec5SDimitry Andric const VectorType *VT = QT->getAs<VectorType>(); 715*0b57cec5SDimitry Andric if (VT) { 716*0b57cec5SDimitry Andric QT = VT->getElementType(); 717*0b57cec5SDimitry Andric BT = QT->getAs<BuiltinType>(); 718*0b57cec5SDimitry Andric VectorNumElts = OptionalAmount(VT->getNumElements()); 719*0b57cec5SDimitry Andric } 720*0b57cec5SDimitry Andric } 721*0b57cec5SDimitry Andric 722*0b57cec5SDimitry Andric // We can only work with builtin types. 723*0b57cec5SDimitry Andric if (!BT) 724*0b57cec5SDimitry Andric return false; 725*0b57cec5SDimitry Andric 726*0b57cec5SDimitry Andric // Set length modifier 727*0b57cec5SDimitry Andric switch (BT->getKind()) { 728*0b57cec5SDimitry Andric case BuiltinType::Bool: 729*0b57cec5SDimitry Andric case BuiltinType::WChar_U: 730*0b57cec5SDimitry Andric case BuiltinType::WChar_S: 731*0b57cec5SDimitry Andric case BuiltinType::Char8: // FIXME: Treat like 'char'? 732*0b57cec5SDimitry Andric case BuiltinType::Char16: 733*0b57cec5SDimitry Andric case BuiltinType::Char32: 734*0b57cec5SDimitry Andric case BuiltinType::UInt128: 735*0b57cec5SDimitry Andric case BuiltinType::Int128: 736*0b57cec5SDimitry Andric case BuiltinType::Half: 737*0b57cec5SDimitry Andric case BuiltinType::Float16: 738*0b57cec5SDimitry Andric case BuiltinType::Float128: 739*0b57cec5SDimitry Andric case BuiltinType::ShortAccum: 740*0b57cec5SDimitry Andric case BuiltinType::Accum: 741*0b57cec5SDimitry Andric case BuiltinType::LongAccum: 742*0b57cec5SDimitry Andric case BuiltinType::UShortAccum: 743*0b57cec5SDimitry Andric case BuiltinType::UAccum: 744*0b57cec5SDimitry Andric case BuiltinType::ULongAccum: 745*0b57cec5SDimitry Andric case BuiltinType::ShortFract: 746*0b57cec5SDimitry Andric case BuiltinType::Fract: 747*0b57cec5SDimitry Andric case BuiltinType::LongFract: 748*0b57cec5SDimitry Andric case BuiltinType::UShortFract: 749*0b57cec5SDimitry Andric case BuiltinType::UFract: 750*0b57cec5SDimitry Andric case BuiltinType::ULongFract: 751*0b57cec5SDimitry Andric case BuiltinType::SatShortAccum: 752*0b57cec5SDimitry Andric case BuiltinType::SatAccum: 753*0b57cec5SDimitry Andric case BuiltinType::SatLongAccum: 754*0b57cec5SDimitry Andric case BuiltinType::SatUShortAccum: 755*0b57cec5SDimitry Andric case BuiltinType::SatUAccum: 756*0b57cec5SDimitry Andric case BuiltinType::SatULongAccum: 757*0b57cec5SDimitry Andric case BuiltinType::SatShortFract: 758*0b57cec5SDimitry Andric case BuiltinType::SatFract: 759*0b57cec5SDimitry Andric case BuiltinType::SatLongFract: 760*0b57cec5SDimitry Andric case BuiltinType::SatUShortFract: 761*0b57cec5SDimitry Andric case BuiltinType::SatUFract: 762*0b57cec5SDimitry Andric case BuiltinType::SatULongFract: 763*0b57cec5SDimitry Andric // Various types which are non-trivial to correct. 764*0b57cec5SDimitry Andric return false; 765*0b57cec5SDimitry Andric 766*0b57cec5SDimitry Andric #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ 767*0b57cec5SDimitry Andric case BuiltinType::Id: 768*0b57cec5SDimitry Andric #include "clang/Basic/OpenCLImageTypes.def" 769*0b57cec5SDimitry Andric #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ 770*0b57cec5SDimitry Andric case BuiltinType::Id: 771*0b57cec5SDimitry Andric #include "clang/Basic/OpenCLExtensionTypes.def" 772*0b57cec5SDimitry Andric #define SIGNED_TYPE(Id, SingletonId) 773*0b57cec5SDimitry Andric #define UNSIGNED_TYPE(Id, SingletonId) 774*0b57cec5SDimitry Andric #define FLOATING_TYPE(Id, SingletonId) 775*0b57cec5SDimitry Andric #define BUILTIN_TYPE(Id, SingletonId) \ 776*0b57cec5SDimitry Andric case BuiltinType::Id: 777*0b57cec5SDimitry Andric #include "clang/AST/BuiltinTypes.def" 778*0b57cec5SDimitry Andric // Misc other stuff which doesn't make sense here. 779*0b57cec5SDimitry Andric return false; 780*0b57cec5SDimitry Andric 781*0b57cec5SDimitry Andric case BuiltinType::UInt: 782*0b57cec5SDimitry Andric case BuiltinType::Int: 783*0b57cec5SDimitry Andric case BuiltinType::Float: 784*0b57cec5SDimitry Andric LM.setKind(VectorNumElts.isInvalid() ? 785*0b57cec5SDimitry Andric LengthModifier::None : LengthModifier::AsShortLong); 786*0b57cec5SDimitry Andric break; 787*0b57cec5SDimitry Andric case BuiltinType::Double: 788*0b57cec5SDimitry Andric LM.setKind(VectorNumElts.isInvalid() ? 789*0b57cec5SDimitry Andric LengthModifier::None : LengthModifier::AsLong); 790*0b57cec5SDimitry Andric break; 791*0b57cec5SDimitry Andric case BuiltinType::Char_U: 792*0b57cec5SDimitry Andric case BuiltinType::UChar: 793*0b57cec5SDimitry Andric case BuiltinType::Char_S: 794*0b57cec5SDimitry Andric case BuiltinType::SChar: 795*0b57cec5SDimitry Andric LM.setKind(LengthModifier::AsChar); 796*0b57cec5SDimitry Andric break; 797*0b57cec5SDimitry Andric 798*0b57cec5SDimitry Andric case BuiltinType::Short: 799*0b57cec5SDimitry Andric case BuiltinType::UShort: 800*0b57cec5SDimitry Andric LM.setKind(LengthModifier::AsShort); 801*0b57cec5SDimitry Andric break; 802*0b57cec5SDimitry Andric 803*0b57cec5SDimitry Andric case BuiltinType::Long: 804*0b57cec5SDimitry Andric case BuiltinType::ULong: 805*0b57cec5SDimitry Andric LM.setKind(LengthModifier::AsLong); 806*0b57cec5SDimitry Andric break; 807*0b57cec5SDimitry Andric 808*0b57cec5SDimitry Andric case BuiltinType::LongLong: 809*0b57cec5SDimitry Andric case BuiltinType::ULongLong: 810*0b57cec5SDimitry Andric LM.setKind(LengthModifier::AsLongLong); 811*0b57cec5SDimitry Andric break; 812*0b57cec5SDimitry Andric 813*0b57cec5SDimitry Andric case BuiltinType::LongDouble: 814*0b57cec5SDimitry Andric LM.setKind(LengthModifier::AsLongDouble); 815*0b57cec5SDimitry Andric break; 816*0b57cec5SDimitry Andric } 817*0b57cec5SDimitry Andric 818*0b57cec5SDimitry Andric // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. 819*0b57cec5SDimitry Andric if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11)) 820*0b57cec5SDimitry Andric namedTypeToLengthModifier(QT, LM); 821*0b57cec5SDimitry Andric 822*0b57cec5SDimitry Andric // If fixing the length modifier was enough, we might be done. 823*0b57cec5SDimitry Andric if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) { 824*0b57cec5SDimitry Andric // If we're going to offer a fix anyway, make sure the sign matches. 825*0b57cec5SDimitry Andric switch (CS.getKind()) { 826*0b57cec5SDimitry Andric case ConversionSpecifier::uArg: 827*0b57cec5SDimitry Andric case ConversionSpecifier::UArg: 828*0b57cec5SDimitry Andric if (QT->isSignedIntegerType()) 829*0b57cec5SDimitry Andric CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg); 830*0b57cec5SDimitry Andric break; 831*0b57cec5SDimitry Andric case ConversionSpecifier::dArg: 832*0b57cec5SDimitry Andric case ConversionSpecifier::DArg: 833*0b57cec5SDimitry Andric case ConversionSpecifier::iArg: 834*0b57cec5SDimitry Andric if (QT->isUnsignedIntegerType() && !HasPlusPrefix) 835*0b57cec5SDimitry Andric CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg); 836*0b57cec5SDimitry Andric break; 837*0b57cec5SDimitry Andric default: 838*0b57cec5SDimitry Andric // Other specifiers do not have signed/unsigned variants. 839*0b57cec5SDimitry Andric break; 840*0b57cec5SDimitry Andric } 841*0b57cec5SDimitry Andric 842*0b57cec5SDimitry Andric const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral); 843*0b57cec5SDimitry Andric if (ATR.isValid() && ATR.matchesType(Ctx, QT)) 844*0b57cec5SDimitry Andric return true; 845*0b57cec5SDimitry Andric } 846*0b57cec5SDimitry Andric 847*0b57cec5SDimitry Andric // Set conversion specifier and disable any flags which do not apply to it. 848*0b57cec5SDimitry Andric // Let typedefs to char fall through to int, as %c is silly for uint8_t. 849*0b57cec5SDimitry Andric if (!isa<TypedefType>(QT) && QT->isCharType()) { 850*0b57cec5SDimitry Andric CS.setKind(ConversionSpecifier::cArg); 851*0b57cec5SDimitry Andric LM.setKind(LengthModifier::None); 852*0b57cec5SDimitry Andric Precision.setHowSpecified(OptionalAmount::NotSpecified); 853*0b57cec5SDimitry Andric HasAlternativeForm = 0; 854*0b57cec5SDimitry Andric HasLeadingZeroes = 0; 855*0b57cec5SDimitry Andric HasPlusPrefix = 0; 856*0b57cec5SDimitry Andric } 857*0b57cec5SDimitry Andric // Test for Floating type first as LongDouble can pass isUnsignedIntegerType 858*0b57cec5SDimitry Andric else if (QT->isRealFloatingType()) { 859*0b57cec5SDimitry Andric CS.setKind(ConversionSpecifier::fArg); 860*0b57cec5SDimitry Andric } 861*0b57cec5SDimitry Andric else if (QT->isSignedIntegerType()) { 862*0b57cec5SDimitry Andric CS.setKind(ConversionSpecifier::dArg); 863*0b57cec5SDimitry Andric HasAlternativeForm = 0; 864*0b57cec5SDimitry Andric } 865*0b57cec5SDimitry Andric else if (QT->isUnsignedIntegerType()) { 866*0b57cec5SDimitry Andric CS.setKind(ConversionSpecifier::uArg); 867*0b57cec5SDimitry Andric HasAlternativeForm = 0; 868*0b57cec5SDimitry Andric HasPlusPrefix = 0; 869*0b57cec5SDimitry Andric } else { 870*0b57cec5SDimitry Andric llvm_unreachable("Unexpected type"); 871*0b57cec5SDimitry Andric } 872*0b57cec5SDimitry Andric 873*0b57cec5SDimitry Andric return true; 874*0b57cec5SDimitry Andric } 875*0b57cec5SDimitry Andric 876*0b57cec5SDimitry Andric void PrintfSpecifier::toString(raw_ostream &os) const { 877*0b57cec5SDimitry Andric // Whilst some features have no defined order, we are using the order 878*0b57cec5SDimitry Andric // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1) 879*0b57cec5SDimitry Andric os << "%"; 880*0b57cec5SDimitry Andric 881*0b57cec5SDimitry Andric // Positional args 882*0b57cec5SDimitry Andric if (usesPositionalArg()) { 883*0b57cec5SDimitry Andric os << getPositionalArgIndex() << "$"; 884*0b57cec5SDimitry Andric } 885*0b57cec5SDimitry Andric 886*0b57cec5SDimitry Andric // Conversion flags 887*0b57cec5SDimitry Andric if (IsLeftJustified) os << "-"; 888*0b57cec5SDimitry Andric if (HasPlusPrefix) os << "+"; 889*0b57cec5SDimitry Andric if (HasSpacePrefix) os << " "; 890*0b57cec5SDimitry Andric if (HasAlternativeForm) os << "#"; 891*0b57cec5SDimitry Andric if (HasLeadingZeroes) os << "0"; 892*0b57cec5SDimitry Andric 893*0b57cec5SDimitry Andric // Minimum field width 894*0b57cec5SDimitry Andric FieldWidth.toString(os); 895*0b57cec5SDimitry Andric // Precision 896*0b57cec5SDimitry Andric Precision.toString(os); 897*0b57cec5SDimitry Andric 898*0b57cec5SDimitry Andric // Vector modifier 899*0b57cec5SDimitry Andric if (!VectorNumElts.isInvalid()) 900*0b57cec5SDimitry Andric os << 'v' << VectorNumElts.getConstantAmount(); 901*0b57cec5SDimitry Andric 902*0b57cec5SDimitry Andric // Length modifier 903*0b57cec5SDimitry Andric os << LM.toString(); 904*0b57cec5SDimitry Andric // Conversion specifier 905*0b57cec5SDimitry Andric os << CS.toString(); 906*0b57cec5SDimitry Andric } 907*0b57cec5SDimitry Andric 908*0b57cec5SDimitry Andric bool PrintfSpecifier::hasValidPlusPrefix() const { 909*0b57cec5SDimitry Andric if (!HasPlusPrefix) 910*0b57cec5SDimitry Andric return true; 911*0b57cec5SDimitry Andric 912*0b57cec5SDimitry Andric // The plus prefix only makes sense for signed conversions 913*0b57cec5SDimitry Andric switch (CS.getKind()) { 914*0b57cec5SDimitry Andric case ConversionSpecifier::dArg: 915*0b57cec5SDimitry Andric case ConversionSpecifier::DArg: 916*0b57cec5SDimitry Andric case ConversionSpecifier::iArg: 917*0b57cec5SDimitry Andric case ConversionSpecifier::fArg: 918*0b57cec5SDimitry Andric case ConversionSpecifier::FArg: 919*0b57cec5SDimitry Andric case ConversionSpecifier::eArg: 920*0b57cec5SDimitry Andric case ConversionSpecifier::EArg: 921*0b57cec5SDimitry Andric case ConversionSpecifier::gArg: 922*0b57cec5SDimitry Andric case ConversionSpecifier::GArg: 923*0b57cec5SDimitry Andric case ConversionSpecifier::aArg: 924*0b57cec5SDimitry Andric case ConversionSpecifier::AArg: 925*0b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDrArg: 926*0b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDyArg: 927*0b57cec5SDimitry Andric return true; 928*0b57cec5SDimitry Andric 929*0b57cec5SDimitry Andric default: 930*0b57cec5SDimitry Andric return false; 931*0b57cec5SDimitry Andric } 932*0b57cec5SDimitry Andric } 933*0b57cec5SDimitry Andric 934*0b57cec5SDimitry Andric bool PrintfSpecifier::hasValidAlternativeForm() const { 935*0b57cec5SDimitry Andric if (!HasAlternativeForm) 936*0b57cec5SDimitry Andric return true; 937*0b57cec5SDimitry Andric 938*0b57cec5SDimitry Andric // Alternate form flag only valid with the oxXaAeEfFgG conversions 939*0b57cec5SDimitry Andric switch (CS.getKind()) { 940*0b57cec5SDimitry Andric case ConversionSpecifier::oArg: 941*0b57cec5SDimitry Andric case ConversionSpecifier::OArg: 942*0b57cec5SDimitry Andric case ConversionSpecifier::xArg: 943*0b57cec5SDimitry Andric case ConversionSpecifier::XArg: 944*0b57cec5SDimitry Andric case ConversionSpecifier::aArg: 945*0b57cec5SDimitry Andric case ConversionSpecifier::AArg: 946*0b57cec5SDimitry Andric case ConversionSpecifier::eArg: 947*0b57cec5SDimitry Andric case ConversionSpecifier::EArg: 948*0b57cec5SDimitry Andric case ConversionSpecifier::fArg: 949*0b57cec5SDimitry Andric case ConversionSpecifier::FArg: 950*0b57cec5SDimitry Andric case ConversionSpecifier::gArg: 951*0b57cec5SDimitry Andric case ConversionSpecifier::GArg: 952*0b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDrArg: 953*0b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDyArg: 954*0b57cec5SDimitry Andric return true; 955*0b57cec5SDimitry Andric 956*0b57cec5SDimitry Andric default: 957*0b57cec5SDimitry Andric return false; 958*0b57cec5SDimitry Andric } 959*0b57cec5SDimitry Andric } 960*0b57cec5SDimitry Andric 961*0b57cec5SDimitry Andric bool PrintfSpecifier::hasValidLeadingZeros() const { 962*0b57cec5SDimitry Andric if (!HasLeadingZeroes) 963*0b57cec5SDimitry Andric return true; 964*0b57cec5SDimitry Andric 965*0b57cec5SDimitry Andric // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions 966*0b57cec5SDimitry Andric switch (CS.getKind()) { 967*0b57cec5SDimitry Andric case ConversionSpecifier::dArg: 968*0b57cec5SDimitry Andric case ConversionSpecifier::DArg: 969*0b57cec5SDimitry Andric case ConversionSpecifier::iArg: 970*0b57cec5SDimitry Andric case ConversionSpecifier::oArg: 971*0b57cec5SDimitry Andric case ConversionSpecifier::OArg: 972*0b57cec5SDimitry Andric case ConversionSpecifier::uArg: 973*0b57cec5SDimitry Andric case ConversionSpecifier::UArg: 974*0b57cec5SDimitry Andric case ConversionSpecifier::xArg: 975*0b57cec5SDimitry Andric case ConversionSpecifier::XArg: 976*0b57cec5SDimitry Andric case ConversionSpecifier::aArg: 977*0b57cec5SDimitry Andric case ConversionSpecifier::AArg: 978*0b57cec5SDimitry Andric case ConversionSpecifier::eArg: 979*0b57cec5SDimitry Andric case ConversionSpecifier::EArg: 980*0b57cec5SDimitry Andric case ConversionSpecifier::fArg: 981*0b57cec5SDimitry Andric case ConversionSpecifier::FArg: 982*0b57cec5SDimitry Andric case ConversionSpecifier::gArg: 983*0b57cec5SDimitry Andric case ConversionSpecifier::GArg: 984*0b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDrArg: 985*0b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDyArg: 986*0b57cec5SDimitry Andric return true; 987*0b57cec5SDimitry Andric 988*0b57cec5SDimitry Andric default: 989*0b57cec5SDimitry Andric return false; 990*0b57cec5SDimitry Andric } 991*0b57cec5SDimitry Andric } 992*0b57cec5SDimitry Andric 993*0b57cec5SDimitry Andric bool PrintfSpecifier::hasValidSpacePrefix() const { 994*0b57cec5SDimitry Andric if (!HasSpacePrefix) 995*0b57cec5SDimitry Andric return true; 996*0b57cec5SDimitry Andric 997*0b57cec5SDimitry Andric // The space prefix only makes sense for signed conversions 998*0b57cec5SDimitry Andric switch (CS.getKind()) { 999*0b57cec5SDimitry Andric case ConversionSpecifier::dArg: 1000*0b57cec5SDimitry Andric case ConversionSpecifier::DArg: 1001*0b57cec5SDimitry Andric case ConversionSpecifier::iArg: 1002*0b57cec5SDimitry Andric case ConversionSpecifier::fArg: 1003*0b57cec5SDimitry Andric case ConversionSpecifier::FArg: 1004*0b57cec5SDimitry Andric case ConversionSpecifier::eArg: 1005*0b57cec5SDimitry Andric case ConversionSpecifier::EArg: 1006*0b57cec5SDimitry Andric case ConversionSpecifier::gArg: 1007*0b57cec5SDimitry Andric case ConversionSpecifier::GArg: 1008*0b57cec5SDimitry Andric case ConversionSpecifier::aArg: 1009*0b57cec5SDimitry Andric case ConversionSpecifier::AArg: 1010*0b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDrArg: 1011*0b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDyArg: 1012*0b57cec5SDimitry Andric return true; 1013*0b57cec5SDimitry Andric 1014*0b57cec5SDimitry Andric default: 1015*0b57cec5SDimitry Andric return false; 1016*0b57cec5SDimitry Andric } 1017*0b57cec5SDimitry Andric } 1018*0b57cec5SDimitry Andric 1019*0b57cec5SDimitry Andric bool PrintfSpecifier::hasValidLeftJustified() const { 1020*0b57cec5SDimitry Andric if (!IsLeftJustified) 1021*0b57cec5SDimitry Andric return true; 1022*0b57cec5SDimitry Andric 1023*0b57cec5SDimitry Andric // The left justified flag is valid for all conversions except n 1024*0b57cec5SDimitry Andric switch (CS.getKind()) { 1025*0b57cec5SDimitry Andric case ConversionSpecifier::nArg: 1026*0b57cec5SDimitry Andric return false; 1027*0b57cec5SDimitry Andric 1028*0b57cec5SDimitry Andric default: 1029*0b57cec5SDimitry Andric return true; 1030*0b57cec5SDimitry Andric } 1031*0b57cec5SDimitry Andric } 1032*0b57cec5SDimitry Andric 1033*0b57cec5SDimitry Andric bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const { 1034*0b57cec5SDimitry Andric if (!HasThousandsGrouping) 1035*0b57cec5SDimitry Andric return true; 1036*0b57cec5SDimitry Andric 1037*0b57cec5SDimitry Andric switch (CS.getKind()) { 1038*0b57cec5SDimitry Andric case ConversionSpecifier::dArg: 1039*0b57cec5SDimitry Andric case ConversionSpecifier::DArg: 1040*0b57cec5SDimitry Andric case ConversionSpecifier::iArg: 1041*0b57cec5SDimitry Andric case ConversionSpecifier::uArg: 1042*0b57cec5SDimitry Andric case ConversionSpecifier::UArg: 1043*0b57cec5SDimitry Andric case ConversionSpecifier::fArg: 1044*0b57cec5SDimitry Andric case ConversionSpecifier::FArg: 1045*0b57cec5SDimitry Andric case ConversionSpecifier::gArg: 1046*0b57cec5SDimitry Andric case ConversionSpecifier::GArg: 1047*0b57cec5SDimitry Andric return true; 1048*0b57cec5SDimitry Andric default: 1049*0b57cec5SDimitry Andric return false; 1050*0b57cec5SDimitry Andric } 1051*0b57cec5SDimitry Andric } 1052*0b57cec5SDimitry Andric 1053*0b57cec5SDimitry Andric bool PrintfSpecifier::hasValidPrecision() const { 1054*0b57cec5SDimitry Andric if (Precision.getHowSpecified() == OptionalAmount::NotSpecified) 1055*0b57cec5SDimitry Andric return true; 1056*0b57cec5SDimitry Andric 1057*0b57cec5SDimitry Andric // Precision is only valid with the diouxXaAeEfFgGsP conversions 1058*0b57cec5SDimitry Andric switch (CS.getKind()) { 1059*0b57cec5SDimitry Andric case ConversionSpecifier::dArg: 1060*0b57cec5SDimitry Andric case ConversionSpecifier::DArg: 1061*0b57cec5SDimitry Andric case ConversionSpecifier::iArg: 1062*0b57cec5SDimitry Andric case ConversionSpecifier::oArg: 1063*0b57cec5SDimitry Andric case ConversionSpecifier::OArg: 1064*0b57cec5SDimitry Andric case ConversionSpecifier::uArg: 1065*0b57cec5SDimitry Andric case ConversionSpecifier::UArg: 1066*0b57cec5SDimitry Andric case ConversionSpecifier::xArg: 1067*0b57cec5SDimitry Andric case ConversionSpecifier::XArg: 1068*0b57cec5SDimitry Andric case ConversionSpecifier::aArg: 1069*0b57cec5SDimitry Andric case ConversionSpecifier::AArg: 1070*0b57cec5SDimitry Andric case ConversionSpecifier::eArg: 1071*0b57cec5SDimitry Andric case ConversionSpecifier::EArg: 1072*0b57cec5SDimitry Andric case ConversionSpecifier::fArg: 1073*0b57cec5SDimitry Andric case ConversionSpecifier::FArg: 1074*0b57cec5SDimitry Andric case ConversionSpecifier::gArg: 1075*0b57cec5SDimitry Andric case ConversionSpecifier::GArg: 1076*0b57cec5SDimitry Andric case ConversionSpecifier::sArg: 1077*0b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDrArg: 1078*0b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDyArg: 1079*0b57cec5SDimitry Andric case ConversionSpecifier::PArg: 1080*0b57cec5SDimitry Andric return true; 1081*0b57cec5SDimitry Andric 1082*0b57cec5SDimitry Andric default: 1083*0b57cec5SDimitry Andric return false; 1084*0b57cec5SDimitry Andric } 1085*0b57cec5SDimitry Andric } 1086*0b57cec5SDimitry Andric bool PrintfSpecifier::hasValidFieldWidth() const { 1087*0b57cec5SDimitry Andric if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified) 1088*0b57cec5SDimitry Andric return true; 1089*0b57cec5SDimitry Andric 1090*0b57cec5SDimitry Andric // The field width is valid for all conversions except n 1091*0b57cec5SDimitry Andric switch (CS.getKind()) { 1092*0b57cec5SDimitry Andric case ConversionSpecifier::nArg: 1093*0b57cec5SDimitry Andric return false; 1094*0b57cec5SDimitry Andric 1095*0b57cec5SDimitry Andric default: 1096*0b57cec5SDimitry Andric return true; 1097*0b57cec5SDimitry Andric } 1098*0b57cec5SDimitry Andric } 1099