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