xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/AST/PrintfFormatString.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // Handling of format string in printf and friends.  The structure of format
107330f729Sjoerg // strings for fprintf() are described in C99 7.19.6.1.
117330f729Sjoerg //
127330f729Sjoerg //===----------------------------------------------------------------------===//
137330f729Sjoerg 
14*e038c9c4Sjoerg #include "FormatStringParsing.h"
157330f729Sjoerg #include "clang/AST/FormatString.h"
167330f729Sjoerg #include "clang/AST/OSLog.h"
177330f729Sjoerg #include "clang/Basic/TargetInfo.h"
18*e038c9c4Sjoerg #include "llvm/Support/Regex.h"
197330f729Sjoerg 
207330f729Sjoerg using clang::analyze_format_string::ArgType;
217330f729Sjoerg using clang::analyze_format_string::FormatStringHandler;
227330f729Sjoerg using clang::analyze_format_string::LengthModifier;
237330f729Sjoerg using clang::analyze_format_string::OptionalAmount;
247330f729Sjoerg using clang::analyze_format_string::ConversionSpecifier;
257330f729Sjoerg using clang::analyze_printf::PrintfSpecifier;
267330f729Sjoerg 
277330f729Sjoerg using namespace clang;
287330f729Sjoerg 
297330f729Sjoerg typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
307330f729Sjoerg         PrintfSpecifierResult;
317330f729Sjoerg 
327330f729Sjoerg //===----------------------------------------------------------------------===//
337330f729Sjoerg // Methods for parsing format strings.
347330f729Sjoerg //===----------------------------------------------------------------------===//
357330f729Sjoerg 
367330f729Sjoerg using analyze_format_string::ParseNonPositionAmount;
377330f729Sjoerg 
ParsePrecision(FormatStringHandler & H,PrintfSpecifier & FS,const char * Start,const char * & Beg,const char * E,unsigned * argIndex)387330f729Sjoerg static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
397330f729Sjoerg                            const char *Start, const char *&Beg, const char *E,
407330f729Sjoerg                            unsigned *argIndex) {
417330f729Sjoerg   if (argIndex) {
427330f729Sjoerg     FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
437330f729Sjoerg   } else {
447330f729Sjoerg     const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
457330f729Sjoerg                                            analyze_format_string::PrecisionPos);
467330f729Sjoerg     if (Amt.isInvalid())
477330f729Sjoerg       return true;
487330f729Sjoerg     FS.setPrecision(Amt);
497330f729Sjoerg   }
507330f729Sjoerg   return false;
517330f729Sjoerg }
527330f729Sjoerg 
ParseObjCFlags(FormatStringHandler & H,PrintfSpecifier & FS,const char * FlagBeg,const char * E,bool Warn)537330f729Sjoerg static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,
547330f729Sjoerg                            const char *FlagBeg, const char *E, bool Warn) {
557330f729Sjoerg    StringRef Flag(FlagBeg, E - FlagBeg);
567330f729Sjoerg    // Currently there is only one flag.
577330f729Sjoerg    if (Flag == "tt") {
587330f729Sjoerg      FS.setHasObjCTechnicalTerm(FlagBeg);
597330f729Sjoerg      return false;
607330f729Sjoerg    }
617330f729Sjoerg    // Handle either the case of no flag or an invalid flag.
627330f729Sjoerg    if (Warn) {
637330f729Sjoerg      if (Flag == "")
647330f729Sjoerg        H.HandleEmptyObjCModifierFlag(FlagBeg, E  - FlagBeg);
657330f729Sjoerg      else
667330f729Sjoerg        H.HandleInvalidObjCModifierFlag(FlagBeg, E  - FlagBeg);
677330f729Sjoerg    }
687330f729Sjoerg    return true;
697330f729Sjoerg }
707330f729Sjoerg 
ParsePrintfSpecifier(FormatStringHandler & H,const char * & Beg,const char * E,unsigned & argIndex,const LangOptions & LO,const TargetInfo & Target,bool Warn,bool isFreeBSDKPrintf)717330f729Sjoerg static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
727330f729Sjoerg                                                   const char *&Beg,
737330f729Sjoerg                                                   const char *E,
747330f729Sjoerg                                                   unsigned &argIndex,
757330f729Sjoerg                                                   const LangOptions &LO,
767330f729Sjoerg                                                   const TargetInfo &Target,
777330f729Sjoerg                                                   bool Warn,
787330f729Sjoerg                                                   bool isFreeBSDKPrintf) {
797330f729Sjoerg 
807330f729Sjoerg   using namespace clang::analyze_format_string;
817330f729Sjoerg   using namespace clang::analyze_printf;
827330f729Sjoerg 
837330f729Sjoerg   const char *I = Beg;
847330f729Sjoerg   const char *Start = nullptr;
857330f729Sjoerg   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
867330f729Sjoerg 
877330f729Sjoerg   // Look for a '%' character that indicates the start of a format specifier.
887330f729Sjoerg   for ( ; I != E ; ++I) {
897330f729Sjoerg     char c = *I;
907330f729Sjoerg     if (c == '\0') {
917330f729Sjoerg       // Detect spurious null characters, which are likely errors.
927330f729Sjoerg       H.HandleNullChar(I);
937330f729Sjoerg       return true;
947330f729Sjoerg     }
957330f729Sjoerg     if (c == '%') {
967330f729Sjoerg       Start = I++;  // Record the start of the format specifier.
977330f729Sjoerg       break;
987330f729Sjoerg     }
997330f729Sjoerg   }
1007330f729Sjoerg 
1017330f729Sjoerg   // No format specifier found?
1027330f729Sjoerg   if (!Start)
1037330f729Sjoerg     return false;
1047330f729Sjoerg 
1057330f729Sjoerg   if (I == E) {
1067330f729Sjoerg     // No more characters left?
1077330f729Sjoerg     if (Warn)
1087330f729Sjoerg       H.HandleIncompleteSpecifier(Start, E - Start);
1097330f729Sjoerg     return true;
1107330f729Sjoerg   }
1117330f729Sjoerg 
1127330f729Sjoerg   PrintfSpecifier FS;
1137330f729Sjoerg   if (ParseArgPosition(H, FS, Start, I, E))
1147330f729Sjoerg     return true;
1157330f729Sjoerg 
1167330f729Sjoerg   if (I == E) {
1177330f729Sjoerg     // No more characters left?
1187330f729Sjoerg     if (Warn)
1197330f729Sjoerg       H.HandleIncompleteSpecifier(Start, E - Start);
1207330f729Sjoerg     return true;
1217330f729Sjoerg   }
1227330f729Sjoerg 
1237330f729Sjoerg   if (*I == '{') {
1247330f729Sjoerg     ++I;
1257330f729Sjoerg     unsigned char PrivacyFlags = 0;
1267330f729Sjoerg     StringRef MatchedStr;
1277330f729Sjoerg 
1287330f729Sjoerg     do {
1297330f729Sjoerg       StringRef Str(I, E - I);
1307330f729Sjoerg       std::string Match = "^[[:space:]]*"
1317330f729Sjoerg                           "(private|public|sensitive|mask\\.[^[:space:],}]*)"
1327330f729Sjoerg                           "[[:space:]]*(,|})";
1337330f729Sjoerg       llvm::Regex R(Match);
1347330f729Sjoerg       SmallVector<StringRef, 2> Matches;
1357330f729Sjoerg 
1367330f729Sjoerg       if (R.match(Str, &Matches)) {
1377330f729Sjoerg         MatchedStr = Matches[1];
1387330f729Sjoerg         I += Matches[0].size();
1397330f729Sjoerg 
1407330f729Sjoerg         // Set the privacy flag if the privacy annotation in the
1417330f729Sjoerg         // comma-delimited segment is at least as strict as the privacy
1427330f729Sjoerg         // annotations in previous comma-delimited segments.
1437330f729Sjoerg         if (MatchedStr.startswith("mask")) {
1447330f729Sjoerg           StringRef MaskType = MatchedStr.substr(sizeof("mask.") - 1);
1457330f729Sjoerg           unsigned Size = MaskType.size();
1467330f729Sjoerg           if (Warn && (Size == 0 || Size > 8))
1477330f729Sjoerg             H.handleInvalidMaskType(MaskType);
1487330f729Sjoerg           FS.setMaskType(MaskType);
1497330f729Sjoerg         } else if (MatchedStr.equals("sensitive"))
1507330f729Sjoerg           PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsSensitive;
1517330f729Sjoerg         else if (PrivacyFlags !=
1527330f729Sjoerg                  clang::analyze_os_log::OSLogBufferItem::IsSensitive &&
1537330f729Sjoerg                  MatchedStr.equals("private"))
1547330f729Sjoerg           PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate;
1557330f729Sjoerg         else if (PrivacyFlags == 0 && MatchedStr.equals("public"))
1567330f729Sjoerg           PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic;
1577330f729Sjoerg       } else {
1587330f729Sjoerg         size_t CommaOrBracePos =
1597330f729Sjoerg             Str.find_if([](char c) { return c == ',' || c == '}'; });
1607330f729Sjoerg 
1617330f729Sjoerg         if (CommaOrBracePos == StringRef::npos) {
1627330f729Sjoerg           // Neither a comma nor the closing brace was found.
1637330f729Sjoerg           if (Warn)
1647330f729Sjoerg             H.HandleIncompleteSpecifier(Start, E - Start);
1657330f729Sjoerg           return true;
1667330f729Sjoerg         }
1677330f729Sjoerg 
1687330f729Sjoerg         I += CommaOrBracePos + 1;
1697330f729Sjoerg       }
1707330f729Sjoerg       // Continue until the closing brace is found.
1717330f729Sjoerg     } while (*(I - 1) == ',');
1727330f729Sjoerg 
1737330f729Sjoerg     // Set the privacy flag.
1747330f729Sjoerg     switch (PrivacyFlags) {
1757330f729Sjoerg     case 0:
1767330f729Sjoerg       break;
1777330f729Sjoerg     case clang::analyze_os_log::OSLogBufferItem::IsPrivate:
1787330f729Sjoerg       FS.setIsPrivate(MatchedStr.data());
1797330f729Sjoerg       break;
1807330f729Sjoerg     case clang::analyze_os_log::OSLogBufferItem::IsPublic:
1817330f729Sjoerg       FS.setIsPublic(MatchedStr.data());
1827330f729Sjoerg       break;
1837330f729Sjoerg     case clang::analyze_os_log::OSLogBufferItem::IsSensitive:
1847330f729Sjoerg       FS.setIsSensitive(MatchedStr.data());
1857330f729Sjoerg       break;
1867330f729Sjoerg     default:
1877330f729Sjoerg       llvm_unreachable("Unexpected privacy flag value");
1887330f729Sjoerg     }
1897330f729Sjoerg   }
1907330f729Sjoerg 
1917330f729Sjoerg   // Look for flags (if any).
1927330f729Sjoerg   bool hasMore = true;
1937330f729Sjoerg   for ( ; I != E; ++I) {
1947330f729Sjoerg     switch (*I) {
1957330f729Sjoerg       default: hasMore = false; break;
1967330f729Sjoerg       case '\'':
1977330f729Sjoerg         // FIXME: POSIX specific.  Always accept?
1987330f729Sjoerg         FS.setHasThousandsGrouping(I);
1997330f729Sjoerg         break;
2007330f729Sjoerg       case '-': FS.setIsLeftJustified(I); break;
2017330f729Sjoerg       case '+': FS.setHasPlusPrefix(I); break;
2027330f729Sjoerg       case ' ': FS.setHasSpacePrefix(I); break;
2037330f729Sjoerg       case '#': FS.setHasAlternativeForm(I); break;
2047330f729Sjoerg       case '0': FS.setHasLeadingZeros(I); break;
2057330f729Sjoerg     }
2067330f729Sjoerg     if (!hasMore)
2077330f729Sjoerg       break;
2087330f729Sjoerg   }
2097330f729Sjoerg 
2107330f729Sjoerg   if (I == E) {
2117330f729Sjoerg     // No more characters left?
2127330f729Sjoerg     if (Warn)
2137330f729Sjoerg       H.HandleIncompleteSpecifier(Start, E - Start);
2147330f729Sjoerg     return true;
2157330f729Sjoerg   }
2167330f729Sjoerg 
2177330f729Sjoerg   // Look for the field width (if any).
2187330f729Sjoerg   if (ParseFieldWidth(H, FS, Start, I, E,
2197330f729Sjoerg                       FS.usesPositionalArg() ? nullptr : &argIndex))
2207330f729Sjoerg     return true;
2217330f729Sjoerg 
2227330f729Sjoerg   if (I == E) {
2237330f729Sjoerg     // No more characters left?
2247330f729Sjoerg     if (Warn)
2257330f729Sjoerg       H.HandleIncompleteSpecifier(Start, E - Start);
2267330f729Sjoerg     return true;
2277330f729Sjoerg   }
2287330f729Sjoerg 
2297330f729Sjoerg   // Look for the precision (if any).
2307330f729Sjoerg   if (*I == '.') {
2317330f729Sjoerg     ++I;
2327330f729Sjoerg     if (I == E) {
2337330f729Sjoerg       if (Warn)
2347330f729Sjoerg         H.HandleIncompleteSpecifier(Start, E - Start);
2357330f729Sjoerg       return true;
2367330f729Sjoerg     }
2377330f729Sjoerg 
2387330f729Sjoerg     if (ParsePrecision(H, FS, Start, I, E,
2397330f729Sjoerg                        FS.usesPositionalArg() ? nullptr : &argIndex))
2407330f729Sjoerg       return true;
2417330f729Sjoerg 
2427330f729Sjoerg     if (I == E) {
2437330f729Sjoerg       // No more characters left?
2447330f729Sjoerg       if (Warn)
2457330f729Sjoerg         H.HandleIncompleteSpecifier(Start, E - Start);
2467330f729Sjoerg       return true;
2477330f729Sjoerg     }
2487330f729Sjoerg   }
2497330f729Sjoerg 
2507330f729Sjoerg   if (ParseVectorModifier(H, FS, I, E, LO))
2517330f729Sjoerg     return true;
2527330f729Sjoerg 
2537330f729Sjoerg   // Look for the length modifier.
2547330f729Sjoerg   if (ParseLengthModifier(FS, I, E, LO) && I == E) {
2557330f729Sjoerg     // No more characters left?
2567330f729Sjoerg     if (Warn)
2577330f729Sjoerg       H.HandleIncompleteSpecifier(Start, E - Start);
2587330f729Sjoerg     return true;
2597330f729Sjoerg   }
2607330f729Sjoerg 
2617330f729Sjoerg   // Look for the Objective-C modifier flags, if any.
2627330f729Sjoerg   // We parse these here, even if they don't apply to
2637330f729Sjoerg   // the conversion specifier, and then emit an error
2647330f729Sjoerg   // later if the conversion specifier isn't '@'.  This
2657330f729Sjoerg   // enables better recovery, and we don't know if
2667330f729Sjoerg   // these flags are applicable until later.
2677330f729Sjoerg   const char *ObjCModifierFlagsStart = nullptr,
2687330f729Sjoerg              *ObjCModifierFlagsEnd = nullptr;
2697330f729Sjoerg   if (*I == '[') {
2707330f729Sjoerg     ObjCModifierFlagsStart = I;
2717330f729Sjoerg     ++I;
2727330f729Sjoerg     auto flagStart = I;
2737330f729Sjoerg     for (;; ++I) {
2747330f729Sjoerg       ObjCModifierFlagsEnd = I;
2757330f729Sjoerg       if (I == E) {
2767330f729Sjoerg         if (Warn)
2777330f729Sjoerg           H.HandleIncompleteSpecifier(Start, E - Start);
2787330f729Sjoerg         return true;
2797330f729Sjoerg       }
2807330f729Sjoerg       // Did we find the closing ']'?
2817330f729Sjoerg       if (*I == ']') {
2827330f729Sjoerg         if (ParseObjCFlags(H, FS, flagStart, I, Warn))
2837330f729Sjoerg           return true;
2847330f729Sjoerg         ++I;
2857330f729Sjoerg         break;
2867330f729Sjoerg       }
2877330f729Sjoerg       // There are no separators defined yet for multiple
2887330f729Sjoerg       // Objective-C modifier flags.  When those are
2897330f729Sjoerg       // defined, this is the place to check.
2907330f729Sjoerg     }
2917330f729Sjoerg   }
2927330f729Sjoerg 
2937330f729Sjoerg   if (*I == '\0') {
2947330f729Sjoerg     // Detect spurious null characters, which are likely errors.
2957330f729Sjoerg     H.HandleNullChar(I);
2967330f729Sjoerg     return true;
2977330f729Sjoerg   }
2987330f729Sjoerg 
2997330f729Sjoerg   // Finally, look for the conversion specifier.
3007330f729Sjoerg   const char *conversionPosition = I++;
3017330f729Sjoerg   ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
3027330f729Sjoerg   switch (*conversionPosition) {
3037330f729Sjoerg     default:
3047330f729Sjoerg       break;
3057330f729Sjoerg     // C99: 7.19.6.1 (section 8).
3067330f729Sjoerg     case '%': k = ConversionSpecifier::PercentArg;   break;
3077330f729Sjoerg     case 'A': k = ConversionSpecifier::AArg; break;
3087330f729Sjoerg     case 'E': k = ConversionSpecifier::EArg; break;
3097330f729Sjoerg     case 'F': k = ConversionSpecifier::FArg; break;
3107330f729Sjoerg     case 'G': k = ConversionSpecifier::GArg; break;
3117330f729Sjoerg     case 'X': k = ConversionSpecifier::XArg; break;
3127330f729Sjoerg     case 'a': k = ConversionSpecifier::aArg; break;
3137330f729Sjoerg     case 'c': k = ConversionSpecifier::cArg; break;
3147330f729Sjoerg     case 'd': k = ConversionSpecifier::dArg; break;
3157330f729Sjoerg     case 'e': k = ConversionSpecifier::eArg; break;
3167330f729Sjoerg     case 'f': k = ConversionSpecifier::fArg; break;
3177330f729Sjoerg     case 'g': k = ConversionSpecifier::gArg; break;
3187330f729Sjoerg     case 'i': k = ConversionSpecifier::iArg; break;
3197330f729Sjoerg     case 'n':
3207330f729Sjoerg       // Not handled, but reserved in OpenCL.
3217330f729Sjoerg       if (!LO.OpenCL)
3227330f729Sjoerg         k = ConversionSpecifier::nArg;
3237330f729Sjoerg       break;
3247330f729Sjoerg     case 'o': k = ConversionSpecifier::oArg; break;
3257330f729Sjoerg     case 'p': k = ConversionSpecifier::pArg; break;
3267330f729Sjoerg     case 's': k = ConversionSpecifier::sArg; break;
3277330f729Sjoerg     case 'u': k = ConversionSpecifier::uArg; break;
3287330f729Sjoerg     case 'x': k = ConversionSpecifier::xArg; break;
3297330f729Sjoerg     // POSIX specific.
3307330f729Sjoerg     case 'C': k = ConversionSpecifier::CArg; break;
3317330f729Sjoerg     case 'S': k = ConversionSpecifier::SArg; break;
3327330f729Sjoerg     // Apple extension for os_log
3337330f729Sjoerg     case 'P':
3347330f729Sjoerg       k = ConversionSpecifier::PArg;
3357330f729Sjoerg       break;
3367330f729Sjoerg     // Objective-C.
3377330f729Sjoerg     case '@': k = ConversionSpecifier::ObjCObjArg; break;
3387330f729Sjoerg     // Glibc specific.
3397330f729Sjoerg     case 'm': k = ConversionSpecifier::PrintErrno; break;
3407330f729Sjoerg     // FreeBSD kernel specific.
3417330f729Sjoerg     case 'b':
3427330f729Sjoerg       if (isFreeBSDKPrintf)
3437330f729Sjoerg         k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
3447330f729Sjoerg       break;
3457330f729Sjoerg     case 'r':
3467330f729Sjoerg       if (isFreeBSDKPrintf)
3477330f729Sjoerg         k = ConversionSpecifier::FreeBSDrArg; // int
3487330f729Sjoerg       break;
3497330f729Sjoerg     case 'y':
3507330f729Sjoerg       if (isFreeBSDKPrintf)
3517330f729Sjoerg         k = ConversionSpecifier::FreeBSDyArg; // int
3527330f729Sjoerg       break;
3537330f729Sjoerg     // Apple-specific.
3547330f729Sjoerg     case 'D':
3557330f729Sjoerg       if (isFreeBSDKPrintf)
3567330f729Sjoerg         k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *
3577330f729Sjoerg       else if (Target.getTriple().isOSDarwin())
3587330f729Sjoerg         k = ConversionSpecifier::DArg;
3597330f729Sjoerg       break;
3607330f729Sjoerg     case 'O':
3617330f729Sjoerg       if (Target.getTriple().isOSDarwin())
3627330f729Sjoerg         k = ConversionSpecifier::OArg;
3637330f729Sjoerg       break;
3647330f729Sjoerg     case 'U':
3657330f729Sjoerg       if (Target.getTriple().isOSDarwin())
3667330f729Sjoerg         k = ConversionSpecifier::UArg;
3677330f729Sjoerg       break;
3687330f729Sjoerg     // MS specific.
3697330f729Sjoerg     case 'Z':
3707330f729Sjoerg       if (Target.getTriple().isOSMSVCRT())
3717330f729Sjoerg         k = ConversionSpecifier::ZArg;
3727330f729Sjoerg       break;
3737330f729Sjoerg   }
3747330f729Sjoerg 
3757330f729Sjoerg   // Check to see if we used the Objective-C modifier flags with
3767330f729Sjoerg   // a conversion specifier other than '@'.
3777330f729Sjoerg   if (k != ConversionSpecifier::ObjCObjArg &&
3787330f729Sjoerg       k != ConversionSpecifier::InvalidSpecifier &&
3797330f729Sjoerg       ObjCModifierFlagsStart) {
3807330f729Sjoerg     H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart,
3817330f729Sjoerg                                            ObjCModifierFlagsEnd + 1,
3827330f729Sjoerg                                            conversionPosition);
3837330f729Sjoerg     return true;
3847330f729Sjoerg   }
3857330f729Sjoerg 
3867330f729Sjoerg   PrintfConversionSpecifier CS(conversionPosition, k);
3877330f729Sjoerg   FS.setConversionSpecifier(CS);
3887330f729Sjoerg   if (CS.consumesDataArgument() && !FS.usesPositionalArg())
3897330f729Sjoerg     FS.setArgIndex(argIndex++);
3907330f729Sjoerg   // FreeBSD kernel specific.
3917330f729Sjoerg   if (k == ConversionSpecifier::FreeBSDbArg ||
3927330f729Sjoerg       k == ConversionSpecifier::FreeBSDDArg)
3937330f729Sjoerg     argIndex++;
3947330f729Sjoerg 
3957330f729Sjoerg   if (k == ConversionSpecifier::InvalidSpecifier) {
3967330f729Sjoerg     unsigned Len = I - Start;
3977330f729Sjoerg     if (ParseUTF8InvalidSpecifier(Start, E, Len)) {
3987330f729Sjoerg       CS.setEndScanList(Start + Len);
3997330f729Sjoerg       FS.setConversionSpecifier(CS);
4007330f729Sjoerg     }
4017330f729Sjoerg     // Assume the conversion takes one argument.
4027330f729Sjoerg     return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len);
4037330f729Sjoerg   }
4047330f729Sjoerg   return PrintfSpecifierResult(Start, FS);
4057330f729Sjoerg }
4067330f729Sjoerg 
ParsePrintfString(FormatStringHandler & H,const char * I,const char * E,const LangOptions & LO,const TargetInfo & Target,bool isFreeBSDKPrintf)4077330f729Sjoerg bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
4087330f729Sjoerg                                                      const char *I,
4097330f729Sjoerg                                                      const char *E,
4107330f729Sjoerg                                                      const LangOptions &LO,
4117330f729Sjoerg                                                      const TargetInfo &Target,
4127330f729Sjoerg                                                      bool isFreeBSDKPrintf) {
4137330f729Sjoerg 
4147330f729Sjoerg   unsigned argIndex = 0;
4157330f729Sjoerg 
4167330f729Sjoerg   // Keep looking for a format specifier until we have exhausted the string.
4177330f729Sjoerg   while (I != E) {
4187330f729Sjoerg     const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
4197330f729Sjoerg                                                             LO, Target, true,
4207330f729Sjoerg                                                             isFreeBSDKPrintf);
4217330f729Sjoerg     // Did a fail-stop error of any kind occur when parsing the specifier?
4227330f729Sjoerg     // If so, don't do any more processing.
4237330f729Sjoerg     if (FSR.shouldStop())
4247330f729Sjoerg       return true;
4257330f729Sjoerg     // Did we exhaust the string or encounter an error that
4267330f729Sjoerg     // we can recover from?
4277330f729Sjoerg     if (!FSR.hasValue())
4287330f729Sjoerg       continue;
4297330f729Sjoerg     // We have a format specifier.  Pass it to the callback.
4307330f729Sjoerg     if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
4317330f729Sjoerg                                  I - FSR.getStart()))
4327330f729Sjoerg       return true;
4337330f729Sjoerg   }
4347330f729Sjoerg   assert(I == E && "Format string not exhausted");
4357330f729Sjoerg   return false;
4367330f729Sjoerg }
4377330f729Sjoerg 
ParseFormatStringHasSArg(const char * I,const char * E,const LangOptions & LO,const TargetInfo & Target)4387330f729Sjoerg bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
4397330f729Sjoerg                                                             const char *E,
4407330f729Sjoerg                                                             const LangOptions &LO,
4417330f729Sjoerg                                                             const TargetInfo &Target) {
4427330f729Sjoerg 
4437330f729Sjoerg   unsigned argIndex = 0;
4447330f729Sjoerg 
4457330f729Sjoerg   // Keep looking for a %s format specifier until we have exhausted the string.
4467330f729Sjoerg   FormatStringHandler H;
4477330f729Sjoerg   while (I != E) {
4487330f729Sjoerg     const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
4497330f729Sjoerg                                                             LO, Target, false,
4507330f729Sjoerg                                                             false);
4517330f729Sjoerg     // Did a fail-stop error of any kind occur when parsing the specifier?
4527330f729Sjoerg     // If so, don't do any more processing.
4537330f729Sjoerg     if (FSR.shouldStop())
4547330f729Sjoerg       return false;
4557330f729Sjoerg     // Did we exhaust the string or encounter an error that
4567330f729Sjoerg     // we can recover from?
4577330f729Sjoerg     if (!FSR.hasValue())
4587330f729Sjoerg       continue;
4597330f729Sjoerg     const analyze_printf::PrintfSpecifier &FS = FSR.getValue();
4607330f729Sjoerg     // Return true if this a %s format specifier.
4617330f729Sjoerg     if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg)
4627330f729Sjoerg       return true;
4637330f729Sjoerg   }
4647330f729Sjoerg   return false;
4657330f729Sjoerg }
4667330f729Sjoerg 
parseFormatStringHasFormattingSpecifiers(const char * Begin,const char * End,const LangOptions & LO,const TargetInfo & Target)4677330f729Sjoerg bool clang::analyze_format_string::parseFormatStringHasFormattingSpecifiers(
4687330f729Sjoerg     const char *Begin, const char *End, const LangOptions &LO,
4697330f729Sjoerg     const TargetInfo &Target) {
4707330f729Sjoerg   unsigned ArgIndex = 0;
4717330f729Sjoerg   // Keep looking for a formatting specifier until we have exhausted the string.
4727330f729Sjoerg   FormatStringHandler H;
4737330f729Sjoerg   while (Begin != End) {
4747330f729Sjoerg     const PrintfSpecifierResult &FSR =
4757330f729Sjoerg         ParsePrintfSpecifier(H, Begin, End, ArgIndex, LO, Target, false, false);
4767330f729Sjoerg     if (FSR.shouldStop())
4777330f729Sjoerg       break;
4787330f729Sjoerg     if (FSR.hasValue())
4797330f729Sjoerg       return true;
4807330f729Sjoerg   }
4817330f729Sjoerg   return false;
4827330f729Sjoerg }
4837330f729Sjoerg 
4847330f729Sjoerg //===----------------------------------------------------------------------===//
4857330f729Sjoerg // Methods on PrintfSpecifier.
4867330f729Sjoerg //===----------------------------------------------------------------------===//
4877330f729Sjoerg 
getScalarArgType(ASTContext & Ctx,bool IsObjCLiteral) const4887330f729Sjoerg ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
4897330f729Sjoerg                                           bool IsObjCLiteral) const {
4907330f729Sjoerg   if (CS.getKind() == ConversionSpecifier::cArg)
4917330f729Sjoerg     switch (LM.getKind()) {
4927330f729Sjoerg       case LengthModifier::None:
4937330f729Sjoerg         return Ctx.IntTy;
4947330f729Sjoerg       case LengthModifier::AsLong:
4957330f729Sjoerg       case LengthModifier::AsWide:
4967330f729Sjoerg         return ArgType(ArgType::WIntTy, "wint_t");
4977330f729Sjoerg       case LengthModifier::AsShort:
4987330f729Sjoerg         if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
4997330f729Sjoerg           return Ctx.IntTy;
5007330f729Sjoerg         LLVM_FALLTHROUGH;
5017330f729Sjoerg       default:
5027330f729Sjoerg         return ArgType::Invalid();
5037330f729Sjoerg     }
5047330f729Sjoerg 
5057330f729Sjoerg   if (CS.isIntArg())
5067330f729Sjoerg     switch (LM.getKind()) {
5077330f729Sjoerg       case LengthModifier::AsLongDouble:
5087330f729Sjoerg         // GNU extension.
5097330f729Sjoerg         return Ctx.LongLongTy;
5107330f729Sjoerg       case LengthModifier::None:
5117330f729Sjoerg       case LengthModifier::AsShortLong:
5127330f729Sjoerg         return Ctx.IntTy;
5137330f729Sjoerg       case LengthModifier::AsInt32:
5147330f729Sjoerg         return ArgType(Ctx.IntTy, "__int32");
5157330f729Sjoerg       case LengthModifier::AsChar:
5167330f729Sjoerg         return ArgType::AnyCharTy;
5177330f729Sjoerg       case LengthModifier::AsShort: return Ctx.ShortTy;
5187330f729Sjoerg       case LengthModifier::AsLong: return Ctx.LongTy;
5197330f729Sjoerg       case LengthModifier::AsLongLong:
5207330f729Sjoerg       case LengthModifier::AsQuad:
5217330f729Sjoerg         return Ctx.LongLongTy;
5227330f729Sjoerg       case LengthModifier::AsInt64:
5237330f729Sjoerg         return ArgType(Ctx.LongLongTy, "__int64");
5247330f729Sjoerg       case LengthModifier::AsIntMax:
5257330f729Sjoerg         return ArgType(Ctx.getIntMaxType(), "intmax_t");
5267330f729Sjoerg       case LengthModifier::AsSizeT:
5277330f729Sjoerg         return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
5287330f729Sjoerg       case LengthModifier::AsInt3264:
5297330f729Sjoerg         return Ctx.getTargetInfo().getTriple().isArch64Bit()
5307330f729Sjoerg                    ? ArgType(Ctx.LongLongTy, "__int64")
5317330f729Sjoerg                    : ArgType(Ctx.IntTy, "__int32");
5327330f729Sjoerg       case LengthModifier::AsPtrDiff:
5337330f729Sjoerg         return ArgType::makePtrdiffT(
5347330f729Sjoerg             ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
5357330f729Sjoerg       case LengthModifier::AsAllocate:
5367330f729Sjoerg       case LengthModifier::AsMAllocate:
5377330f729Sjoerg       case LengthModifier::AsWide:
5387330f729Sjoerg         return ArgType::Invalid();
5397330f729Sjoerg     }
5407330f729Sjoerg 
5417330f729Sjoerg   if (CS.isUIntArg())
5427330f729Sjoerg     switch (LM.getKind()) {
5437330f729Sjoerg       case LengthModifier::AsLongDouble:
5447330f729Sjoerg         // GNU extension.
5457330f729Sjoerg         return Ctx.UnsignedLongLongTy;
5467330f729Sjoerg       case LengthModifier::None:
5477330f729Sjoerg       case LengthModifier::AsShortLong:
5487330f729Sjoerg         return Ctx.UnsignedIntTy;
5497330f729Sjoerg       case LengthModifier::AsInt32:
5507330f729Sjoerg         return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
5517330f729Sjoerg       case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
5527330f729Sjoerg       case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
5537330f729Sjoerg       case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
5547330f729Sjoerg       case LengthModifier::AsLongLong:
5557330f729Sjoerg       case LengthModifier::AsQuad:
5567330f729Sjoerg         return Ctx.UnsignedLongLongTy;
5577330f729Sjoerg       case LengthModifier::AsInt64:
5587330f729Sjoerg         return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
5597330f729Sjoerg       case LengthModifier::AsIntMax:
5607330f729Sjoerg         return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
5617330f729Sjoerg       case LengthModifier::AsSizeT:
5627330f729Sjoerg         return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));
5637330f729Sjoerg       case LengthModifier::AsInt3264:
5647330f729Sjoerg         return Ctx.getTargetInfo().getTriple().isArch64Bit()
5657330f729Sjoerg                    ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
5667330f729Sjoerg                    : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
5677330f729Sjoerg       case LengthModifier::AsPtrDiff:
5687330f729Sjoerg         return ArgType::makePtrdiffT(
5697330f729Sjoerg             ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
5707330f729Sjoerg       case LengthModifier::AsAllocate:
5717330f729Sjoerg       case LengthModifier::AsMAllocate:
5727330f729Sjoerg       case LengthModifier::AsWide:
5737330f729Sjoerg         return ArgType::Invalid();
5747330f729Sjoerg     }
5757330f729Sjoerg 
5767330f729Sjoerg   if (CS.isDoubleArg()) {
5777330f729Sjoerg     if (!VectorNumElts.isInvalid()) {
5787330f729Sjoerg       switch (LM.getKind()) {
5797330f729Sjoerg       case LengthModifier::AsShort:
5807330f729Sjoerg         return Ctx.HalfTy;
5817330f729Sjoerg       case LengthModifier::AsShortLong:
5827330f729Sjoerg         return Ctx.FloatTy;
5837330f729Sjoerg       case LengthModifier::AsLong:
5847330f729Sjoerg       default:
5857330f729Sjoerg         return Ctx.DoubleTy;
5867330f729Sjoerg       }
5877330f729Sjoerg     }
5887330f729Sjoerg 
5897330f729Sjoerg     if (LM.getKind() == LengthModifier::AsLongDouble)
5907330f729Sjoerg       return Ctx.LongDoubleTy;
5917330f729Sjoerg     return Ctx.DoubleTy;
5927330f729Sjoerg   }
5937330f729Sjoerg 
5947330f729Sjoerg   if (CS.getKind() == ConversionSpecifier::nArg) {
5957330f729Sjoerg     switch (LM.getKind()) {
5967330f729Sjoerg       case LengthModifier::None:
5977330f729Sjoerg         return ArgType::PtrTo(Ctx.IntTy);
5987330f729Sjoerg       case LengthModifier::AsChar:
5997330f729Sjoerg         return ArgType::PtrTo(Ctx.SignedCharTy);
6007330f729Sjoerg       case LengthModifier::AsShort:
6017330f729Sjoerg         return ArgType::PtrTo(Ctx.ShortTy);
6027330f729Sjoerg       case LengthModifier::AsLong:
6037330f729Sjoerg         return ArgType::PtrTo(Ctx.LongTy);
6047330f729Sjoerg       case LengthModifier::AsLongLong:
6057330f729Sjoerg       case LengthModifier::AsQuad:
6067330f729Sjoerg         return ArgType::PtrTo(Ctx.LongLongTy);
6077330f729Sjoerg       case LengthModifier::AsIntMax:
6087330f729Sjoerg         return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
6097330f729Sjoerg       case LengthModifier::AsSizeT:
6107330f729Sjoerg         return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
6117330f729Sjoerg       case LengthModifier::AsPtrDiff:
6127330f729Sjoerg         return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
6137330f729Sjoerg       case LengthModifier::AsLongDouble:
6147330f729Sjoerg         return ArgType(); // FIXME: Is this a known extension?
6157330f729Sjoerg       case LengthModifier::AsAllocate:
6167330f729Sjoerg       case LengthModifier::AsMAllocate:
6177330f729Sjoerg       case LengthModifier::AsInt32:
6187330f729Sjoerg       case LengthModifier::AsInt3264:
6197330f729Sjoerg       case LengthModifier::AsInt64:
6207330f729Sjoerg       case LengthModifier::AsWide:
6217330f729Sjoerg         return ArgType::Invalid();
6227330f729Sjoerg       case LengthModifier::AsShortLong:
6237330f729Sjoerg         llvm_unreachable("only used for OpenCL which doesn not handle nArg");
6247330f729Sjoerg     }
6257330f729Sjoerg   }
6267330f729Sjoerg 
6277330f729Sjoerg   switch (CS.getKind()) {
6287330f729Sjoerg     case ConversionSpecifier::sArg:
6297330f729Sjoerg       if (LM.getKind() == LengthModifier::AsWideChar) {
6307330f729Sjoerg         if (IsObjCLiteral)
6317330f729Sjoerg           return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
6327330f729Sjoerg                          "const unichar *");
6337330f729Sjoerg         return ArgType(ArgType::WCStrTy, "wchar_t *");
6347330f729Sjoerg       }
6357330f729Sjoerg       if (LM.getKind() == LengthModifier::AsWide)
6367330f729Sjoerg         return ArgType(ArgType::WCStrTy, "wchar_t *");
6377330f729Sjoerg       return ArgType::CStrTy;
6387330f729Sjoerg     case ConversionSpecifier::SArg:
6397330f729Sjoerg       if (IsObjCLiteral)
6407330f729Sjoerg         return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
6417330f729Sjoerg                        "const unichar *");
6427330f729Sjoerg       if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
6437330f729Sjoerg           LM.getKind() == LengthModifier::AsShort)
6447330f729Sjoerg         return ArgType::CStrTy;
6457330f729Sjoerg       return ArgType(ArgType::WCStrTy, "wchar_t *");
6467330f729Sjoerg     case ConversionSpecifier::CArg:
6477330f729Sjoerg       if (IsObjCLiteral)
6487330f729Sjoerg         return ArgType(Ctx.UnsignedShortTy, "unichar");
6497330f729Sjoerg       if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
6507330f729Sjoerg           LM.getKind() == LengthModifier::AsShort)
6517330f729Sjoerg         return Ctx.IntTy;
6527330f729Sjoerg       return ArgType(Ctx.WideCharTy, "wchar_t");
6537330f729Sjoerg     case ConversionSpecifier::pArg:
6547330f729Sjoerg     case ConversionSpecifier::PArg:
6557330f729Sjoerg       return ArgType::CPointerTy;
6567330f729Sjoerg     case ConversionSpecifier::ObjCObjArg:
6577330f729Sjoerg       return ArgType::ObjCPointerTy;
6587330f729Sjoerg     default:
6597330f729Sjoerg       break;
6607330f729Sjoerg   }
6617330f729Sjoerg 
6627330f729Sjoerg   // FIXME: Handle other cases.
6637330f729Sjoerg   return ArgType();
6647330f729Sjoerg }
6657330f729Sjoerg 
6667330f729Sjoerg 
getArgType(ASTContext & Ctx,bool IsObjCLiteral) const6677330f729Sjoerg ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
6687330f729Sjoerg                                     bool IsObjCLiteral) const {
6697330f729Sjoerg   const PrintfConversionSpecifier &CS = getConversionSpecifier();
6707330f729Sjoerg 
6717330f729Sjoerg   if (!CS.consumesDataArgument())
6727330f729Sjoerg     return ArgType::Invalid();
6737330f729Sjoerg 
6747330f729Sjoerg   ArgType ScalarTy = getScalarArgType(Ctx, IsObjCLiteral);
6757330f729Sjoerg   if (!ScalarTy.isValid() || VectorNumElts.isInvalid())
6767330f729Sjoerg     return ScalarTy;
6777330f729Sjoerg 
6787330f729Sjoerg   return ScalarTy.makeVectorType(Ctx, VectorNumElts.getConstantAmount());
6797330f729Sjoerg }
6807330f729Sjoerg 
fixType(QualType QT,const LangOptions & LangOpt,ASTContext & Ctx,bool IsObjCLiteral)6817330f729Sjoerg bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
6827330f729Sjoerg                               ASTContext &Ctx, bool IsObjCLiteral) {
6837330f729Sjoerg   // %n is different from other conversion specifiers; don't try to fix it.
6847330f729Sjoerg   if (CS.getKind() == ConversionSpecifier::nArg)
6857330f729Sjoerg     return false;
6867330f729Sjoerg 
6877330f729Sjoerg   // Handle Objective-C objects first. Note that while the '%@' specifier will
6887330f729Sjoerg   // not warn for structure pointer or void pointer arguments (because that's
6897330f729Sjoerg   // how CoreFoundation objects are implemented), we only show a fixit for '%@'
6907330f729Sjoerg   // if we know it's an object (block, id, class, or __attribute__((NSObject))).
6917330f729Sjoerg   if (QT->isObjCRetainableType()) {
6927330f729Sjoerg     if (!IsObjCLiteral)
6937330f729Sjoerg       return false;
6947330f729Sjoerg 
6957330f729Sjoerg     CS.setKind(ConversionSpecifier::ObjCObjArg);
6967330f729Sjoerg 
6977330f729Sjoerg     // Disable irrelevant flags
6987330f729Sjoerg     HasThousandsGrouping = false;
6997330f729Sjoerg     HasPlusPrefix = false;
7007330f729Sjoerg     HasSpacePrefix = false;
7017330f729Sjoerg     HasAlternativeForm = false;
7027330f729Sjoerg     HasLeadingZeroes = false;
7037330f729Sjoerg     Precision.setHowSpecified(OptionalAmount::NotSpecified);
7047330f729Sjoerg     LM.setKind(LengthModifier::None);
7057330f729Sjoerg 
7067330f729Sjoerg     return true;
7077330f729Sjoerg   }
7087330f729Sjoerg 
7097330f729Sjoerg   // Handle strings next (char *, wchar_t *)
7107330f729Sjoerg   if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
7117330f729Sjoerg     CS.setKind(ConversionSpecifier::sArg);
7127330f729Sjoerg 
7137330f729Sjoerg     // Disable irrelevant flags
7147330f729Sjoerg     HasAlternativeForm = 0;
7157330f729Sjoerg     HasLeadingZeroes = 0;
7167330f729Sjoerg 
7177330f729Sjoerg     // Set the long length modifier for wide characters
7187330f729Sjoerg     if (QT->getPointeeType()->isWideCharType())
7197330f729Sjoerg       LM.setKind(LengthModifier::AsWideChar);
7207330f729Sjoerg     else
7217330f729Sjoerg       LM.setKind(LengthModifier::None);
7227330f729Sjoerg 
7237330f729Sjoerg     return true;
7247330f729Sjoerg   }
7257330f729Sjoerg 
7267330f729Sjoerg   // If it's an enum, get its underlying type.
7277330f729Sjoerg   if (const EnumType *ETy = QT->getAs<EnumType>())
7287330f729Sjoerg     QT = ETy->getDecl()->getIntegerType();
7297330f729Sjoerg 
7307330f729Sjoerg   const BuiltinType *BT = QT->getAs<BuiltinType>();
7317330f729Sjoerg   if (!BT) {
7327330f729Sjoerg     const VectorType *VT = QT->getAs<VectorType>();
7337330f729Sjoerg     if (VT) {
7347330f729Sjoerg       QT = VT->getElementType();
7357330f729Sjoerg       BT = QT->getAs<BuiltinType>();
7367330f729Sjoerg       VectorNumElts = OptionalAmount(VT->getNumElements());
7377330f729Sjoerg     }
7387330f729Sjoerg   }
7397330f729Sjoerg 
7407330f729Sjoerg   // We can only work with builtin types.
7417330f729Sjoerg   if (!BT)
7427330f729Sjoerg     return false;
7437330f729Sjoerg 
7447330f729Sjoerg   // Set length modifier
7457330f729Sjoerg   switch (BT->getKind()) {
7467330f729Sjoerg   case BuiltinType::Bool:
7477330f729Sjoerg   case BuiltinType::WChar_U:
7487330f729Sjoerg   case BuiltinType::WChar_S:
7497330f729Sjoerg   case BuiltinType::Char8: // FIXME: Treat like 'char'?
7507330f729Sjoerg   case BuiltinType::Char16:
7517330f729Sjoerg   case BuiltinType::Char32:
7527330f729Sjoerg   case BuiltinType::UInt128:
7537330f729Sjoerg   case BuiltinType::Int128:
7547330f729Sjoerg   case BuiltinType::Half:
755*e038c9c4Sjoerg   case BuiltinType::BFloat16:
7567330f729Sjoerg   case BuiltinType::Float16:
7577330f729Sjoerg   case BuiltinType::Float128:
7587330f729Sjoerg   case BuiltinType::ShortAccum:
7597330f729Sjoerg   case BuiltinType::Accum:
7607330f729Sjoerg   case BuiltinType::LongAccum:
7617330f729Sjoerg   case BuiltinType::UShortAccum:
7627330f729Sjoerg   case BuiltinType::UAccum:
7637330f729Sjoerg   case BuiltinType::ULongAccum:
7647330f729Sjoerg   case BuiltinType::ShortFract:
7657330f729Sjoerg   case BuiltinType::Fract:
7667330f729Sjoerg   case BuiltinType::LongFract:
7677330f729Sjoerg   case BuiltinType::UShortFract:
7687330f729Sjoerg   case BuiltinType::UFract:
7697330f729Sjoerg   case BuiltinType::ULongFract:
7707330f729Sjoerg   case BuiltinType::SatShortAccum:
7717330f729Sjoerg   case BuiltinType::SatAccum:
7727330f729Sjoerg   case BuiltinType::SatLongAccum:
7737330f729Sjoerg   case BuiltinType::SatUShortAccum:
7747330f729Sjoerg   case BuiltinType::SatUAccum:
7757330f729Sjoerg   case BuiltinType::SatULongAccum:
7767330f729Sjoerg   case BuiltinType::SatShortFract:
7777330f729Sjoerg   case BuiltinType::SatFract:
7787330f729Sjoerg   case BuiltinType::SatLongFract:
7797330f729Sjoerg   case BuiltinType::SatUShortFract:
7807330f729Sjoerg   case BuiltinType::SatUFract:
7817330f729Sjoerg   case BuiltinType::SatULongFract:
7827330f729Sjoerg     // Various types which are non-trivial to correct.
7837330f729Sjoerg     return false;
7847330f729Sjoerg 
7857330f729Sjoerg #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
7867330f729Sjoerg   case BuiltinType::Id:
7877330f729Sjoerg #include "clang/Basic/OpenCLImageTypes.def"
7887330f729Sjoerg #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
7897330f729Sjoerg   case BuiltinType::Id:
7907330f729Sjoerg #include "clang/Basic/OpenCLExtensionTypes.def"
7917330f729Sjoerg #define SVE_TYPE(Name, Id, SingletonId) \
7927330f729Sjoerg   case BuiltinType::Id:
7937330f729Sjoerg #include "clang/Basic/AArch64SVEACLETypes.def"
794*e038c9c4Sjoerg #define PPC_VECTOR_TYPE(Name, Id, Size) \
795*e038c9c4Sjoerg   case BuiltinType::Id:
796*e038c9c4Sjoerg #include "clang/Basic/PPCTypes.def"
797*e038c9c4Sjoerg #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
798*e038c9c4Sjoerg #include "clang/Basic/RISCVVTypes.def"
7997330f729Sjoerg #define SIGNED_TYPE(Id, SingletonId)
8007330f729Sjoerg #define UNSIGNED_TYPE(Id, SingletonId)
8017330f729Sjoerg #define FLOATING_TYPE(Id, SingletonId)
8027330f729Sjoerg #define BUILTIN_TYPE(Id, SingletonId) \
8037330f729Sjoerg   case BuiltinType::Id:
8047330f729Sjoerg #include "clang/AST/BuiltinTypes.def"
8057330f729Sjoerg     // Misc other stuff which doesn't make sense here.
8067330f729Sjoerg     return false;
8077330f729Sjoerg 
8087330f729Sjoerg   case BuiltinType::UInt:
8097330f729Sjoerg   case BuiltinType::Int:
8107330f729Sjoerg   case BuiltinType::Float:
8117330f729Sjoerg     LM.setKind(VectorNumElts.isInvalid() ?
8127330f729Sjoerg                LengthModifier::None : LengthModifier::AsShortLong);
8137330f729Sjoerg     break;
8147330f729Sjoerg   case BuiltinType::Double:
8157330f729Sjoerg     LM.setKind(VectorNumElts.isInvalid() ?
8167330f729Sjoerg                LengthModifier::None : LengthModifier::AsLong);
8177330f729Sjoerg     break;
8187330f729Sjoerg   case BuiltinType::Char_U:
8197330f729Sjoerg   case BuiltinType::UChar:
8207330f729Sjoerg   case BuiltinType::Char_S:
8217330f729Sjoerg   case BuiltinType::SChar:
8227330f729Sjoerg     LM.setKind(LengthModifier::AsChar);
8237330f729Sjoerg     break;
8247330f729Sjoerg 
8257330f729Sjoerg   case BuiltinType::Short:
8267330f729Sjoerg   case BuiltinType::UShort:
8277330f729Sjoerg     LM.setKind(LengthModifier::AsShort);
8287330f729Sjoerg     break;
8297330f729Sjoerg 
8307330f729Sjoerg   case BuiltinType::Long:
8317330f729Sjoerg   case BuiltinType::ULong:
8327330f729Sjoerg     LM.setKind(LengthModifier::AsLong);
8337330f729Sjoerg     break;
8347330f729Sjoerg 
8357330f729Sjoerg   case BuiltinType::LongLong:
8367330f729Sjoerg   case BuiltinType::ULongLong:
8377330f729Sjoerg     LM.setKind(LengthModifier::AsLongLong);
8387330f729Sjoerg     break;
8397330f729Sjoerg 
8407330f729Sjoerg   case BuiltinType::LongDouble:
8417330f729Sjoerg     LM.setKind(LengthModifier::AsLongDouble);
8427330f729Sjoerg     break;
8437330f729Sjoerg   }
8447330f729Sjoerg 
8457330f729Sjoerg   // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
8467330f729Sjoerg   if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
8477330f729Sjoerg     namedTypeToLengthModifier(QT, LM);
8487330f729Sjoerg 
8497330f729Sjoerg   // If fixing the length modifier was enough, we might be done.
8507330f729Sjoerg   if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
8517330f729Sjoerg     // If we're going to offer a fix anyway, make sure the sign matches.
8527330f729Sjoerg     switch (CS.getKind()) {
8537330f729Sjoerg     case ConversionSpecifier::uArg:
8547330f729Sjoerg     case ConversionSpecifier::UArg:
8557330f729Sjoerg       if (QT->isSignedIntegerType())
8567330f729Sjoerg         CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
8577330f729Sjoerg       break;
8587330f729Sjoerg     case ConversionSpecifier::dArg:
8597330f729Sjoerg     case ConversionSpecifier::DArg:
8607330f729Sjoerg     case ConversionSpecifier::iArg:
8617330f729Sjoerg       if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
8627330f729Sjoerg         CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
8637330f729Sjoerg       break;
8647330f729Sjoerg     default:
8657330f729Sjoerg       // Other specifiers do not have signed/unsigned variants.
8667330f729Sjoerg       break;
8677330f729Sjoerg     }
8687330f729Sjoerg 
8697330f729Sjoerg     const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
8707330f729Sjoerg     if (ATR.isValid() && ATR.matchesType(Ctx, QT))
8717330f729Sjoerg       return true;
8727330f729Sjoerg   }
8737330f729Sjoerg 
8747330f729Sjoerg   // Set conversion specifier and disable any flags which do not apply to it.
8757330f729Sjoerg   // Let typedefs to char fall through to int, as %c is silly for uint8_t.
8767330f729Sjoerg   if (!isa<TypedefType>(QT) && QT->isCharType()) {
8777330f729Sjoerg     CS.setKind(ConversionSpecifier::cArg);
8787330f729Sjoerg     LM.setKind(LengthModifier::None);
8797330f729Sjoerg     Precision.setHowSpecified(OptionalAmount::NotSpecified);
8807330f729Sjoerg     HasAlternativeForm = 0;
8817330f729Sjoerg     HasLeadingZeroes = 0;
8827330f729Sjoerg     HasPlusPrefix = 0;
8837330f729Sjoerg   }
8847330f729Sjoerg   // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
8857330f729Sjoerg   else if (QT->isRealFloatingType()) {
8867330f729Sjoerg     CS.setKind(ConversionSpecifier::fArg);
8877330f729Sjoerg   }
8887330f729Sjoerg   else if (QT->isSignedIntegerType()) {
8897330f729Sjoerg     CS.setKind(ConversionSpecifier::dArg);
8907330f729Sjoerg     HasAlternativeForm = 0;
8917330f729Sjoerg   }
8927330f729Sjoerg   else if (QT->isUnsignedIntegerType()) {
8937330f729Sjoerg     CS.setKind(ConversionSpecifier::uArg);
8947330f729Sjoerg     HasAlternativeForm = 0;
8957330f729Sjoerg     HasPlusPrefix = 0;
8967330f729Sjoerg   } else {
8977330f729Sjoerg     llvm_unreachable("Unexpected type");
8987330f729Sjoerg   }
8997330f729Sjoerg 
9007330f729Sjoerg   return true;
9017330f729Sjoerg }
9027330f729Sjoerg 
toString(raw_ostream & os) const9037330f729Sjoerg void PrintfSpecifier::toString(raw_ostream &os) const {
9047330f729Sjoerg   // Whilst some features have no defined order, we are using the order
9057330f729Sjoerg   // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
9067330f729Sjoerg   os << "%";
9077330f729Sjoerg 
9087330f729Sjoerg   // Positional args
9097330f729Sjoerg   if (usesPositionalArg()) {
9107330f729Sjoerg     os << getPositionalArgIndex() << "$";
9117330f729Sjoerg   }
9127330f729Sjoerg 
9137330f729Sjoerg   // Conversion flags
9147330f729Sjoerg   if (IsLeftJustified)    os << "-";
9157330f729Sjoerg   if (HasPlusPrefix)      os << "+";
9167330f729Sjoerg   if (HasSpacePrefix)     os << " ";
9177330f729Sjoerg   if (HasAlternativeForm) os << "#";
9187330f729Sjoerg   if (HasLeadingZeroes)   os << "0";
9197330f729Sjoerg 
9207330f729Sjoerg   // Minimum field width
9217330f729Sjoerg   FieldWidth.toString(os);
9227330f729Sjoerg   // Precision
9237330f729Sjoerg   Precision.toString(os);
9247330f729Sjoerg 
9257330f729Sjoerg   // Vector modifier
9267330f729Sjoerg   if (!VectorNumElts.isInvalid())
9277330f729Sjoerg     os << 'v' << VectorNumElts.getConstantAmount();
9287330f729Sjoerg 
9297330f729Sjoerg   // Length modifier
9307330f729Sjoerg   os << LM.toString();
9317330f729Sjoerg   // Conversion specifier
9327330f729Sjoerg   os << CS.toString();
9337330f729Sjoerg }
9347330f729Sjoerg 
hasValidPlusPrefix() const9357330f729Sjoerg bool PrintfSpecifier::hasValidPlusPrefix() const {
9367330f729Sjoerg   if (!HasPlusPrefix)
9377330f729Sjoerg     return true;
9387330f729Sjoerg 
9397330f729Sjoerg   // The plus prefix only makes sense for signed conversions
9407330f729Sjoerg   switch (CS.getKind()) {
9417330f729Sjoerg   case ConversionSpecifier::dArg:
9427330f729Sjoerg   case ConversionSpecifier::DArg:
9437330f729Sjoerg   case ConversionSpecifier::iArg:
9447330f729Sjoerg   case ConversionSpecifier::fArg:
9457330f729Sjoerg   case ConversionSpecifier::FArg:
9467330f729Sjoerg   case ConversionSpecifier::eArg:
9477330f729Sjoerg   case ConversionSpecifier::EArg:
9487330f729Sjoerg   case ConversionSpecifier::gArg:
9497330f729Sjoerg   case ConversionSpecifier::GArg:
9507330f729Sjoerg   case ConversionSpecifier::aArg:
9517330f729Sjoerg   case ConversionSpecifier::AArg:
9527330f729Sjoerg   case ConversionSpecifier::FreeBSDrArg:
9537330f729Sjoerg   case ConversionSpecifier::FreeBSDyArg:
9547330f729Sjoerg     return true;
9557330f729Sjoerg 
9567330f729Sjoerg   default:
9577330f729Sjoerg     return false;
9587330f729Sjoerg   }
9597330f729Sjoerg }
9607330f729Sjoerg 
hasValidAlternativeForm() const9617330f729Sjoerg bool PrintfSpecifier::hasValidAlternativeForm() const {
9627330f729Sjoerg   if (!HasAlternativeForm)
9637330f729Sjoerg     return true;
9647330f729Sjoerg 
9657330f729Sjoerg   // Alternate form flag only valid with the oxXaAeEfFgG conversions
9667330f729Sjoerg   switch (CS.getKind()) {
9677330f729Sjoerg   case ConversionSpecifier::oArg:
9687330f729Sjoerg   case ConversionSpecifier::OArg:
9697330f729Sjoerg   case ConversionSpecifier::xArg:
9707330f729Sjoerg   case ConversionSpecifier::XArg:
9717330f729Sjoerg   case ConversionSpecifier::aArg:
9727330f729Sjoerg   case ConversionSpecifier::AArg:
9737330f729Sjoerg   case ConversionSpecifier::eArg:
9747330f729Sjoerg   case ConversionSpecifier::EArg:
9757330f729Sjoerg   case ConversionSpecifier::fArg:
9767330f729Sjoerg   case ConversionSpecifier::FArg:
9777330f729Sjoerg   case ConversionSpecifier::gArg:
9787330f729Sjoerg   case ConversionSpecifier::GArg:
9797330f729Sjoerg   case ConversionSpecifier::FreeBSDrArg:
9807330f729Sjoerg   case ConversionSpecifier::FreeBSDyArg:
9817330f729Sjoerg     return true;
9827330f729Sjoerg 
9837330f729Sjoerg   default:
9847330f729Sjoerg     return false;
9857330f729Sjoerg   }
9867330f729Sjoerg }
9877330f729Sjoerg 
hasValidLeadingZeros() const9887330f729Sjoerg bool PrintfSpecifier::hasValidLeadingZeros() const {
9897330f729Sjoerg   if (!HasLeadingZeroes)
9907330f729Sjoerg     return true;
9917330f729Sjoerg 
9927330f729Sjoerg   // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
9937330f729Sjoerg   switch (CS.getKind()) {
9947330f729Sjoerg   case ConversionSpecifier::dArg:
9957330f729Sjoerg   case ConversionSpecifier::DArg:
9967330f729Sjoerg   case ConversionSpecifier::iArg:
9977330f729Sjoerg   case ConversionSpecifier::oArg:
9987330f729Sjoerg   case ConversionSpecifier::OArg:
9997330f729Sjoerg   case ConversionSpecifier::uArg:
10007330f729Sjoerg   case ConversionSpecifier::UArg:
10017330f729Sjoerg   case ConversionSpecifier::xArg:
10027330f729Sjoerg   case ConversionSpecifier::XArg:
10037330f729Sjoerg   case ConversionSpecifier::aArg:
10047330f729Sjoerg   case ConversionSpecifier::AArg:
10057330f729Sjoerg   case ConversionSpecifier::eArg:
10067330f729Sjoerg   case ConversionSpecifier::EArg:
10077330f729Sjoerg   case ConversionSpecifier::fArg:
10087330f729Sjoerg   case ConversionSpecifier::FArg:
10097330f729Sjoerg   case ConversionSpecifier::gArg:
10107330f729Sjoerg   case ConversionSpecifier::GArg:
10117330f729Sjoerg   case ConversionSpecifier::FreeBSDrArg:
10127330f729Sjoerg   case ConversionSpecifier::FreeBSDyArg:
10137330f729Sjoerg     return true;
10147330f729Sjoerg 
10157330f729Sjoerg   default:
10167330f729Sjoerg     return false;
10177330f729Sjoerg   }
10187330f729Sjoerg }
10197330f729Sjoerg 
hasValidSpacePrefix() const10207330f729Sjoerg bool PrintfSpecifier::hasValidSpacePrefix() const {
10217330f729Sjoerg   if (!HasSpacePrefix)
10227330f729Sjoerg     return true;
10237330f729Sjoerg 
10247330f729Sjoerg   // The space prefix only makes sense for signed conversions
10257330f729Sjoerg   switch (CS.getKind()) {
10267330f729Sjoerg   case ConversionSpecifier::dArg:
10277330f729Sjoerg   case ConversionSpecifier::DArg:
10287330f729Sjoerg   case ConversionSpecifier::iArg:
10297330f729Sjoerg   case ConversionSpecifier::fArg:
10307330f729Sjoerg   case ConversionSpecifier::FArg:
10317330f729Sjoerg   case ConversionSpecifier::eArg:
10327330f729Sjoerg   case ConversionSpecifier::EArg:
10337330f729Sjoerg   case ConversionSpecifier::gArg:
10347330f729Sjoerg   case ConversionSpecifier::GArg:
10357330f729Sjoerg   case ConversionSpecifier::aArg:
10367330f729Sjoerg   case ConversionSpecifier::AArg:
10377330f729Sjoerg   case ConversionSpecifier::FreeBSDrArg:
10387330f729Sjoerg   case ConversionSpecifier::FreeBSDyArg:
10397330f729Sjoerg     return true;
10407330f729Sjoerg 
10417330f729Sjoerg   default:
10427330f729Sjoerg     return false;
10437330f729Sjoerg   }
10447330f729Sjoerg }
10457330f729Sjoerg 
hasValidLeftJustified() const10467330f729Sjoerg bool PrintfSpecifier::hasValidLeftJustified() const {
10477330f729Sjoerg   if (!IsLeftJustified)
10487330f729Sjoerg     return true;
10497330f729Sjoerg 
10507330f729Sjoerg   // The left justified flag is valid for all conversions except n
10517330f729Sjoerg   switch (CS.getKind()) {
10527330f729Sjoerg   case ConversionSpecifier::nArg:
10537330f729Sjoerg     return false;
10547330f729Sjoerg 
10557330f729Sjoerg   default:
10567330f729Sjoerg     return true;
10577330f729Sjoerg   }
10587330f729Sjoerg }
10597330f729Sjoerg 
hasValidThousandsGroupingPrefix() const10607330f729Sjoerg bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
10617330f729Sjoerg   if (!HasThousandsGrouping)
10627330f729Sjoerg     return true;
10637330f729Sjoerg 
10647330f729Sjoerg   switch (CS.getKind()) {
10657330f729Sjoerg     case ConversionSpecifier::dArg:
10667330f729Sjoerg     case ConversionSpecifier::DArg:
10677330f729Sjoerg     case ConversionSpecifier::iArg:
10687330f729Sjoerg     case ConversionSpecifier::uArg:
10697330f729Sjoerg     case ConversionSpecifier::UArg:
10707330f729Sjoerg     case ConversionSpecifier::fArg:
10717330f729Sjoerg     case ConversionSpecifier::FArg:
10727330f729Sjoerg     case ConversionSpecifier::gArg:
10737330f729Sjoerg     case ConversionSpecifier::GArg:
10747330f729Sjoerg       return true;
10757330f729Sjoerg     default:
10767330f729Sjoerg       return false;
10777330f729Sjoerg   }
10787330f729Sjoerg }
10797330f729Sjoerg 
hasValidPrecision() const10807330f729Sjoerg bool PrintfSpecifier::hasValidPrecision() const {
10817330f729Sjoerg   if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
10827330f729Sjoerg     return true;
10837330f729Sjoerg 
10847330f729Sjoerg   // Precision is only valid with the diouxXaAeEfFgGsP conversions
10857330f729Sjoerg   switch (CS.getKind()) {
10867330f729Sjoerg   case ConversionSpecifier::dArg:
10877330f729Sjoerg   case ConversionSpecifier::DArg:
10887330f729Sjoerg   case ConversionSpecifier::iArg:
10897330f729Sjoerg   case ConversionSpecifier::oArg:
10907330f729Sjoerg   case ConversionSpecifier::OArg:
10917330f729Sjoerg   case ConversionSpecifier::uArg:
10927330f729Sjoerg   case ConversionSpecifier::UArg:
10937330f729Sjoerg   case ConversionSpecifier::xArg:
10947330f729Sjoerg   case ConversionSpecifier::XArg:
10957330f729Sjoerg   case ConversionSpecifier::aArg:
10967330f729Sjoerg   case ConversionSpecifier::AArg:
10977330f729Sjoerg   case ConversionSpecifier::eArg:
10987330f729Sjoerg   case ConversionSpecifier::EArg:
10997330f729Sjoerg   case ConversionSpecifier::fArg:
11007330f729Sjoerg   case ConversionSpecifier::FArg:
11017330f729Sjoerg   case ConversionSpecifier::gArg:
11027330f729Sjoerg   case ConversionSpecifier::GArg:
11037330f729Sjoerg   case ConversionSpecifier::sArg:
11047330f729Sjoerg   case ConversionSpecifier::FreeBSDrArg:
11057330f729Sjoerg   case ConversionSpecifier::FreeBSDyArg:
11067330f729Sjoerg   case ConversionSpecifier::PArg:
11077330f729Sjoerg     return true;
11087330f729Sjoerg 
11097330f729Sjoerg   default:
11107330f729Sjoerg     return false;
11117330f729Sjoerg   }
11127330f729Sjoerg }
hasValidFieldWidth() const11137330f729Sjoerg bool PrintfSpecifier::hasValidFieldWidth() const {
11147330f729Sjoerg   if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
11157330f729Sjoerg       return true;
11167330f729Sjoerg 
11177330f729Sjoerg   // The field width is valid for all conversions except n
11187330f729Sjoerg   switch (CS.getKind()) {
11197330f729Sjoerg   case ConversionSpecifier::nArg:
11207330f729Sjoerg     return false;
11217330f729Sjoerg 
11227330f729Sjoerg   default:
11237330f729Sjoerg     return true;
11247330f729Sjoerg   }
11257330f729Sjoerg }
1126