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