xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/PrintfFormatString.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Handling of format string in printf and friends.  The structure of format
100b57cec5SDimitry Andric // strings for fprintf() are described in C99 7.19.6.1.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
145ffd83dbSDimitry Andric #include "FormatStringParsing.h"
150b57cec5SDimitry Andric #include "clang/AST/FormatString.h"
160b57cec5SDimitry Andric #include "clang/AST/OSLog.h"
170b57cec5SDimitry Andric #include "clang/Basic/TargetInfo.h"
185ffd83dbSDimitry Andric #include "llvm/Support/Regex.h"
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric using clang::analyze_format_string::ArgType;
210b57cec5SDimitry Andric using clang::analyze_format_string::FormatStringHandler;
220b57cec5SDimitry Andric using clang::analyze_format_string::LengthModifier;
230b57cec5SDimitry Andric using clang::analyze_format_string::OptionalAmount;
240b57cec5SDimitry Andric using clang::analyze_format_string::ConversionSpecifier;
250b57cec5SDimitry Andric using clang::analyze_printf::PrintfSpecifier;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric using namespace clang;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
300b57cec5SDimitry Andric         PrintfSpecifierResult;
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
330b57cec5SDimitry Andric // Methods for parsing format strings.
340b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric using analyze_format_string::ParseNonPositionAmount;
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
390b57cec5SDimitry Andric                            const char *Start, const char *&Beg, const char *E,
400b57cec5SDimitry Andric                            unsigned *argIndex) {
410b57cec5SDimitry Andric   if (argIndex) {
420b57cec5SDimitry Andric     FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
430b57cec5SDimitry Andric   } else {
440b57cec5SDimitry Andric     const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
450b57cec5SDimitry Andric                                            analyze_format_string::PrecisionPos);
460b57cec5SDimitry Andric     if (Amt.isInvalid())
470b57cec5SDimitry Andric       return true;
480b57cec5SDimitry Andric     FS.setPrecision(Amt);
490b57cec5SDimitry Andric   }
500b57cec5SDimitry Andric   return false;
510b57cec5SDimitry Andric }
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,
540b57cec5SDimitry Andric                            const char *FlagBeg, const char *E, bool Warn) {
550b57cec5SDimitry Andric    StringRef Flag(FlagBeg, E - FlagBeg);
560b57cec5SDimitry Andric    // Currently there is only one flag.
570b57cec5SDimitry Andric    if (Flag == "tt") {
580b57cec5SDimitry Andric      FS.setHasObjCTechnicalTerm(FlagBeg);
590b57cec5SDimitry Andric      return false;
600b57cec5SDimitry Andric    }
610b57cec5SDimitry Andric    // Handle either the case of no flag or an invalid flag.
620b57cec5SDimitry Andric    if (Warn) {
630b57cec5SDimitry Andric      if (Flag == "")
640b57cec5SDimitry Andric        H.HandleEmptyObjCModifierFlag(FlagBeg, E  - FlagBeg);
650b57cec5SDimitry Andric      else
660b57cec5SDimitry Andric        H.HandleInvalidObjCModifierFlag(FlagBeg, E  - FlagBeg);
670b57cec5SDimitry Andric    }
680b57cec5SDimitry Andric    return true;
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
720b57cec5SDimitry Andric                                                   const char *&Beg,
730b57cec5SDimitry Andric                                                   const char *E,
740b57cec5SDimitry Andric                                                   unsigned &argIndex,
750b57cec5SDimitry Andric                                                   const LangOptions &LO,
760b57cec5SDimitry Andric                                                   const TargetInfo &Target,
770b57cec5SDimitry Andric                                                   bool Warn,
780b57cec5SDimitry Andric                                                   bool isFreeBSDKPrintf) {
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric   using namespace clang::analyze_format_string;
810b57cec5SDimitry Andric   using namespace clang::analyze_printf;
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   const char *I = Beg;
840b57cec5SDimitry Andric   const char *Start = nullptr;
850b57cec5SDimitry Andric   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   // Look for a '%' character that indicates the start of a format specifier.
880b57cec5SDimitry Andric   for ( ; I != E ; ++I) {
890b57cec5SDimitry Andric     char c = *I;
900b57cec5SDimitry Andric     if (c == '\0') {
910b57cec5SDimitry Andric       // Detect spurious null characters, which are likely errors.
920b57cec5SDimitry Andric       H.HandleNullChar(I);
930b57cec5SDimitry Andric       return true;
940b57cec5SDimitry Andric     }
950b57cec5SDimitry Andric     if (c == '%') {
960b57cec5SDimitry Andric       Start = I++;  // Record the start of the format specifier.
970b57cec5SDimitry Andric       break;
980b57cec5SDimitry Andric     }
990b57cec5SDimitry Andric   }
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   // No format specifier found?
1020b57cec5SDimitry Andric   if (!Start)
1030b57cec5SDimitry Andric     return false;
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   if (I == E) {
1060b57cec5SDimitry Andric     // No more characters left?
1070b57cec5SDimitry Andric     if (Warn)
1080b57cec5SDimitry Andric       H.HandleIncompleteSpecifier(Start, E - Start);
1090b57cec5SDimitry Andric     return true;
1100b57cec5SDimitry Andric   }
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   PrintfSpecifier FS;
1130b57cec5SDimitry Andric   if (ParseArgPosition(H, FS, Start, I, E))
1140b57cec5SDimitry Andric     return true;
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   if (I == E) {
1170b57cec5SDimitry Andric     // No more characters left?
1180b57cec5SDimitry Andric     if (Warn)
1190b57cec5SDimitry Andric       H.HandleIncompleteSpecifier(Start, E - Start);
1200b57cec5SDimitry Andric     return true;
1210b57cec5SDimitry Andric   }
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   if (*I == '{') {
1240b57cec5SDimitry Andric     ++I;
1250b57cec5SDimitry Andric     unsigned char PrivacyFlags = 0;
1260b57cec5SDimitry Andric     StringRef MatchedStr;
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric     do {
1290b57cec5SDimitry Andric       StringRef Str(I, E - I);
1300b57cec5SDimitry Andric       std::string Match = "^[[:space:]]*"
1310b57cec5SDimitry Andric                           "(private|public|sensitive|mask\\.[^[:space:],}]*)"
1320b57cec5SDimitry Andric                           "[[:space:]]*(,|})";
1330b57cec5SDimitry Andric       llvm::Regex R(Match);
1340b57cec5SDimitry Andric       SmallVector<StringRef, 2> Matches;
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric       if (R.match(Str, &Matches)) {
1370b57cec5SDimitry Andric         MatchedStr = Matches[1];
1380b57cec5SDimitry Andric         I += Matches[0].size();
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric         // Set the privacy flag if the privacy annotation in the
1410b57cec5SDimitry Andric         // comma-delimited segment is at least as strict as the privacy
1420b57cec5SDimitry Andric         // annotations in previous comma-delimited segments.
1435f757f3fSDimitry Andric         if (MatchedStr.starts_with("mask")) {
1440b57cec5SDimitry Andric           StringRef MaskType = MatchedStr.substr(sizeof("mask.") - 1);
1450b57cec5SDimitry Andric           unsigned Size = MaskType.size();
1460b57cec5SDimitry Andric           if (Warn && (Size == 0 || Size > 8))
1470b57cec5SDimitry Andric             H.handleInvalidMaskType(MaskType);
1480b57cec5SDimitry Andric           FS.setMaskType(MaskType);
149*0fca6ea1SDimitry Andric         } else if (MatchedStr == "sensitive")
1500b57cec5SDimitry Andric           PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsSensitive;
1510b57cec5SDimitry Andric         else if (PrivacyFlags !=
1520b57cec5SDimitry Andric                      clang::analyze_os_log::OSLogBufferItem::IsSensitive &&
153*0fca6ea1SDimitry Andric                  MatchedStr == "private")
1540b57cec5SDimitry Andric           PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate;
155*0fca6ea1SDimitry Andric         else if (PrivacyFlags == 0 && MatchedStr == "public")
1560b57cec5SDimitry Andric           PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic;
1570b57cec5SDimitry Andric       } else {
1580b57cec5SDimitry Andric         size_t CommaOrBracePos =
1590b57cec5SDimitry Andric             Str.find_if([](char c) { return c == ',' || c == '}'; });
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric         if (CommaOrBracePos == StringRef::npos) {
1620b57cec5SDimitry Andric           // Neither a comma nor the closing brace was found.
1630b57cec5SDimitry Andric           if (Warn)
1640b57cec5SDimitry Andric             H.HandleIncompleteSpecifier(Start, E - Start);
1650b57cec5SDimitry Andric           return true;
1660b57cec5SDimitry Andric         }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric         I += CommaOrBracePos + 1;
1690b57cec5SDimitry Andric       }
1700b57cec5SDimitry Andric       // Continue until the closing brace is found.
1710b57cec5SDimitry Andric     } while (*(I - 1) == ',');
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric     // Set the privacy flag.
1740b57cec5SDimitry Andric     switch (PrivacyFlags) {
1750b57cec5SDimitry Andric     case 0:
1760b57cec5SDimitry Andric       break;
1770b57cec5SDimitry Andric     case clang::analyze_os_log::OSLogBufferItem::IsPrivate:
1780b57cec5SDimitry Andric       FS.setIsPrivate(MatchedStr.data());
1790b57cec5SDimitry Andric       break;
1800b57cec5SDimitry Andric     case clang::analyze_os_log::OSLogBufferItem::IsPublic:
1810b57cec5SDimitry Andric       FS.setIsPublic(MatchedStr.data());
1820b57cec5SDimitry Andric       break;
1830b57cec5SDimitry Andric     case clang::analyze_os_log::OSLogBufferItem::IsSensitive:
1840b57cec5SDimitry Andric       FS.setIsSensitive(MatchedStr.data());
1850b57cec5SDimitry Andric       break;
1860b57cec5SDimitry Andric     default:
1870b57cec5SDimitry Andric       llvm_unreachable("Unexpected privacy flag value");
1880b57cec5SDimitry Andric     }
1890b57cec5SDimitry Andric   }
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric   // Look for flags (if any).
1920b57cec5SDimitry Andric   bool hasMore = true;
1930b57cec5SDimitry Andric   for ( ; I != E; ++I) {
1940b57cec5SDimitry Andric     switch (*I) {
1950b57cec5SDimitry Andric       default: hasMore = false; break;
1960b57cec5SDimitry Andric       case '\'':
1970b57cec5SDimitry Andric         // FIXME: POSIX specific.  Always accept?
1980b57cec5SDimitry Andric         FS.setHasThousandsGrouping(I);
1990b57cec5SDimitry Andric         break;
2000b57cec5SDimitry Andric       case '-': FS.setIsLeftJustified(I); break;
2010b57cec5SDimitry Andric       case '+': FS.setHasPlusPrefix(I); break;
2020b57cec5SDimitry Andric       case ' ': FS.setHasSpacePrefix(I); break;
2030b57cec5SDimitry Andric       case '#': FS.setHasAlternativeForm(I); break;
2040b57cec5SDimitry Andric       case '0': FS.setHasLeadingZeros(I); break;
2050b57cec5SDimitry Andric     }
2060b57cec5SDimitry Andric     if (!hasMore)
2070b57cec5SDimitry Andric       break;
2080b57cec5SDimitry Andric   }
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric   if (I == E) {
2110b57cec5SDimitry Andric     // No more characters left?
2120b57cec5SDimitry Andric     if (Warn)
2130b57cec5SDimitry Andric       H.HandleIncompleteSpecifier(Start, E - Start);
2140b57cec5SDimitry Andric     return true;
2150b57cec5SDimitry Andric   }
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric   // Look for the field width (if any).
2180b57cec5SDimitry Andric   if (ParseFieldWidth(H, FS, Start, I, E,
2190b57cec5SDimitry Andric                       FS.usesPositionalArg() ? nullptr : &argIndex))
2200b57cec5SDimitry Andric     return true;
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric   if (I == E) {
2230b57cec5SDimitry Andric     // No more characters left?
2240b57cec5SDimitry Andric     if (Warn)
2250b57cec5SDimitry Andric       H.HandleIncompleteSpecifier(Start, E - Start);
2260b57cec5SDimitry Andric     return true;
2270b57cec5SDimitry Andric   }
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric   // Look for the precision (if any).
2300b57cec5SDimitry Andric   if (*I == '.') {
2310b57cec5SDimitry Andric     ++I;
2320b57cec5SDimitry Andric     if (I == E) {
2330b57cec5SDimitry Andric       if (Warn)
2340b57cec5SDimitry Andric         H.HandleIncompleteSpecifier(Start, E - Start);
2350b57cec5SDimitry Andric       return true;
2360b57cec5SDimitry Andric     }
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric     if (ParsePrecision(H, FS, Start, I, E,
2390b57cec5SDimitry Andric                        FS.usesPositionalArg() ? nullptr : &argIndex))
2400b57cec5SDimitry Andric       return true;
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric     if (I == E) {
2430b57cec5SDimitry Andric       // No more characters left?
2440b57cec5SDimitry Andric       if (Warn)
2450b57cec5SDimitry Andric         H.HandleIncompleteSpecifier(Start, E - Start);
2460b57cec5SDimitry Andric       return true;
2470b57cec5SDimitry Andric     }
2480b57cec5SDimitry Andric   }
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric   if (ParseVectorModifier(H, FS, I, E, LO))
2510b57cec5SDimitry Andric     return true;
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric   // Look for the length modifier.
2540b57cec5SDimitry Andric   if (ParseLengthModifier(FS, I, E, LO) && I == E) {
2550b57cec5SDimitry Andric     // No more characters left?
2560b57cec5SDimitry Andric     if (Warn)
2570b57cec5SDimitry Andric       H.HandleIncompleteSpecifier(Start, E - Start);
2580b57cec5SDimitry Andric     return true;
2590b57cec5SDimitry Andric   }
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric   // Look for the Objective-C modifier flags, if any.
2620b57cec5SDimitry Andric   // We parse these here, even if they don't apply to
2630b57cec5SDimitry Andric   // the conversion specifier, and then emit an error
2640b57cec5SDimitry Andric   // later if the conversion specifier isn't '@'.  This
2650b57cec5SDimitry Andric   // enables better recovery, and we don't know if
2660b57cec5SDimitry Andric   // these flags are applicable until later.
2670b57cec5SDimitry Andric   const char *ObjCModifierFlagsStart = nullptr,
2680b57cec5SDimitry Andric              *ObjCModifierFlagsEnd = nullptr;
2690b57cec5SDimitry Andric   if (*I == '[') {
2700b57cec5SDimitry Andric     ObjCModifierFlagsStart = I;
2710b57cec5SDimitry Andric     ++I;
2720b57cec5SDimitry Andric     auto flagStart = I;
2730b57cec5SDimitry Andric     for (;; ++I) {
2740b57cec5SDimitry Andric       ObjCModifierFlagsEnd = I;
2750b57cec5SDimitry Andric       if (I == E) {
2760b57cec5SDimitry Andric         if (Warn)
2770b57cec5SDimitry Andric           H.HandleIncompleteSpecifier(Start, E - Start);
2780b57cec5SDimitry Andric         return true;
2790b57cec5SDimitry Andric       }
2800b57cec5SDimitry Andric       // Did we find the closing ']'?
2810b57cec5SDimitry Andric       if (*I == ']') {
2820b57cec5SDimitry Andric         if (ParseObjCFlags(H, FS, flagStart, I, Warn))
2830b57cec5SDimitry Andric           return true;
2840b57cec5SDimitry Andric         ++I;
2850b57cec5SDimitry Andric         break;
2860b57cec5SDimitry Andric       }
2870b57cec5SDimitry Andric       // There are no separators defined yet for multiple
2880b57cec5SDimitry Andric       // Objective-C modifier flags.  When those are
2890b57cec5SDimitry Andric       // defined, this is the place to check.
2900b57cec5SDimitry Andric     }
2910b57cec5SDimitry Andric   }
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric   if (*I == '\0') {
2940b57cec5SDimitry Andric     // Detect spurious null characters, which are likely errors.
2950b57cec5SDimitry Andric     H.HandleNullChar(I);
2960b57cec5SDimitry Andric     return true;
2970b57cec5SDimitry Andric   }
2980b57cec5SDimitry Andric 
2990b57cec5SDimitry Andric   // Finally, look for the conversion specifier.
3000b57cec5SDimitry Andric   const char *conversionPosition = I++;
3010b57cec5SDimitry Andric   ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
3020b57cec5SDimitry Andric   switch (*conversionPosition) {
3030b57cec5SDimitry Andric     default:
3040b57cec5SDimitry Andric       break;
3050b57cec5SDimitry Andric     // C99: 7.19.6.1 (section 8).
3060b57cec5SDimitry Andric     case '%': k = ConversionSpecifier::PercentArg;   break;
3070b57cec5SDimitry Andric     case 'A': k = ConversionSpecifier::AArg; break;
3080b57cec5SDimitry Andric     case 'E': k = ConversionSpecifier::EArg; break;
3090b57cec5SDimitry Andric     case 'F': k = ConversionSpecifier::FArg; break;
3100b57cec5SDimitry Andric     case 'G': k = ConversionSpecifier::GArg; break;
3110b57cec5SDimitry Andric     case 'X': k = ConversionSpecifier::XArg; break;
3120b57cec5SDimitry Andric     case 'a': k = ConversionSpecifier::aArg; break;
3130b57cec5SDimitry Andric     case 'c': k = ConversionSpecifier::cArg; break;
3140b57cec5SDimitry Andric     case 'd': k = ConversionSpecifier::dArg; break;
3150b57cec5SDimitry Andric     case 'e': k = ConversionSpecifier::eArg; break;
3160b57cec5SDimitry Andric     case 'f': k = ConversionSpecifier::fArg; break;
3170b57cec5SDimitry Andric     case 'g': k = ConversionSpecifier::gArg; break;
3180b57cec5SDimitry Andric     case 'i': k = ConversionSpecifier::iArg; break;
3190b57cec5SDimitry Andric     case 'n':
320ec280e9eSDimitry Andric       // Not handled, but reserved in OpenCL and FreeBSD kernel.
321ec280e9eSDimitry Andric       if (!LO.OpenCL && !isFreeBSDKPrintf)
3220b57cec5SDimitry Andric         k = ConversionSpecifier::nArg;
3230b57cec5SDimitry Andric       break;
3240b57cec5SDimitry Andric     case 'o': k = ConversionSpecifier::oArg; break;
3250b57cec5SDimitry Andric     case 'p': k = ConversionSpecifier::pArg; break;
3260b57cec5SDimitry Andric     case 's': k = ConversionSpecifier::sArg; break;
3270b57cec5SDimitry Andric     case 'u': k = ConversionSpecifier::uArg; break;
3280b57cec5SDimitry Andric     case 'x': k = ConversionSpecifier::xArg; break;
329bdd1243dSDimitry Andric     // C23.
330bdd1243dSDimitry Andric     case 'b':
331bdd1243dSDimitry Andric       if (isFreeBSDKPrintf)
332bdd1243dSDimitry Andric         k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
333bdd1243dSDimitry Andric       else
334bdd1243dSDimitry Andric         k = ConversionSpecifier::bArg;
335bdd1243dSDimitry Andric       break;
336bdd1243dSDimitry Andric     case 'B': k = ConversionSpecifier::BArg; break;
3370b57cec5SDimitry Andric     // POSIX specific.
3380b57cec5SDimitry Andric     case 'C': k = ConversionSpecifier::CArg; break;
3390b57cec5SDimitry Andric     case 'S': k = ConversionSpecifier::SArg; break;
3400b57cec5SDimitry Andric     // Apple extension for os_log
3410b57cec5SDimitry Andric     case 'P':
3420b57cec5SDimitry Andric       k = ConversionSpecifier::PArg;
3430b57cec5SDimitry Andric       break;
3440b57cec5SDimitry Andric     // Objective-C.
3450b57cec5SDimitry Andric     case '@': k = ConversionSpecifier::ObjCObjArg; break;
3460b57cec5SDimitry Andric     // Glibc specific.
3470b57cec5SDimitry Andric     case 'm': k = ConversionSpecifier::PrintErrno; break;
3480b57cec5SDimitry Andric     case 'r':
3490b57cec5SDimitry Andric       if (isFreeBSDKPrintf)
3500b57cec5SDimitry Andric         k = ConversionSpecifier::FreeBSDrArg; // int
351*0fca6ea1SDimitry Andric       else if (LO.FixedPoint)
352*0fca6ea1SDimitry Andric         k = ConversionSpecifier::rArg;
3530b57cec5SDimitry Andric       break;
3540b57cec5SDimitry Andric     case 'y':
3550b57cec5SDimitry Andric       if (isFreeBSDKPrintf)
3560b57cec5SDimitry Andric         k = ConversionSpecifier::FreeBSDyArg; // int
3570b57cec5SDimitry Andric       break;
3580b57cec5SDimitry Andric     // Apple-specific.
3590b57cec5SDimitry Andric     case 'D':
3600b57cec5SDimitry Andric       if (isFreeBSDKPrintf)
3610b57cec5SDimitry Andric         k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *
3620b57cec5SDimitry Andric       else if (Target.getTriple().isOSDarwin())
3630b57cec5SDimitry Andric         k = ConversionSpecifier::DArg;
3640b57cec5SDimitry Andric       break;
3650b57cec5SDimitry Andric     case 'O':
3660b57cec5SDimitry Andric       if (Target.getTriple().isOSDarwin())
3670b57cec5SDimitry Andric         k = ConversionSpecifier::OArg;
3680b57cec5SDimitry Andric       break;
3690b57cec5SDimitry Andric     case 'U':
3700b57cec5SDimitry Andric       if (Target.getTriple().isOSDarwin())
3710b57cec5SDimitry Andric         k = ConversionSpecifier::UArg;
3720b57cec5SDimitry Andric       break;
3730b57cec5SDimitry Andric     // MS specific.
3740b57cec5SDimitry Andric     case 'Z':
3750b57cec5SDimitry Andric       if (Target.getTriple().isOSMSVCRT())
3760b57cec5SDimitry Andric         k = ConversionSpecifier::ZArg;
3770b57cec5SDimitry Andric       break;
378*0fca6ea1SDimitry Andric     // ISO/IEC TR 18037 (fixed-point) specific.
379*0fca6ea1SDimitry Andric     // NOTE: 'r' is handled up above since FreeBSD also supports %r.
380*0fca6ea1SDimitry Andric     case 'k':
381*0fca6ea1SDimitry Andric       if (LO.FixedPoint)
382*0fca6ea1SDimitry Andric         k = ConversionSpecifier::kArg;
383*0fca6ea1SDimitry Andric       break;
384*0fca6ea1SDimitry Andric     case 'K':
385*0fca6ea1SDimitry Andric       if (LO.FixedPoint)
386*0fca6ea1SDimitry Andric         k = ConversionSpecifier::KArg;
387*0fca6ea1SDimitry Andric       break;
388*0fca6ea1SDimitry Andric     case 'R':
389*0fca6ea1SDimitry Andric       if (LO.FixedPoint)
390*0fca6ea1SDimitry Andric         k = ConversionSpecifier::RArg;
391*0fca6ea1SDimitry Andric       break;
3920b57cec5SDimitry Andric   }
3930b57cec5SDimitry Andric 
3940b57cec5SDimitry Andric   // Check to see if we used the Objective-C modifier flags with
3950b57cec5SDimitry Andric   // a conversion specifier other than '@'.
3960b57cec5SDimitry Andric   if (k != ConversionSpecifier::ObjCObjArg &&
3970b57cec5SDimitry Andric       k != ConversionSpecifier::InvalidSpecifier &&
3980b57cec5SDimitry Andric       ObjCModifierFlagsStart) {
3990b57cec5SDimitry Andric     H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart,
4000b57cec5SDimitry Andric                                            ObjCModifierFlagsEnd + 1,
4010b57cec5SDimitry Andric                                            conversionPosition);
4020b57cec5SDimitry Andric     return true;
4030b57cec5SDimitry Andric   }
4040b57cec5SDimitry Andric 
4050b57cec5SDimitry Andric   PrintfConversionSpecifier CS(conversionPosition, k);
4060b57cec5SDimitry Andric   FS.setConversionSpecifier(CS);
4070b57cec5SDimitry Andric   if (CS.consumesDataArgument() && !FS.usesPositionalArg())
4080b57cec5SDimitry Andric     FS.setArgIndex(argIndex++);
4090b57cec5SDimitry Andric   // FreeBSD kernel specific.
4100b57cec5SDimitry Andric   if (k == ConversionSpecifier::FreeBSDbArg ||
4110b57cec5SDimitry Andric       k == ConversionSpecifier::FreeBSDDArg)
4120b57cec5SDimitry Andric     argIndex++;
4130b57cec5SDimitry Andric 
4140b57cec5SDimitry Andric   if (k == ConversionSpecifier::InvalidSpecifier) {
4150b57cec5SDimitry Andric     unsigned Len = I - Start;
4160b57cec5SDimitry Andric     if (ParseUTF8InvalidSpecifier(Start, E, Len)) {
4170b57cec5SDimitry Andric       CS.setEndScanList(Start + Len);
4180b57cec5SDimitry Andric       FS.setConversionSpecifier(CS);
4190b57cec5SDimitry Andric     }
4200b57cec5SDimitry Andric     // Assume the conversion takes one argument.
4210b57cec5SDimitry Andric     return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len);
4220b57cec5SDimitry Andric   }
4230b57cec5SDimitry Andric   return PrintfSpecifierResult(Start, FS);
4240b57cec5SDimitry Andric }
4250b57cec5SDimitry Andric 
4260b57cec5SDimitry Andric bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
4270b57cec5SDimitry Andric                                                      const char *I,
4280b57cec5SDimitry Andric                                                      const char *E,
4290b57cec5SDimitry Andric                                                      const LangOptions &LO,
4300b57cec5SDimitry Andric                                                      const TargetInfo &Target,
4310b57cec5SDimitry Andric                                                      bool isFreeBSDKPrintf) {
4320b57cec5SDimitry Andric 
4330b57cec5SDimitry Andric   unsigned argIndex = 0;
4340b57cec5SDimitry Andric 
4350b57cec5SDimitry Andric   // Keep looking for a format specifier until we have exhausted the string.
4360b57cec5SDimitry Andric   while (I != E) {
4370b57cec5SDimitry Andric     const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
4380b57cec5SDimitry Andric                                                             LO, Target, true,
4390b57cec5SDimitry Andric                                                             isFreeBSDKPrintf);
4400b57cec5SDimitry Andric     // Did a fail-stop error of any kind occur when parsing the specifier?
4410b57cec5SDimitry Andric     // If so, don't do any more processing.
4420b57cec5SDimitry Andric     if (FSR.shouldStop())
4430b57cec5SDimitry Andric       return true;
4440b57cec5SDimitry Andric     // Did we exhaust the string or encounter an error that
4450b57cec5SDimitry Andric     // we can recover from?
4460b57cec5SDimitry Andric     if (!FSR.hasValue())
4470b57cec5SDimitry Andric       continue;
4480b57cec5SDimitry Andric     // We have a format specifier.  Pass it to the callback.
4490b57cec5SDimitry Andric     if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
45004eeddc0SDimitry Andric                                  I - FSR.getStart(), Target))
4510b57cec5SDimitry Andric       return true;
4520b57cec5SDimitry Andric   }
4530b57cec5SDimitry Andric   assert(I == E && "Format string not exhausted");
4540b57cec5SDimitry Andric   return false;
4550b57cec5SDimitry Andric }
4560b57cec5SDimitry Andric 
4570b57cec5SDimitry Andric bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
4580b57cec5SDimitry Andric                                                             const char *E,
4590b57cec5SDimitry Andric                                                             const LangOptions &LO,
4600b57cec5SDimitry Andric                                                             const TargetInfo &Target) {
4610b57cec5SDimitry Andric 
4620b57cec5SDimitry Andric   unsigned argIndex = 0;
4630b57cec5SDimitry Andric 
4640b57cec5SDimitry Andric   // Keep looking for a %s format specifier until we have exhausted the string.
4650b57cec5SDimitry Andric   FormatStringHandler H;
4660b57cec5SDimitry Andric   while (I != E) {
4670b57cec5SDimitry Andric     const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
4680b57cec5SDimitry Andric                                                             LO, Target, false,
4690b57cec5SDimitry Andric                                                             false);
4700b57cec5SDimitry Andric     // Did a fail-stop error of any kind occur when parsing the specifier?
4710b57cec5SDimitry Andric     // If so, don't do any more processing.
4720b57cec5SDimitry Andric     if (FSR.shouldStop())
4730b57cec5SDimitry Andric       return false;
4740b57cec5SDimitry Andric     // Did we exhaust the string or encounter an error that
4750b57cec5SDimitry Andric     // we can recover from?
4760b57cec5SDimitry Andric     if (!FSR.hasValue())
4770b57cec5SDimitry Andric       continue;
4780b57cec5SDimitry Andric     const analyze_printf::PrintfSpecifier &FS = FSR.getValue();
4790b57cec5SDimitry Andric     // Return true if this a %s format specifier.
4800b57cec5SDimitry Andric     if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg)
4810b57cec5SDimitry Andric       return true;
4820b57cec5SDimitry Andric   }
4830b57cec5SDimitry Andric   return false;
4840b57cec5SDimitry Andric }
4850b57cec5SDimitry Andric 
486a7dea167SDimitry Andric bool clang::analyze_format_string::parseFormatStringHasFormattingSpecifiers(
487a7dea167SDimitry Andric     const char *Begin, const char *End, const LangOptions &LO,
488a7dea167SDimitry Andric     const TargetInfo &Target) {
489a7dea167SDimitry Andric   unsigned ArgIndex = 0;
490a7dea167SDimitry Andric   // Keep looking for a formatting specifier until we have exhausted the string.
491a7dea167SDimitry Andric   FormatStringHandler H;
492a7dea167SDimitry Andric   while (Begin != End) {
493a7dea167SDimitry Andric     const PrintfSpecifierResult &FSR =
494a7dea167SDimitry Andric         ParsePrintfSpecifier(H, Begin, End, ArgIndex, LO, Target, false, false);
495a7dea167SDimitry Andric     if (FSR.shouldStop())
496a7dea167SDimitry Andric       break;
497a7dea167SDimitry Andric     if (FSR.hasValue())
498a7dea167SDimitry Andric       return true;
499a7dea167SDimitry Andric   }
500a7dea167SDimitry Andric   return false;
501a7dea167SDimitry Andric }
502a7dea167SDimitry Andric 
5030b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
5040b57cec5SDimitry Andric // Methods on PrintfSpecifier.
5050b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
5060b57cec5SDimitry Andric 
5070b57cec5SDimitry Andric ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
5080b57cec5SDimitry Andric                                           bool IsObjCLiteral) const {
5090b57cec5SDimitry Andric   if (CS.getKind() == ConversionSpecifier::cArg)
5100b57cec5SDimitry Andric     switch (LM.getKind()) {
5110b57cec5SDimitry Andric       case LengthModifier::None:
5120b57cec5SDimitry Andric         return Ctx.IntTy;
5130b57cec5SDimitry Andric       case LengthModifier::AsLong:
5140b57cec5SDimitry Andric       case LengthModifier::AsWide:
5150b57cec5SDimitry Andric         return ArgType(ArgType::WIntTy, "wint_t");
5160b57cec5SDimitry Andric       case LengthModifier::AsShort:
5170b57cec5SDimitry Andric         if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
5180b57cec5SDimitry Andric           return Ctx.IntTy;
519bdd1243dSDimitry Andric         [[fallthrough]];
5200b57cec5SDimitry Andric       default:
5210b57cec5SDimitry Andric         return ArgType::Invalid();
5220b57cec5SDimitry Andric     }
5230b57cec5SDimitry Andric 
5240b57cec5SDimitry Andric   if (CS.isIntArg())
5250b57cec5SDimitry Andric     switch (LM.getKind()) {
5260b57cec5SDimitry Andric       case LengthModifier::AsLongDouble:
5270b57cec5SDimitry Andric         // GNU extension.
5280b57cec5SDimitry Andric         return Ctx.LongLongTy;
5290b57cec5SDimitry Andric       case LengthModifier::None:
5300b57cec5SDimitry Andric       case LengthModifier::AsShortLong:
5310b57cec5SDimitry Andric         return Ctx.IntTy;
5320b57cec5SDimitry Andric       case LengthModifier::AsInt32:
5330b57cec5SDimitry Andric         return ArgType(Ctx.IntTy, "__int32");
5340b57cec5SDimitry Andric       case LengthModifier::AsChar:
5350b57cec5SDimitry Andric         return ArgType::AnyCharTy;
5360b57cec5SDimitry Andric       case LengthModifier::AsShort: return Ctx.ShortTy;
5370b57cec5SDimitry Andric       case LengthModifier::AsLong: return Ctx.LongTy;
5380b57cec5SDimitry Andric       case LengthModifier::AsLongLong:
5390b57cec5SDimitry Andric       case LengthModifier::AsQuad:
5400b57cec5SDimitry Andric         return Ctx.LongLongTy;
5410b57cec5SDimitry Andric       case LengthModifier::AsInt64:
5420b57cec5SDimitry Andric         return ArgType(Ctx.LongLongTy, "__int64");
5430b57cec5SDimitry Andric       case LengthModifier::AsIntMax:
5440b57cec5SDimitry Andric         return ArgType(Ctx.getIntMaxType(), "intmax_t");
5450b57cec5SDimitry Andric       case LengthModifier::AsSizeT:
5460b57cec5SDimitry Andric         return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
5470b57cec5SDimitry Andric       case LengthModifier::AsInt3264:
5480b57cec5SDimitry Andric         return Ctx.getTargetInfo().getTriple().isArch64Bit()
5490b57cec5SDimitry Andric                    ? ArgType(Ctx.LongLongTy, "__int64")
5500b57cec5SDimitry Andric                    : ArgType(Ctx.IntTy, "__int32");
5510b57cec5SDimitry Andric       case LengthModifier::AsPtrDiff:
5520b57cec5SDimitry Andric         return ArgType::makePtrdiffT(
5530b57cec5SDimitry Andric             ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
5540b57cec5SDimitry Andric       case LengthModifier::AsAllocate:
5550b57cec5SDimitry Andric       case LengthModifier::AsMAllocate:
5560b57cec5SDimitry Andric       case LengthModifier::AsWide:
5570b57cec5SDimitry Andric         return ArgType::Invalid();
5580b57cec5SDimitry Andric     }
5590b57cec5SDimitry Andric 
5600b57cec5SDimitry Andric   if (CS.isUIntArg())
5610b57cec5SDimitry Andric     switch (LM.getKind()) {
5620b57cec5SDimitry Andric       case LengthModifier::AsLongDouble:
5630b57cec5SDimitry Andric         // GNU extension.
5640b57cec5SDimitry Andric         return Ctx.UnsignedLongLongTy;
5650b57cec5SDimitry Andric       case LengthModifier::None:
5660b57cec5SDimitry Andric       case LengthModifier::AsShortLong:
5670b57cec5SDimitry Andric         return Ctx.UnsignedIntTy;
5680b57cec5SDimitry Andric       case LengthModifier::AsInt32:
5690b57cec5SDimitry Andric         return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
5700b57cec5SDimitry Andric       case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
5710b57cec5SDimitry Andric       case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
5720b57cec5SDimitry Andric       case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
5730b57cec5SDimitry Andric       case LengthModifier::AsLongLong:
5740b57cec5SDimitry Andric       case LengthModifier::AsQuad:
5750b57cec5SDimitry Andric         return Ctx.UnsignedLongLongTy;
5760b57cec5SDimitry Andric       case LengthModifier::AsInt64:
5770b57cec5SDimitry Andric         return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
5780b57cec5SDimitry Andric       case LengthModifier::AsIntMax:
5790b57cec5SDimitry Andric         return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
5800b57cec5SDimitry Andric       case LengthModifier::AsSizeT:
5810b57cec5SDimitry Andric         return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));
5820b57cec5SDimitry Andric       case LengthModifier::AsInt3264:
5830b57cec5SDimitry Andric         return Ctx.getTargetInfo().getTriple().isArch64Bit()
5840b57cec5SDimitry Andric                    ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
5850b57cec5SDimitry Andric                    : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
5860b57cec5SDimitry Andric       case LengthModifier::AsPtrDiff:
5870b57cec5SDimitry Andric         return ArgType::makePtrdiffT(
5880b57cec5SDimitry Andric             ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
5890b57cec5SDimitry Andric       case LengthModifier::AsAllocate:
5900b57cec5SDimitry Andric       case LengthModifier::AsMAllocate:
5910b57cec5SDimitry Andric       case LengthModifier::AsWide:
5920b57cec5SDimitry Andric         return ArgType::Invalid();
5930b57cec5SDimitry Andric     }
5940b57cec5SDimitry Andric 
5950b57cec5SDimitry Andric   if (CS.isDoubleArg()) {
5960b57cec5SDimitry Andric     if (!VectorNumElts.isInvalid()) {
5970b57cec5SDimitry Andric       switch (LM.getKind()) {
5980b57cec5SDimitry Andric       case LengthModifier::AsShort:
5990b57cec5SDimitry Andric         return Ctx.HalfTy;
6000b57cec5SDimitry Andric       case LengthModifier::AsShortLong:
6010b57cec5SDimitry Andric         return Ctx.FloatTy;
6020b57cec5SDimitry Andric       case LengthModifier::AsLong:
6030b57cec5SDimitry Andric       default:
6040b57cec5SDimitry Andric         return Ctx.DoubleTy;
6050b57cec5SDimitry Andric       }
6060b57cec5SDimitry Andric     }
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric     if (LM.getKind() == LengthModifier::AsLongDouble)
6090b57cec5SDimitry Andric       return Ctx.LongDoubleTy;
6100b57cec5SDimitry Andric     return Ctx.DoubleTy;
6110b57cec5SDimitry Andric   }
6120b57cec5SDimitry Andric 
6130b57cec5SDimitry Andric   if (CS.getKind() == ConversionSpecifier::nArg) {
6140b57cec5SDimitry Andric     switch (LM.getKind()) {
6150b57cec5SDimitry Andric       case LengthModifier::None:
6160b57cec5SDimitry Andric         return ArgType::PtrTo(Ctx.IntTy);
6170b57cec5SDimitry Andric       case LengthModifier::AsChar:
6180b57cec5SDimitry Andric         return ArgType::PtrTo(Ctx.SignedCharTy);
6190b57cec5SDimitry Andric       case LengthModifier::AsShort:
6200b57cec5SDimitry Andric         return ArgType::PtrTo(Ctx.ShortTy);
6210b57cec5SDimitry Andric       case LengthModifier::AsLong:
6220b57cec5SDimitry Andric         return ArgType::PtrTo(Ctx.LongTy);
6230b57cec5SDimitry Andric       case LengthModifier::AsLongLong:
6240b57cec5SDimitry Andric       case LengthModifier::AsQuad:
6250b57cec5SDimitry Andric         return ArgType::PtrTo(Ctx.LongLongTy);
6260b57cec5SDimitry Andric       case LengthModifier::AsIntMax:
6270b57cec5SDimitry Andric         return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
6280b57cec5SDimitry Andric       case LengthModifier::AsSizeT:
6290b57cec5SDimitry Andric         return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
6300b57cec5SDimitry Andric       case LengthModifier::AsPtrDiff:
6310b57cec5SDimitry Andric         return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
6320b57cec5SDimitry Andric       case LengthModifier::AsLongDouble:
6330b57cec5SDimitry Andric         return ArgType(); // FIXME: Is this a known extension?
6340b57cec5SDimitry Andric       case LengthModifier::AsAllocate:
6350b57cec5SDimitry Andric       case LengthModifier::AsMAllocate:
6360b57cec5SDimitry Andric       case LengthModifier::AsInt32:
6370b57cec5SDimitry Andric       case LengthModifier::AsInt3264:
6380b57cec5SDimitry Andric       case LengthModifier::AsInt64:
6390b57cec5SDimitry Andric       case LengthModifier::AsWide:
6400b57cec5SDimitry Andric         return ArgType::Invalid();
6410b57cec5SDimitry Andric       case LengthModifier::AsShortLong:
6420b57cec5SDimitry Andric         llvm_unreachable("only used for OpenCL which doesn not handle nArg");
6430b57cec5SDimitry Andric     }
6440b57cec5SDimitry Andric   }
6450b57cec5SDimitry Andric 
646*0fca6ea1SDimitry Andric   if (CS.isFixedPointArg() && !Ctx.getLangOpts().FixedPoint)
647*0fca6ea1SDimitry Andric     return ArgType::Invalid();
648*0fca6ea1SDimitry Andric 
6490b57cec5SDimitry Andric   switch (CS.getKind()) {
6500b57cec5SDimitry Andric     case ConversionSpecifier::sArg:
6510b57cec5SDimitry Andric       if (LM.getKind() == LengthModifier::AsWideChar) {
6520b57cec5SDimitry Andric         if (IsObjCLiteral)
6530b57cec5SDimitry Andric           return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
6540b57cec5SDimitry Andric                          "const unichar *");
6550b57cec5SDimitry Andric         return ArgType(ArgType::WCStrTy, "wchar_t *");
6560b57cec5SDimitry Andric       }
6570b57cec5SDimitry Andric       if (LM.getKind() == LengthModifier::AsWide)
6580b57cec5SDimitry Andric         return ArgType(ArgType::WCStrTy, "wchar_t *");
6590b57cec5SDimitry Andric       return ArgType::CStrTy;
6600b57cec5SDimitry Andric     case ConversionSpecifier::SArg:
6610b57cec5SDimitry Andric       if (IsObjCLiteral)
6620b57cec5SDimitry Andric         return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
6630b57cec5SDimitry Andric                        "const unichar *");
6640b57cec5SDimitry Andric       if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
6650b57cec5SDimitry Andric           LM.getKind() == LengthModifier::AsShort)
6660b57cec5SDimitry Andric         return ArgType::CStrTy;
6670b57cec5SDimitry Andric       return ArgType(ArgType::WCStrTy, "wchar_t *");
6680b57cec5SDimitry Andric     case ConversionSpecifier::CArg:
6690b57cec5SDimitry Andric       if (IsObjCLiteral)
6700b57cec5SDimitry Andric         return ArgType(Ctx.UnsignedShortTy, "unichar");
6710b57cec5SDimitry Andric       if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
6720b57cec5SDimitry Andric           LM.getKind() == LengthModifier::AsShort)
6730b57cec5SDimitry Andric         return Ctx.IntTy;
6740b57cec5SDimitry Andric       return ArgType(Ctx.WideCharTy, "wchar_t");
6750b57cec5SDimitry Andric     case ConversionSpecifier::pArg:
6760b57cec5SDimitry Andric     case ConversionSpecifier::PArg:
6770b57cec5SDimitry Andric       return ArgType::CPointerTy;
6780b57cec5SDimitry Andric     case ConversionSpecifier::ObjCObjArg:
6790b57cec5SDimitry Andric       return ArgType::ObjCPointerTy;
680*0fca6ea1SDimitry Andric     case ConversionSpecifier::kArg:
681*0fca6ea1SDimitry Andric       switch (LM.getKind()) {
682*0fca6ea1SDimitry Andric       case LengthModifier::None:
683*0fca6ea1SDimitry Andric         return Ctx.AccumTy;
684*0fca6ea1SDimitry Andric       case LengthModifier::AsShort:
685*0fca6ea1SDimitry Andric         return Ctx.ShortAccumTy;
686*0fca6ea1SDimitry Andric       case LengthModifier::AsLong:
687*0fca6ea1SDimitry Andric         return Ctx.LongAccumTy;
688*0fca6ea1SDimitry Andric       default:
689*0fca6ea1SDimitry Andric         return ArgType::Invalid();
690*0fca6ea1SDimitry Andric       }
691*0fca6ea1SDimitry Andric     case ConversionSpecifier::KArg:
692*0fca6ea1SDimitry Andric       switch (LM.getKind()) {
693*0fca6ea1SDimitry Andric       case LengthModifier::None:
694*0fca6ea1SDimitry Andric         return Ctx.UnsignedAccumTy;
695*0fca6ea1SDimitry Andric       case LengthModifier::AsShort:
696*0fca6ea1SDimitry Andric         return Ctx.UnsignedShortAccumTy;
697*0fca6ea1SDimitry Andric       case LengthModifier::AsLong:
698*0fca6ea1SDimitry Andric         return Ctx.UnsignedLongAccumTy;
699*0fca6ea1SDimitry Andric       default:
700*0fca6ea1SDimitry Andric         return ArgType::Invalid();
701*0fca6ea1SDimitry Andric       }
702*0fca6ea1SDimitry Andric     case ConversionSpecifier::rArg:
703*0fca6ea1SDimitry Andric       switch (LM.getKind()) {
704*0fca6ea1SDimitry Andric       case LengthModifier::None:
705*0fca6ea1SDimitry Andric         return Ctx.FractTy;
706*0fca6ea1SDimitry Andric       case LengthModifier::AsShort:
707*0fca6ea1SDimitry Andric         return Ctx.ShortFractTy;
708*0fca6ea1SDimitry Andric       case LengthModifier::AsLong:
709*0fca6ea1SDimitry Andric         return Ctx.LongFractTy;
710*0fca6ea1SDimitry Andric       default:
711*0fca6ea1SDimitry Andric         return ArgType::Invalid();
712*0fca6ea1SDimitry Andric       }
713*0fca6ea1SDimitry Andric     case ConversionSpecifier::RArg:
714*0fca6ea1SDimitry Andric       switch (LM.getKind()) {
715*0fca6ea1SDimitry Andric       case LengthModifier::None:
716*0fca6ea1SDimitry Andric         return Ctx.UnsignedFractTy;
717*0fca6ea1SDimitry Andric       case LengthModifier::AsShort:
718*0fca6ea1SDimitry Andric         return Ctx.UnsignedShortFractTy;
719*0fca6ea1SDimitry Andric       case LengthModifier::AsLong:
720*0fca6ea1SDimitry Andric         return Ctx.UnsignedLongFractTy;
721*0fca6ea1SDimitry Andric       default:
722*0fca6ea1SDimitry Andric         return ArgType::Invalid();
723*0fca6ea1SDimitry Andric       }
7240b57cec5SDimitry Andric     default:
7250b57cec5SDimitry Andric       break;
7260b57cec5SDimitry Andric   }
7270b57cec5SDimitry Andric 
7280b57cec5SDimitry Andric   // FIXME: Handle other cases.
7290b57cec5SDimitry Andric   return ArgType();
7300b57cec5SDimitry Andric }
7310b57cec5SDimitry Andric 
7320b57cec5SDimitry Andric 
7330b57cec5SDimitry Andric ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
7340b57cec5SDimitry Andric                                     bool IsObjCLiteral) const {
7350b57cec5SDimitry Andric   const PrintfConversionSpecifier &CS = getConversionSpecifier();
7360b57cec5SDimitry Andric 
7370b57cec5SDimitry Andric   if (!CS.consumesDataArgument())
7380b57cec5SDimitry Andric     return ArgType::Invalid();
7390b57cec5SDimitry Andric 
7400b57cec5SDimitry Andric   ArgType ScalarTy = getScalarArgType(Ctx, IsObjCLiteral);
7410b57cec5SDimitry Andric   if (!ScalarTy.isValid() || VectorNumElts.isInvalid())
7420b57cec5SDimitry Andric     return ScalarTy;
7430b57cec5SDimitry Andric 
7440b57cec5SDimitry Andric   return ScalarTy.makeVectorType(Ctx, VectorNumElts.getConstantAmount());
7450b57cec5SDimitry Andric }
7460b57cec5SDimitry Andric 
7470b57cec5SDimitry Andric bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
7480b57cec5SDimitry Andric                               ASTContext &Ctx, bool IsObjCLiteral) {
7490b57cec5SDimitry Andric   // %n is different from other conversion specifiers; don't try to fix it.
7500b57cec5SDimitry Andric   if (CS.getKind() == ConversionSpecifier::nArg)
7510b57cec5SDimitry Andric     return false;
7520b57cec5SDimitry Andric 
7530b57cec5SDimitry Andric   // Handle Objective-C objects first. Note that while the '%@' specifier will
7540b57cec5SDimitry Andric   // not warn for structure pointer or void pointer arguments (because that's
7550b57cec5SDimitry Andric   // how CoreFoundation objects are implemented), we only show a fixit for '%@'
7560b57cec5SDimitry Andric   // if we know it's an object (block, id, class, or __attribute__((NSObject))).
7570b57cec5SDimitry Andric   if (QT->isObjCRetainableType()) {
7580b57cec5SDimitry Andric     if (!IsObjCLiteral)
7590b57cec5SDimitry Andric       return false;
7600b57cec5SDimitry Andric 
7610b57cec5SDimitry Andric     CS.setKind(ConversionSpecifier::ObjCObjArg);
7620b57cec5SDimitry Andric 
7630b57cec5SDimitry Andric     // Disable irrelevant flags
7640b57cec5SDimitry Andric     HasThousandsGrouping = false;
7650b57cec5SDimitry Andric     HasPlusPrefix = false;
7660b57cec5SDimitry Andric     HasSpacePrefix = false;
7670b57cec5SDimitry Andric     HasAlternativeForm = false;
7680b57cec5SDimitry Andric     HasLeadingZeroes = false;
7690b57cec5SDimitry Andric     Precision.setHowSpecified(OptionalAmount::NotSpecified);
7700b57cec5SDimitry Andric     LM.setKind(LengthModifier::None);
7710b57cec5SDimitry Andric 
7720b57cec5SDimitry Andric     return true;
7730b57cec5SDimitry Andric   }
7740b57cec5SDimitry Andric 
7750b57cec5SDimitry Andric   // Handle strings next (char *, wchar_t *)
7760b57cec5SDimitry Andric   if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
7770b57cec5SDimitry Andric     CS.setKind(ConversionSpecifier::sArg);
7780b57cec5SDimitry Andric 
7790b57cec5SDimitry Andric     // Disable irrelevant flags
78004eeddc0SDimitry Andric     HasAlternativeForm = false;
78104eeddc0SDimitry Andric     HasLeadingZeroes = false;
7820b57cec5SDimitry Andric 
7830b57cec5SDimitry Andric     // Set the long length modifier for wide characters
7840b57cec5SDimitry Andric     if (QT->getPointeeType()->isWideCharType())
7850b57cec5SDimitry Andric       LM.setKind(LengthModifier::AsWideChar);
7860b57cec5SDimitry Andric     else
7870b57cec5SDimitry Andric       LM.setKind(LengthModifier::None);
7880b57cec5SDimitry Andric 
7890b57cec5SDimitry Andric     return true;
7900b57cec5SDimitry Andric   }
7910b57cec5SDimitry Andric 
7920b57cec5SDimitry Andric   // If it's an enum, get its underlying type.
7930b57cec5SDimitry Andric   if (const EnumType *ETy = QT->getAs<EnumType>())
7940b57cec5SDimitry Andric     QT = ETy->getDecl()->getIntegerType();
7950b57cec5SDimitry Andric 
7960b57cec5SDimitry Andric   const BuiltinType *BT = QT->getAs<BuiltinType>();
7970b57cec5SDimitry Andric   if (!BT) {
7980b57cec5SDimitry Andric     const VectorType *VT = QT->getAs<VectorType>();
7990b57cec5SDimitry Andric     if (VT) {
8000b57cec5SDimitry Andric       QT = VT->getElementType();
8010b57cec5SDimitry Andric       BT = QT->getAs<BuiltinType>();
8020b57cec5SDimitry Andric       VectorNumElts = OptionalAmount(VT->getNumElements());
8030b57cec5SDimitry Andric     }
8040b57cec5SDimitry Andric   }
8050b57cec5SDimitry Andric 
8060b57cec5SDimitry Andric   // We can only work with builtin types.
8070b57cec5SDimitry Andric   if (!BT)
8080b57cec5SDimitry Andric     return false;
8090b57cec5SDimitry Andric 
8100b57cec5SDimitry Andric   // Set length modifier
8110b57cec5SDimitry Andric   switch (BT->getKind()) {
8120b57cec5SDimitry Andric   case BuiltinType::Bool:
8130b57cec5SDimitry Andric   case BuiltinType::WChar_U:
8140b57cec5SDimitry Andric   case BuiltinType::WChar_S:
8150b57cec5SDimitry Andric   case BuiltinType::Char8: // FIXME: Treat like 'char'?
8160b57cec5SDimitry Andric   case BuiltinType::Char16:
8170b57cec5SDimitry Andric   case BuiltinType::Char32:
8180b57cec5SDimitry Andric   case BuiltinType::UInt128:
8190b57cec5SDimitry Andric   case BuiltinType::Int128:
8200b57cec5SDimitry Andric   case BuiltinType::Half:
8215ffd83dbSDimitry Andric   case BuiltinType::BFloat16:
8220b57cec5SDimitry Andric   case BuiltinType::Float16:
8230b57cec5SDimitry Andric   case BuiltinType::Float128:
824349cc55cSDimitry Andric   case BuiltinType::Ibm128:
8250b57cec5SDimitry Andric   case BuiltinType::ShortAccum:
8260b57cec5SDimitry Andric   case BuiltinType::Accum:
8270b57cec5SDimitry Andric   case BuiltinType::LongAccum:
8280b57cec5SDimitry Andric   case BuiltinType::UShortAccum:
8290b57cec5SDimitry Andric   case BuiltinType::UAccum:
8300b57cec5SDimitry Andric   case BuiltinType::ULongAccum:
8310b57cec5SDimitry Andric   case BuiltinType::ShortFract:
8320b57cec5SDimitry Andric   case BuiltinType::Fract:
8330b57cec5SDimitry Andric   case BuiltinType::LongFract:
8340b57cec5SDimitry Andric   case BuiltinType::UShortFract:
8350b57cec5SDimitry Andric   case BuiltinType::UFract:
8360b57cec5SDimitry Andric   case BuiltinType::ULongFract:
8370b57cec5SDimitry Andric   case BuiltinType::SatShortAccum:
8380b57cec5SDimitry Andric   case BuiltinType::SatAccum:
8390b57cec5SDimitry Andric   case BuiltinType::SatLongAccum:
8400b57cec5SDimitry Andric   case BuiltinType::SatUShortAccum:
8410b57cec5SDimitry Andric   case BuiltinType::SatUAccum:
8420b57cec5SDimitry Andric   case BuiltinType::SatULongAccum:
8430b57cec5SDimitry Andric   case BuiltinType::SatShortFract:
8440b57cec5SDimitry Andric   case BuiltinType::SatFract:
8450b57cec5SDimitry Andric   case BuiltinType::SatLongFract:
8460b57cec5SDimitry Andric   case BuiltinType::SatUShortFract:
8470b57cec5SDimitry Andric   case BuiltinType::SatUFract:
8480b57cec5SDimitry Andric   case BuiltinType::SatULongFract:
8490b57cec5SDimitry Andric     // Various types which are non-trivial to correct.
8500b57cec5SDimitry Andric     return false;
8510b57cec5SDimitry Andric 
8520b57cec5SDimitry Andric #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
8530b57cec5SDimitry Andric   case BuiltinType::Id:
8540b57cec5SDimitry Andric #include "clang/Basic/OpenCLImageTypes.def"
8550b57cec5SDimitry Andric #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
8560b57cec5SDimitry Andric   case BuiltinType::Id:
8570b57cec5SDimitry Andric #include "clang/Basic/OpenCLExtensionTypes.def"
858a7dea167SDimitry Andric #define SVE_TYPE(Name, Id, SingletonId) \
859a7dea167SDimitry Andric   case BuiltinType::Id:
860a7dea167SDimitry Andric #include "clang/Basic/AArch64SVEACLETypes.def"
861e8d8bef9SDimitry Andric #define PPC_VECTOR_TYPE(Name, Id, Size) \
862e8d8bef9SDimitry Andric   case BuiltinType::Id:
863e8d8bef9SDimitry Andric #include "clang/Basic/PPCTypes.def"
864fe6060f1SDimitry Andric #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
865fe6060f1SDimitry Andric #include "clang/Basic/RISCVVTypes.def"
86606c3fb27SDimitry Andric #define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
86706c3fb27SDimitry Andric #include "clang/Basic/WebAssemblyReferenceTypes.def"
868*0fca6ea1SDimitry Andric #define AMDGPU_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
869*0fca6ea1SDimitry Andric #include "clang/Basic/AMDGPUTypes.def"
8700b57cec5SDimitry Andric #define SIGNED_TYPE(Id, SingletonId)
8710b57cec5SDimitry Andric #define UNSIGNED_TYPE(Id, SingletonId)
8720b57cec5SDimitry Andric #define FLOATING_TYPE(Id, SingletonId)
8730b57cec5SDimitry Andric #define BUILTIN_TYPE(Id, SingletonId) \
8740b57cec5SDimitry Andric   case BuiltinType::Id:
8750b57cec5SDimitry Andric #include "clang/AST/BuiltinTypes.def"
8760b57cec5SDimitry Andric     // Misc other stuff which doesn't make sense here.
8770b57cec5SDimitry Andric     return false;
8780b57cec5SDimitry Andric 
8790b57cec5SDimitry Andric   case BuiltinType::UInt:
8800b57cec5SDimitry Andric   case BuiltinType::Int:
8810b57cec5SDimitry Andric   case BuiltinType::Float:
8820b57cec5SDimitry Andric     LM.setKind(VectorNumElts.isInvalid() ?
8830b57cec5SDimitry Andric                LengthModifier::None : LengthModifier::AsShortLong);
8840b57cec5SDimitry Andric     break;
8850b57cec5SDimitry Andric   case BuiltinType::Double:
8860b57cec5SDimitry Andric     LM.setKind(VectorNumElts.isInvalid() ?
8870b57cec5SDimitry Andric                LengthModifier::None : LengthModifier::AsLong);
8880b57cec5SDimitry Andric     break;
8890b57cec5SDimitry Andric   case BuiltinType::Char_U:
8900b57cec5SDimitry Andric   case BuiltinType::UChar:
8910b57cec5SDimitry Andric   case BuiltinType::Char_S:
8920b57cec5SDimitry Andric   case BuiltinType::SChar:
8930b57cec5SDimitry Andric     LM.setKind(LengthModifier::AsChar);
8940b57cec5SDimitry Andric     break;
8950b57cec5SDimitry Andric 
8960b57cec5SDimitry Andric   case BuiltinType::Short:
8970b57cec5SDimitry Andric   case BuiltinType::UShort:
8980b57cec5SDimitry Andric     LM.setKind(LengthModifier::AsShort);
8990b57cec5SDimitry Andric     break;
9000b57cec5SDimitry Andric 
9010b57cec5SDimitry Andric   case BuiltinType::Long:
9020b57cec5SDimitry Andric   case BuiltinType::ULong:
9030b57cec5SDimitry Andric     LM.setKind(LengthModifier::AsLong);
9040b57cec5SDimitry Andric     break;
9050b57cec5SDimitry Andric 
9060b57cec5SDimitry Andric   case BuiltinType::LongLong:
9070b57cec5SDimitry Andric   case BuiltinType::ULongLong:
9080b57cec5SDimitry Andric     LM.setKind(LengthModifier::AsLongLong);
9090b57cec5SDimitry Andric     break;
9100b57cec5SDimitry Andric 
9110b57cec5SDimitry Andric   case BuiltinType::LongDouble:
9120b57cec5SDimitry Andric     LM.setKind(LengthModifier::AsLongDouble);
9130b57cec5SDimitry Andric     break;
9140b57cec5SDimitry Andric   }
9150b57cec5SDimitry Andric 
9160b57cec5SDimitry Andric   // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
917bdd1243dSDimitry Andric   if (LangOpt.C99 || LangOpt.CPlusPlus11)
9180b57cec5SDimitry Andric     namedTypeToLengthModifier(QT, LM);
9190b57cec5SDimitry Andric 
9200b57cec5SDimitry Andric   // If fixing the length modifier was enough, we might be done.
9210b57cec5SDimitry Andric   if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
9220b57cec5SDimitry Andric     // If we're going to offer a fix anyway, make sure the sign matches.
9230b57cec5SDimitry Andric     switch (CS.getKind()) {
9240b57cec5SDimitry Andric     case ConversionSpecifier::uArg:
9250b57cec5SDimitry Andric     case ConversionSpecifier::UArg:
9260b57cec5SDimitry Andric       if (QT->isSignedIntegerType())
9270b57cec5SDimitry Andric         CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
9280b57cec5SDimitry Andric       break;
9290b57cec5SDimitry Andric     case ConversionSpecifier::dArg:
9300b57cec5SDimitry Andric     case ConversionSpecifier::DArg:
9310b57cec5SDimitry Andric     case ConversionSpecifier::iArg:
9320b57cec5SDimitry Andric       if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
9330b57cec5SDimitry Andric         CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
9340b57cec5SDimitry Andric       break;
9350b57cec5SDimitry Andric     default:
9360b57cec5SDimitry Andric       // Other specifiers do not have signed/unsigned variants.
9370b57cec5SDimitry Andric       break;
9380b57cec5SDimitry Andric     }
9390b57cec5SDimitry Andric 
9400b57cec5SDimitry Andric     const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
9410b57cec5SDimitry Andric     if (ATR.isValid() && ATR.matchesType(Ctx, QT))
9420b57cec5SDimitry Andric       return true;
9430b57cec5SDimitry Andric   }
9440b57cec5SDimitry Andric 
9450b57cec5SDimitry Andric   // Set conversion specifier and disable any flags which do not apply to it.
9460b57cec5SDimitry Andric   // Let typedefs to char fall through to int, as %c is silly for uint8_t.
947bdd1243dSDimitry Andric   if (!QT->getAs<TypedefType>() && QT->isCharType()) {
9480b57cec5SDimitry Andric     CS.setKind(ConversionSpecifier::cArg);
9490b57cec5SDimitry Andric     LM.setKind(LengthModifier::None);
9500b57cec5SDimitry Andric     Precision.setHowSpecified(OptionalAmount::NotSpecified);
95104eeddc0SDimitry Andric     HasAlternativeForm = false;
95204eeddc0SDimitry Andric     HasLeadingZeroes = false;
95304eeddc0SDimitry Andric     HasPlusPrefix = false;
9540b57cec5SDimitry Andric   }
9550b57cec5SDimitry Andric   // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
9560b57cec5SDimitry Andric   else if (QT->isRealFloatingType()) {
9570b57cec5SDimitry Andric     CS.setKind(ConversionSpecifier::fArg);
958bdd1243dSDimitry Andric   } else if (QT->isSignedIntegerType()) {
9590b57cec5SDimitry Andric     CS.setKind(ConversionSpecifier::dArg);
96004eeddc0SDimitry Andric     HasAlternativeForm = false;
961bdd1243dSDimitry Andric   } else if (QT->isUnsignedIntegerType()) {
9620b57cec5SDimitry Andric     CS.setKind(ConversionSpecifier::uArg);
96304eeddc0SDimitry Andric     HasAlternativeForm = false;
96404eeddc0SDimitry Andric     HasPlusPrefix = false;
9650b57cec5SDimitry Andric   } else {
9660b57cec5SDimitry Andric     llvm_unreachable("Unexpected type");
9670b57cec5SDimitry Andric   }
9680b57cec5SDimitry Andric 
9690b57cec5SDimitry Andric   return true;
9700b57cec5SDimitry Andric }
9710b57cec5SDimitry Andric 
9720b57cec5SDimitry Andric void PrintfSpecifier::toString(raw_ostream &os) const {
9730b57cec5SDimitry Andric   // Whilst some features have no defined order, we are using the order
9740b57cec5SDimitry Andric   // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
9750b57cec5SDimitry Andric   os << "%";
9760b57cec5SDimitry Andric 
9770b57cec5SDimitry Andric   // Positional args
9780b57cec5SDimitry Andric   if (usesPositionalArg()) {
9790b57cec5SDimitry Andric     os << getPositionalArgIndex() << "$";
9800b57cec5SDimitry Andric   }
9810b57cec5SDimitry Andric 
9820b57cec5SDimitry Andric   // Conversion flags
9830b57cec5SDimitry Andric   if (IsLeftJustified)    os << "-";
9840b57cec5SDimitry Andric   if (HasPlusPrefix)      os << "+";
9850b57cec5SDimitry Andric   if (HasSpacePrefix)     os << " ";
9860b57cec5SDimitry Andric   if (HasAlternativeForm) os << "#";
9870b57cec5SDimitry Andric   if (HasLeadingZeroes)   os << "0";
9880b57cec5SDimitry Andric 
9890b57cec5SDimitry Andric   // Minimum field width
9900b57cec5SDimitry Andric   FieldWidth.toString(os);
9910b57cec5SDimitry Andric   // Precision
9920b57cec5SDimitry Andric   Precision.toString(os);
9930b57cec5SDimitry Andric 
9940b57cec5SDimitry Andric   // Vector modifier
9950b57cec5SDimitry Andric   if (!VectorNumElts.isInvalid())
9960b57cec5SDimitry Andric     os << 'v' << VectorNumElts.getConstantAmount();
9970b57cec5SDimitry Andric 
9980b57cec5SDimitry Andric   // Length modifier
9990b57cec5SDimitry Andric   os << LM.toString();
10000b57cec5SDimitry Andric   // Conversion specifier
10010b57cec5SDimitry Andric   os << CS.toString();
10020b57cec5SDimitry Andric }
10030b57cec5SDimitry Andric 
10040b57cec5SDimitry Andric bool PrintfSpecifier::hasValidPlusPrefix() const {
10050b57cec5SDimitry Andric   if (!HasPlusPrefix)
10060b57cec5SDimitry Andric     return true;
10070b57cec5SDimitry Andric 
10080b57cec5SDimitry Andric   // The plus prefix only makes sense for signed conversions
10090b57cec5SDimitry Andric   switch (CS.getKind()) {
10100b57cec5SDimitry Andric   case ConversionSpecifier::dArg:
10110b57cec5SDimitry Andric   case ConversionSpecifier::DArg:
10120b57cec5SDimitry Andric   case ConversionSpecifier::iArg:
10130b57cec5SDimitry Andric   case ConversionSpecifier::fArg:
10140b57cec5SDimitry Andric   case ConversionSpecifier::FArg:
10150b57cec5SDimitry Andric   case ConversionSpecifier::eArg:
10160b57cec5SDimitry Andric   case ConversionSpecifier::EArg:
10170b57cec5SDimitry Andric   case ConversionSpecifier::gArg:
10180b57cec5SDimitry Andric   case ConversionSpecifier::GArg:
10190b57cec5SDimitry Andric   case ConversionSpecifier::aArg:
10200b57cec5SDimitry Andric   case ConversionSpecifier::AArg:
10210b57cec5SDimitry Andric   case ConversionSpecifier::FreeBSDrArg:
10220b57cec5SDimitry Andric   case ConversionSpecifier::FreeBSDyArg:
1023*0fca6ea1SDimitry Andric   case ConversionSpecifier::rArg:
1024*0fca6ea1SDimitry Andric   case ConversionSpecifier::kArg:
10250b57cec5SDimitry Andric     return true;
10260b57cec5SDimitry Andric 
10270b57cec5SDimitry Andric   default:
10280b57cec5SDimitry Andric     return false;
10290b57cec5SDimitry Andric   }
10300b57cec5SDimitry Andric }
10310b57cec5SDimitry Andric 
10320b57cec5SDimitry Andric bool PrintfSpecifier::hasValidAlternativeForm() const {
10330b57cec5SDimitry Andric   if (!HasAlternativeForm)
10340b57cec5SDimitry Andric     return true;
10350b57cec5SDimitry Andric 
1036*0fca6ea1SDimitry Andric   // Alternate form flag only valid with the bBoxXaAeEfFgGrRkK conversions
10370b57cec5SDimitry Andric   switch (CS.getKind()) {
1038bdd1243dSDimitry Andric   case ConversionSpecifier::bArg:
1039bdd1243dSDimitry Andric   case ConversionSpecifier::BArg:
10400b57cec5SDimitry Andric   case ConversionSpecifier::oArg:
10410b57cec5SDimitry Andric   case ConversionSpecifier::OArg:
10420b57cec5SDimitry Andric   case ConversionSpecifier::xArg:
10430b57cec5SDimitry Andric   case ConversionSpecifier::XArg:
10440b57cec5SDimitry Andric   case ConversionSpecifier::aArg:
10450b57cec5SDimitry Andric   case ConversionSpecifier::AArg:
10460b57cec5SDimitry Andric   case ConversionSpecifier::eArg:
10470b57cec5SDimitry Andric   case ConversionSpecifier::EArg:
10480b57cec5SDimitry Andric   case ConversionSpecifier::fArg:
10490b57cec5SDimitry Andric   case ConversionSpecifier::FArg:
10500b57cec5SDimitry Andric   case ConversionSpecifier::gArg:
10510b57cec5SDimitry Andric   case ConversionSpecifier::GArg:
10520b57cec5SDimitry Andric   case ConversionSpecifier::FreeBSDrArg:
10530b57cec5SDimitry Andric   case ConversionSpecifier::FreeBSDyArg:
1054*0fca6ea1SDimitry Andric   case ConversionSpecifier::rArg:
1055*0fca6ea1SDimitry Andric   case ConversionSpecifier::RArg:
1056*0fca6ea1SDimitry Andric   case ConversionSpecifier::kArg:
1057*0fca6ea1SDimitry Andric   case ConversionSpecifier::KArg:
10580b57cec5SDimitry Andric     return true;
10590b57cec5SDimitry Andric 
10600b57cec5SDimitry Andric   default:
10610b57cec5SDimitry Andric     return false;
10620b57cec5SDimitry Andric   }
10630b57cec5SDimitry Andric }
10640b57cec5SDimitry Andric 
10650b57cec5SDimitry Andric bool PrintfSpecifier::hasValidLeadingZeros() const {
10660b57cec5SDimitry Andric   if (!HasLeadingZeroes)
10670b57cec5SDimitry Andric     return true;
10680b57cec5SDimitry Andric 
1069*0fca6ea1SDimitry Andric   // Leading zeroes flag only valid with the bBdiouxXaAeEfFgGrRkK conversions
10700b57cec5SDimitry Andric   switch (CS.getKind()) {
1071bdd1243dSDimitry Andric   case ConversionSpecifier::bArg:
1072bdd1243dSDimitry Andric   case ConversionSpecifier::BArg:
10730b57cec5SDimitry Andric   case ConversionSpecifier::dArg:
10740b57cec5SDimitry Andric   case ConversionSpecifier::DArg:
10750b57cec5SDimitry Andric   case ConversionSpecifier::iArg:
10760b57cec5SDimitry Andric   case ConversionSpecifier::oArg:
10770b57cec5SDimitry Andric   case ConversionSpecifier::OArg:
10780b57cec5SDimitry Andric   case ConversionSpecifier::uArg:
10790b57cec5SDimitry Andric   case ConversionSpecifier::UArg:
10800b57cec5SDimitry Andric   case ConversionSpecifier::xArg:
10810b57cec5SDimitry Andric   case ConversionSpecifier::XArg:
10820b57cec5SDimitry Andric   case ConversionSpecifier::aArg:
10830b57cec5SDimitry Andric   case ConversionSpecifier::AArg:
10840b57cec5SDimitry Andric   case ConversionSpecifier::eArg:
10850b57cec5SDimitry Andric   case ConversionSpecifier::EArg:
10860b57cec5SDimitry Andric   case ConversionSpecifier::fArg:
10870b57cec5SDimitry Andric   case ConversionSpecifier::FArg:
10880b57cec5SDimitry Andric   case ConversionSpecifier::gArg:
10890b57cec5SDimitry Andric   case ConversionSpecifier::GArg:
10900b57cec5SDimitry Andric   case ConversionSpecifier::FreeBSDrArg:
10910b57cec5SDimitry Andric   case ConversionSpecifier::FreeBSDyArg:
1092*0fca6ea1SDimitry Andric   case ConversionSpecifier::rArg:
1093*0fca6ea1SDimitry Andric   case ConversionSpecifier::RArg:
1094*0fca6ea1SDimitry Andric   case ConversionSpecifier::kArg:
1095*0fca6ea1SDimitry Andric   case ConversionSpecifier::KArg:
10960b57cec5SDimitry Andric     return true;
10970b57cec5SDimitry Andric 
10980b57cec5SDimitry Andric   default:
10990b57cec5SDimitry Andric     return false;
11000b57cec5SDimitry Andric   }
11010b57cec5SDimitry Andric }
11020b57cec5SDimitry Andric 
11030b57cec5SDimitry Andric bool PrintfSpecifier::hasValidSpacePrefix() const {
11040b57cec5SDimitry Andric   if (!HasSpacePrefix)
11050b57cec5SDimitry Andric     return true;
11060b57cec5SDimitry Andric 
11070b57cec5SDimitry Andric   // The space prefix only makes sense for signed conversions
11080b57cec5SDimitry Andric   switch (CS.getKind()) {
11090b57cec5SDimitry Andric   case ConversionSpecifier::dArg:
11100b57cec5SDimitry Andric   case ConversionSpecifier::DArg:
11110b57cec5SDimitry Andric   case ConversionSpecifier::iArg:
11120b57cec5SDimitry Andric   case ConversionSpecifier::fArg:
11130b57cec5SDimitry Andric   case ConversionSpecifier::FArg:
11140b57cec5SDimitry Andric   case ConversionSpecifier::eArg:
11150b57cec5SDimitry Andric   case ConversionSpecifier::EArg:
11160b57cec5SDimitry Andric   case ConversionSpecifier::gArg:
11170b57cec5SDimitry Andric   case ConversionSpecifier::GArg:
11180b57cec5SDimitry Andric   case ConversionSpecifier::aArg:
11190b57cec5SDimitry Andric   case ConversionSpecifier::AArg:
11200b57cec5SDimitry Andric   case ConversionSpecifier::FreeBSDrArg:
11210b57cec5SDimitry Andric   case ConversionSpecifier::FreeBSDyArg:
1122*0fca6ea1SDimitry Andric   case ConversionSpecifier::rArg:
1123*0fca6ea1SDimitry Andric   case ConversionSpecifier::kArg:
11240b57cec5SDimitry Andric     return true;
11250b57cec5SDimitry Andric 
11260b57cec5SDimitry Andric   default:
11270b57cec5SDimitry Andric     return false;
11280b57cec5SDimitry Andric   }
11290b57cec5SDimitry Andric }
11300b57cec5SDimitry Andric 
11310b57cec5SDimitry Andric bool PrintfSpecifier::hasValidLeftJustified() const {
11320b57cec5SDimitry Andric   if (!IsLeftJustified)
11330b57cec5SDimitry Andric     return true;
11340b57cec5SDimitry Andric 
11350b57cec5SDimitry Andric   // The left justified flag is valid for all conversions except n
11360b57cec5SDimitry Andric   switch (CS.getKind()) {
11370b57cec5SDimitry Andric   case ConversionSpecifier::nArg:
11380b57cec5SDimitry Andric     return false;
11390b57cec5SDimitry Andric 
11400b57cec5SDimitry Andric   default:
11410b57cec5SDimitry Andric     return true;
11420b57cec5SDimitry Andric   }
11430b57cec5SDimitry Andric }
11440b57cec5SDimitry Andric 
11450b57cec5SDimitry Andric bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
11460b57cec5SDimitry Andric   if (!HasThousandsGrouping)
11470b57cec5SDimitry Andric     return true;
11480b57cec5SDimitry Andric 
11490b57cec5SDimitry Andric   switch (CS.getKind()) {
11500b57cec5SDimitry Andric     case ConversionSpecifier::dArg:
11510b57cec5SDimitry Andric     case ConversionSpecifier::DArg:
11520b57cec5SDimitry Andric     case ConversionSpecifier::iArg:
11530b57cec5SDimitry Andric     case ConversionSpecifier::uArg:
11540b57cec5SDimitry Andric     case ConversionSpecifier::UArg:
11550b57cec5SDimitry Andric     case ConversionSpecifier::fArg:
11560b57cec5SDimitry Andric     case ConversionSpecifier::FArg:
11570b57cec5SDimitry Andric     case ConversionSpecifier::gArg:
11580b57cec5SDimitry Andric     case ConversionSpecifier::GArg:
11590b57cec5SDimitry Andric       return true;
11600b57cec5SDimitry Andric     default:
11610b57cec5SDimitry Andric       return false;
11620b57cec5SDimitry Andric   }
11630b57cec5SDimitry Andric }
11640b57cec5SDimitry Andric 
11650b57cec5SDimitry Andric bool PrintfSpecifier::hasValidPrecision() const {
11660b57cec5SDimitry Andric   if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
11670b57cec5SDimitry Andric     return true;
11680b57cec5SDimitry Andric 
1169*0fca6ea1SDimitry Andric   // Precision is only valid with the bBdiouxXaAeEfFgGsPrRkK conversions
11700b57cec5SDimitry Andric   switch (CS.getKind()) {
1171bdd1243dSDimitry Andric   case ConversionSpecifier::bArg:
1172bdd1243dSDimitry Andric   case ConversionSpecifier::BArg:
11730b57cec5SDimitry Andric   case ConversionSpecifier::dArg:
11740b57cec5SDimitry Andric   case ConversionSpecifier::DArg:
11750b57cec5SDimitry Andric   case ConversionSpecifier::iArg:
11760b57cec5SDimitry Andric   case ConversionSpecifier::oArg:
11770b57cec5SDimitry Andric   case ConversionSpecifier::OArg:
11780b57cec5SDimitry Andric   case ConversionSpecifier::uArg:
11790b57cec5SDimitry Andric   case ConversionSpecifier::UArg:
11800b57cec5SDimitry Andric   case ConversionSpecifier::xArg:
11810b57cec5SDimitry Andric   case ConversionSpecifier::XArg:
11820b57cec5SDimitry Andric   case ConversionSpecifier::aArg:
11830b57cec5SDimitry Andric   case ConversionSpecifier::AArg:
11840b57cec5SDimitry Andric   case ConversionSpecifier::eArg:
11850b57cec5SDimitry Andric   case ConversionSpecifier::EArg:
11860b57cec5SDimitry Andric   case ConversionSpecifier::fArg:
11870b57cec5SDimitry Andric   case ConversionSpecifier::FArg:
11880b57cec5SDimitry Andric   case ConversionSpecifier::gArg:
11890b57cec5SDimitry Andric   case ConversionSpecifier::GArg:
11900b57cec5SDimitry Andric   case ConversionSpecifier::sArg:
11910b57cec5SDimitry Andric   case ConversionSpecifier::FreeBSDrArg:
11920b57cec5SDimitry Andric   case ConversionSpecifier::FreeBSDyArg:
11930b57cec5SDimitry Andric   case ConversionSpecifier::PArg:
1194*0fca6ea1SDimitry Andric   case ConversionSpecifier::rArg:
1195*0fca6ea1SDimitry Andric   case ConversionSpecifier::RArg:
1196*0fca6ea1SDimitry Andric   case ConversionSpecifier::kArg:
1197*0fca6ea1SDimitry Andric   case ConversionSpecifier::KArg:
11980b57cec5SDimitry Andric     return true;
11990b57cec5SDimitry Andric 
12000b57cec5SDimitry Andric   default:
12010b57cec5SDimitry Andric     return false;
12020b57cec5SDimitry Andric   }
12030b57cec5SDimitry Andric }
12040b57cec5SDimitry Andric bool PrintfSpecifier::hasValidFieldWidth() const {
12050b57cec5SDimitry Andric   if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
12060b57cec5SDimitry Andric       return true;
12070b57cec5SDimitry Andric 
12080b57cec5SDimitry Andric   // The field width is valid for all conversions except n
12090b57cec5SDimitry Andric   switch (CS.getKind()) {
12100b57cec5SDimitry Andric   case ConversionSpecifier::nArg:
12110b57cec5SDimitry Andric     return false;
12120b57cec5SDimitry Andric 
12130b57cec5SDimitry Andric   default:
12140b57cec5SDimitry Andric     return true;
12150b57cec5SDimitry Andric   }
12160b57cec5SDimitry Andric }
1217