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. 1430b57cec5SDimitry Andric if (MatchedStr.startswith("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); 1490b57cec5SDimitry Andric } else if (MatchedStr.equals("sensitive")) 1500b57cec5SDimitry Andric PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsSensitive; 1510b57cec5SDimitry Andric else if (PrivacyFlags != 1520b57cec5SDimitry Andric clang::analyze_os_log::OSLogBufferItem::IsSensitive && 1530b57cec5SDimitry Andric MatchedStr.equals("private")) 1540b57cec5SDimitry Andric PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate; 1550b57cec5SDimitry Andric else if (PrivacyFlags == 0 && MatchedStr.equals("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; 3290b57cec5SDimitry Andric // POSIX specific. 3300b57cec5SDimitry Andric case 'C': k = ConversionSpecifier::CArg; break; 3310b57cec5SDimitry Andric case 'S': k = ConversionSpecifier::SArg; break; 3320b57cec5SDimitry Andric // Apple extension for os_log 3330b57cec5SDimitry Andric case 'P': 3340b57cec5SDimitry Andric k = ConversionSpecifier::PArg; 3350b57cec5SDimitry Andric break; 3360b57cec5SDimitry Andric // Objective-C. 3370b57cec5SDimitry Andric case '@': k = ConversionSpecifier::ObjCObjArg; break; 3380b57cec5SDimitry Andric // Glibc specific. 3390b57cec5SDimitry Andric case 'm': k = ConversionSpecifier::PrintErrno; break; 3400b57cec5SDimitry Andric // FreeBSD kernel specific. 3410b57cec5SDimitry Andric case 'b': 3420b57cec5SDimitry Andric if (isFreeBSDKPrintf) 3430b57cec5SDimitry Andric k = ConversionSpecifier::FreeBSDbArg; // int followed by char * 3440b57cec5SDimitry Andric break; 3450b57cec5SDimitry Andric case 'r': 3460b57cec5SDimitry Andric if (isFreeBSDKPrintf) 3470b57cec5SDimitry Andric k = ConversionSpecifier::FreeBSDrArg; // int 3480b57cec5SDimitry Andric break; 3490b57cec5SDimitry Andric case 'y': 3500b57cec5SDimitry Andric if (isFreeBSDKPrintf) 3510b57cec5SDimitry Andric k = ConversionSpecifier::FreeBSDyArg; // int 3520b57cec5SDimitry Andric break; 3530b57cec5SDimitry Andric // Apple-specific. 3540b57cec5SDimitry Andric case 'D': 3550b57cec5SDimitry Andric if (isFreeBSDKPrintf) 3560b57cec5SDimitry Andric k = ConversionSpecifier::FreeBSDDArg; // void * followed by char * 3570b57cec5SDimitry Andric else if (Target.getTriple().isOSDarwin()) 3580b57cec5SDimitry Andric k = ConversionSpecifier::DArg; 3590b57cec5SDimitry Andric break; 3600b57cec5SDimitry Andric case 'O': 3610b57cec5SDimitry Andric if (Target.getTriple().isOSDarwin()) 3620b57cec5SDimitry Andric k = ConversionSpecifier::OArg; 3630b57cec5SDimitry Andric break; 3640b57cec5SDimitry Andric case 'U': 3650b57cec5SDimitry Andric if (Target.getTriple().isOSDarwin()) 3660b57cec5SDimitry Andric k = ConversionSpecifier::UArg; 3670b57cec5SDimitry Andric break; 3680b57cec5SDimitry Andric // MS specific. 3690b57cec5SDimitry Andric case 'Z': 3700b57cec5SDimitry Andric if (Target.getTriple().isOSMSVCRT()) 3710b57cec5SDimitry Andric k = ConversionSpecifier::ZArg; 3720b57cec5SDimitry Andric break; 3730b57cec5SDimitry Andric } 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric // Check to see if we used the Objective-C modifier flags with 3760b57cec5SDimitry Andric // a conversion specifier other than '@'. 3770b57cec5SDimitry Andric if (k != ConversionSpecifier::ObjCObjArg && 3780b57cec5SDimitry Andric k != ConversionSpecifier::InvalidSpecifier && 3790b57cec5SDimitry Andric ObjCModifierFlagsStart) { 3800b57cec5SDimitry Andric H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart, 3810b57cec5SDimitry Andric ObjCModifierFlagsEnd + 1, 3820b57cec5SDimitry Andric conversionPosition); 3830b57cec5SDimitry Andric return true; 3840b57cec5SDimitry Andric } 3850b57cec5SDimitry Andric 3860b57cec5SDimitry Andric PrintfConversionSpecifier CS(conversionPosition, k); 3870b57cec5SDimitry Andric FS.setConversionSpecifier(CS); 3880b57cec5SDimitry Andric if (CS.consumesDataArgument() && !FS.usesPositionalArg()) 3890b57cec5SDimitry Andric FS.setArgIndex(argIndex++); 3900b57cec5SDimitry Andric // FreeBSD kernel specific. 3910b57cec5SDimitry Andric if (k == ConversionSpecifier::FreeBSDbArg || 3920b57cec5SDimitry Andric k == ConversionSpecifier::FreeBSDDArg) 3930b57cec5SDimitry Andric argIndex++; 3940b57cec5SDimitry Andric 3950b57cec5SDimitry Andric if (k == ConversionSpecifier::InvalidSpecifier) { 3960b57cec5SDimitry Andric unsigned Len = I - Start; 3970b57cec5SDimitry Andric if (ParseUTF8InvalidSpecifier(Start, E, Len)) { 3980b57cec5SDimitry Andric CS.setEndScanList(Start + Len); 3990b57cec5SDimitry Andric FS.setConversionSpecifier(CS); 4000b57cec5SDimitry Andric } 4010b57cec5SDimitry Andric // Assume the conversion takes one argument. 4020b57cec5SDimitry Andric return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len); 4030b57cec5SDimitry Andric } 4040b57cec5SDimitry Andric return PrintfSpecifierResult(Start, FS); 4050b57cec5SDimitry Andric } 4060b57cec5SDimitry Andric 4070b57cec5SDimitry Andric bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, 4080b57cec5SDimitry Andric const char *I, 4090b57cec5SDimitry Andric const char *E, 4100b57cec5SDimitry Andric const LangOptions &LO, 4110b57cec5SDimitry Andric const TargetInfo &Target, 4120b57cec5SDimitry Andric bool isFreeBSDKPrintf) { 4130b57cec5SDimitry Andric 4140b57cec5SDimitry Andric unsigned argIndex = 0; 4150b57cec5SDimitry Andric 4160b57cec5SDimitry Andric // Keep looking for a format specifier until we have exhausted the string. 4170b57cec5SDimitry Andric while (I != E) { 4180b57cec5SDimitry Andric const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, 4190b57cec5SDimitry Andric LO, Target, true, 4200b57cec5SDimitry Andric isFreeBSDKPrintf); 4210b57cec5SDimitry Andric // Did a fail-stop error of any kind occur when parsing the specifier? 4220b57cec5SDimitry Andric // If so, don't do any more processing. 4230b57cec5SDimitry Andric if (FSR.shouldStop()) 4240b57cec5SDimitry Andric return true; 4250b57cec5SDimitry Andric // Did we exhaust the string or encounter an error that 4260b57cec5SDimitry Andric // we can recover from? 4270b57cec5SDimitry Andric if (!FSR.hasValue()) 4280b57cec5SDimitry Andric continue; 4290b57cec5SDimitry Andric // We have a format specifier. Pass it to the callback. 4300b57cec5SDimitry Andric if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(), 4310b57cec5SDimitry Andric I - FSR.getStart())) 4320b57cec5SDimitry Andric return true; 4330b57cec5SDimitry Andric } 4340b57cec5SDimitry Andric assert(I == E && "Format string not exhausted"); 4350b57cec5SDimitry Andric return false; 4360b57cec5SDimitry Andric } 4370b57cec5SDimitry Andric 4380b57cec5SDimitry Andric bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I, 4390b57cec5SDimitry Andric const char *E, 4400b57cec5SDimitry Andric const LangOptions &LO, 4410b57cec5SDimitry Andric const TargetInfo &Target) { 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric unsigned argIndex = 0; 4440b57cec5SDimitry Andric 4450b57cec5SDimitry Andric // Keep looking for a %s format specifier until we have exhausted the string. 4460b57cec5SDimitry Andric FormatStringHandler H; 4470b57cec5SDimitry Andric while (I != E) { 4480b57cec5SDimitry Andric const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, 4490b57cec5SDimitry Andric LO, Target, false, 4500b57cec5SDimitry Andric false); 4510b57cec5SDimitry Andric // Did a fail-stop error of any kind occur when parsing the specifier? 4520b57cec5SDimitry Andric // If so, don't do any more processing. 4530b57cec5SDimitry Andric if (FSR.shouldStop()) 4540b57cec5SDimitry Andric return false; 4550b57cec5SDimitry Andric // Did we exhaust the string or encounter an error that 4560b57cec5SDimitry Andric // we can recover from? 4570b57cec5SDimitry Andric if (!FSR.hasValue()) 4580b57cec5SDimitry Andric continue; 4590b57cec5SDimitry Andric const analyze_printf::PrintfSpecifier &FS = FSR.getValue(); 4600b57cec5SDimitry Andric // Return true if this a %s format specifier. 4610b57cec5SDimitry Andric if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg) 4620b57cec5SDimitry Andric return true; 4630b57cec5SDimitry Andric } 4640b57cec5SDimitry Andric return false; 4650b57cec5SDimitry Andric } 4660b57cec5SDimitry Andric 467a7dea167SDimitry Andric bool clang::analyze_format_string::parseFormatStringHasFormattingSpecifiers( 468a7dea167SDimitry Andric const char *Begin, const char *End, const LangOptions &LO, 469a7dea167SDimitry Andric const TargetInfo &Target) { 470a7dea167SDimitry Andric unsigned ArgIndex = 0; 471a7dea167SDimitry Andric // Keep looking for a formatting specifier until we have exhausted the string. 472a7dea167SDimitry Andric FormatStringHandler H; 473a7dea167SDimitry Andric while (Begin != End) { 474a7dea167SDimitry Andric const PrintfSpecifierResult &FSR = 475a7dea167SDimitry Andric ParsePrintfSpecifier(H, Begin, End, ArgIndex, LO, Target, false, false); 476a7dea167SDimitry Andric if (FSR.shouldStop()) 477a7dea167SDimitry Andric break; 478a7dea167SDimitry Andric if (FSR.hasValue()) 479a7dea167SDimitry Andric return true; 480a7dea167SDimitry Andric } 481a7dea167SDimitry Andric return false; 482a7dea167SDimitry Andric } 483a7dea167SDimitry Andric 4840b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 4850b57cec5SDimitry Andric // Methods on PrintfSpecifier. 4860b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 4870b57cec5SDimitry Andric 4880b57cec5SDimitry Andric ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, 4890b57cec5SDimitry Andric bool IsObjCLiteral) const { 4900b57cec5SDimitry Andric if (CS.getKind() == ConversionSpecifier::cArg) 4910b57cec5SDimitry Andric switch (LM.getKind()) { 4920b57cec5SDimitry Andric case LengthModifier::None: 4930b57cec5SDimitry Andric return Ctx.IntTy; 4940b57cec5SDimitry Andric case LengthModifier::AsLong: 4950b57cec5SDimitry Andric case LengthModifier::AsWide: 4960b57cec5SDimitry Andric return ArgType(ArgType::WIntTy, "wint_t"); 4970b57cec5SDimitry Andric case LengthModifier::AsShort: 4980b57cec5SDimitry Andric if (Ctx.getTargetInfo().getTriple().isOSMSVCRT()) 4990b57cec5SDimitry Andric return Ctx.IntTy; 5000b57cec5SDimitry Andric LLVM_FALLTHROUGH; 5010b57cec5SDimitry Andric default: 5020b57cec5SDimitry Andric return ArgType::Invalid(); 5030b57cec5SDimitry Andric } 5040b57cec5SDimitry Andric 5050b57cec5SDimitry Andric if (CS.isIntArg()) 5060b57cec5SDimitry Andric switch (LM.getKind()) { 5070b57cec5SDimitry Andric case LengthModifier::AsLongDouble: 5080b57cec5SDimitry Andric // GNU extension. 5090b57cec5SDimitry Andric return Ctx.LongLongTy; 5100b57cec5SDimitry Andric case LengthModifier::None: 5110b57cec5SDimitry Andric case LengthModifier::AsShortLong: 5120b57cec5SDimitry Andric return Ctx.IntTy; 5130b57cec5SDimitry Andric case LengthModifier::AsInt32: 5140b57cec5SDimitry Andric return ArgType(Ctx.IntTy, "__int32"); 5150b57cec5SDimitry Andric case LengthModifier::AsChar: 5160b57cec5SDimitry Andric return ArgType::AnyCharTy; 5170b57cec5SDimitry Andric case LengthModifier::AsShort: return Ctx.ShortTy; 5180b57cec5SDimitry Andric case LengthModifier::AsLong: return Ctx.LongTy; 5190b57cec5SDimitry Andric case LengthModifier::AsLongLong: 5200b57cec5SDimitry Andric case LengthModifier::AsQuad: 5210b57cec5SDimitry Andric return Ctx.LongLongTy; 5220b57cec5SDimitry Andric case LengthModifier::AsInt64: 5230b57cec5SDimitry Andric return ArgType(Ctx.LongLongTy, "__int64"); 5240b57cec5SDimitry Andric case LengthModifier::AsIntMax: 5250b57cec5SDimitry Andric return ArgType(Ctx.getIntMaxType(), "intmax_t"); 5260b57cec5SDimitry Andric case LengthModifier::AsSizeT: 5270b57cec5SDimitry Andric return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(), "ssize_t")); 5280b57cec5SDimitry Andric case LengthModifier::AsInt3264: 5290b57cec5SDimitry Andric return Ctx.getTargetInfo().getTriple().isArch64Bit() 5300b57cec5SDimitry Andric ? ArgType(Ctx.LongLongTy, "__int64") 5310b57cec5SDimitry Andric : ArgType(Ctx.IntTy, "__int32"); 5320b57cec5SDimitry Andric case LengthModifier::AsPtrDiff: 5330b57cec5SDimitry Andric return ArgType::makePtrdiffT( 5340b57cec5SDimitry Andric ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); 5350b57cec5SDimitry Andric case LengthModifier::AsAllocate: 5360b57cec5SDimitry Andric case LengthModifier::AsMAllocate: 5370b57cec5SDimitry Andric case LengthModifier::AsWide: 5380b57cec5SDimitry Andric return ArgType::Invalid(); 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric if (CS.isUIntArg()) 5420b57cec5SDimitry Andric switch (LM.getKind()) { 5430b57cec5SDimitry Andric case LengthModifier::AsLongDouble: 5440b57cec5SDimitry Andric // GNU extension. 5450b57cec5SDimitry Andric return Ctx.UnsignedLongLongTy; 5460b57cec5SDimitry Andric case LengthModifier::None: 5470b57cec5SDimitry Andric case LengthModifier::AsShortLong: 5480b57cec5SDimitry Andric return Ctx.UnsignedIntTy; 5490b57cec5SDimitry Andric case LengthModifier::AsInt32: 5500b57cec5SDimitry Andric return ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); 5510b57cec5SDimitry Andric case LengthModifier::AsChar: return Ctx.UnsignedCharTy; 5520b57cec5SDimitry Andric case LengthModifier::AsShort: return Ctx.UnsignedShortTy; 5530b57cec5SDimitry Andric case LengthModifier::AsLong: return Ctx.UnsignedLongTy; 5540b57cec5SDimitry Andric case LengthModifier::AsLongLong: 5550b57cec5SDimitry Andric case LengthModifier::AsQuad: 5560b57cec5SDimitry Andric return Ctx.UnsignedLongLongTy; 5570b57cec5SDimitry Andric case LengthModifier::AsInt64: 5580b57cec5SDimitry Andric return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"); 5590b57cec5SDimitry Andric case LengthModifier::AsIntMax: 5600b57cec5SDimitry Andric return ArgType(Ctx.getUIntMaxType(), "uintmax_t"); 5610b57cec5SDimitry Andric case LengthModifier::AsSizeT: 5620b57cec5SDimitry Andric return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t")); 5630b57cec5SDimitry Andric case LengthModifier::AsInt3264: 5640b57cec5SDimitry Andric return Ctx.getTargetInfo().getTriple().isArch64Bit() 5650b57cec5SDimitry Andric ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64") 5660b57cec5SDimitry Andric : ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); 5670b57cec5SDimitry Andric case LengthModifier::AsPtrDiff: 5680b57cec5SDimitry Andric return ArgType::makePtrdiffT( 5690b57cec5SDimitry Andric ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t")); 5700b57cec5SDimitry Andric case LengthModifier::AsAllocate: 5710b57cec5SDimitry Andric case LengthModifier::AsMAllocate: 5720b57cec5SDimitry Andric case LengthModifier::AsWide: 5730b57cec5SDimitry Andric return ArgType::Invalid(); 5740b57cec5SDimitry Andric } 5750b57cec5SDimitry Andric 5760b57cec5SDimitry Andric if (CS.isDoubleArg()) { 5770b57cec5SDimitry Andric if (!VectorNumElts.isInvalid()) { 5780b57cec5SDimitry Andric switch (LM.getKind()) { 5790b57cec5SDimitry Andric case LengthModifier::AsShort: 5800b57cec5SDimitry Andric return Ctx.HalfTy; 5810b57cec5SDimitry Andric case LengthModifier::AsShortLong: 5820b57cec5SDimitry Andric return Ctx.FloatTy; 5830b57cec5SDimitry Andric case LengthModifier::AsLong: 5840b57cec5SDimitry Andric default: 5850b57cec5SDimitry Andric return Ctx.DoubleTy; 5860b57cec5SDimitry Andric } 5870b57cec5SDimitry Andric } 5880b57cec5SDimitry Andric 5890b57cec5SDimitry Andric if (LM.getKind() == LengthModifier::AsLongDouble) 5900b57cec5SDimitry Andric return Ctx.LongDoubleTy; 5910b57cec5SDimitry Andric return Ctx.DoubleTy; 5920b57cec5SDimitry Andric } 5930b57cec5SDimitry Andric 5940b57cec5SDimitry Andric if (CS.getKind() == ConversionSpecifier::nArg) { 5950b57cec5SDimitry Andric switch (LM.getKind()) { 5960b57cec5SDimitry Andric case LengthModifier::None: 5970b57cec5SDimitry Andric return ArgType::PtrTo(Ctx.IntTy); 5980b57cec5SDimitry Andric case LengthModifier::AsChar: 5990b57cec5SDimitry Andric return ArgType::PtrTo(Ctx.SignedCharTy); 6000b57cec5SDimitry Andric case LengthModifier::AsShort: 6010b57cec5SDimitry Andric return ArgType::PtrTo(Ctx.ShortTy); 6020b57cec5SDimitry Andric case LengthModifier::AsLong: 6030b57cec5SDimitry Andric return ArgType::PtrTo(Ctx.LongTy); 6040b57cec5SDimitry Andric case LengthModifier::AsLongLong: 6050b57cec5SDimitry Andric case LengthModifier::AsQuad: 6060b57cec5SDimitry Andric return ArgType::PtrTo(Ctx.LongLongTy); 6070b57cec5SDimitry Andric case LengthModifier::AsIntMax: 6080b57cec5SDimitry Andric return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); 6090b57cec5SDimitry Andric case LengthModifier::AsSizeT: 6100b57cec5SDimitry Andric return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t")); 6110b57cec5SDimitry Andric case LengthModifier::AsPtrDiff: 6120b57cec5SDimitry Andric return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); 6130b57cec5SDimitry Andric case LengthModifier::AsLongDouble: 6140b57cec5SDimitry Andric return ArgType(); // FIXME: Is this a known extension? 6150b57cec5SDimitry Andric case LengthModifier::AsAllocate: 6160b57cec5SDimitry Andric case LengthModifier::AsMAllocate: 6170b57cec5SDimitry Andric case LengthModifier::AsInt32: 6180b57cec5SDimitry Andric case LengthModifier::AsInt3264: 6190b57cec5SDimitry Andric case LengthModifier::AsInt64: 6200b57cec5SDimitry Andric case LengthModifier::AsWide: 6210b57cec5SDimitry Andric return ArgType::Invalid(); 6220b57cec5SDimitry Andric case LengthModifier::AsShortLong: 6230b57cec5SDimitry Andric llvm_unreachable("only used for OpenCL which doesn not handle nArg"); 6240b57cec5SDimitry Andric } 6250b57cec5SDimitry Andric } 6260b57cec5SDimitry Andric 6270b57cec5SDimitry Andric switch (CS.getKind()) { 6280b57cec5SDimitry Andric case ConversionSpecifier::sArg: 6290b57cec5SDimitry Andric if (LM.getKind() == LengthModifier::AsWideChar) { 6300b57cec5SDimitry Andric if (IsObjCLiteral) 6310b57cec5SDimitry Andric return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), 6320b57cec5SDimitry Andric "const unichar *"); 6330b57cec5SDimitry Andric return ArgType(ArgType::WCStrTy, "wchar_t *"); 6340b57cec5SDimitry Andric } 6350b57cec5SDimitry Andric if (LM.getKind() == LengthModifier::AsWide) 6360b57cec5SDimitry Andric return ArgType(ArgType::WCStrTy, "wchar_t *"); 6370b57cec5SDimitry Andric return ArgType::CStrTy; 6380b57cec5SDimitry Andric case ConversionSpecifier::SArg: 6390b57cec5SDimitry Andric if (IsObjCLiteral) 6400b57cec5SDimitry Andric return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), 6410b57cec5SDimitry Andric "const unichar *"); 6420b57cec5SDimitry Andric if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() && 6430b57cec5SDimitry Andric LM.getKind() == LengthModifier::AsShort) 6440b57cec5SDimitry Andric return ArgType::CStrTy; 6450b57cec5SDimitry Andric return ArgType(ArgType::WCStrTy, "wchar_t *"); 6460b57cec5SDimitry Andric case ConversionSpecifier::CArg: 6470b57cec5SDimitry Andric if (IsObjCLiteral) 6480b57cec5SDimitry Andric return ArgType(Ctx.UnsignedShortTy, "unichar"); 6490b57cec5SDimitry Andric if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() && 6500b57cec5SDimitry Andric LM.getKind() == LengthModifier::AsShort) 6510b57cec5SDimitry Andric return Ctx.IntTy; 6520b57cec5SDimitry Andric return ArgType(Ctx.WideCharTy, "wchar_t"); 6530b57cec5SDimitry Andric case ConversionSpecifier::pArg: 6540b57cec5SDimitry Andric case ConversionSpecifier::PArg: 6550b57cec5SDimitry Andric return ArgType::CPointerTy; 6560b57cec5SDimitry Andric case ConversionSpecifier::ObjCObjArg: 6570b57cec5SDimitry Andric return ArgType::ObjCPointerTy; 6580b57cec5SDimitry Andric default: 6590b57cec5SDimitry Andric break; 6600b57cec5SDimitry Andric } 6610b57cec5SDimitry Andric 6620b57cec5SDimitry Andric // FIXME: Handle other cases. 6630b57cec5SDimitry Andric return ArgType(); 6640b57cec5SDimitry Andric } 6650b57cec5SDimitry Andric 6660b57cec5SDimitry Andric 6670b57cec5SDimitry Andric ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, 6680b57cec5SDimitry Andric bool IsObjCLiteral) const { 6690b57cec5SDimitry Andric const PrintfConversionSpecifier &CS = getConversionSpecifier(); 6700b57cec5SDimitry Andric 6710b57cec5SDimitry Andric if (!CS.consumesDataArgument()) 6720b57cec5SDimitry Andric return ArgType::Invalid(); 6730b57cec5SDimitry Andric 6740b57cec5SDimitry Andric ArgType ScalarTy = getScalarArgType(Ctx, IsObjCLiteral); 6750b57cec5SDimitry Andric if (!ScalarTy.isValid() || VectorNumElts.isInvalid()) 6760b57cec5SDimitry Andric return ScalarTy; 6770b57cec5SDimitry Andric 6780b57cec5SDimitry Andric return ScalarTy.makeVectorType(Ctx, VectorNumElts.getConstantAmount()); 6790b57cec5SDimitry Andric } 6800b57cec5SDimitry Andric 6810b57cec5SDimitry Andric bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, 6820b57cec5SDimitry Andric ASTContext &Ctx, bool IsObjCLiteral) { 6830b57cec5SDimitry Andric // %n is different from other conversion specifiers; don't try to fix it. 6840b57cec5SDimitry Andric if (CS.getKind() == ConversionSpecifier::nArg) 6850b57cec5SDimitry Andric return false; 6860b57cec5SDimitry Andric 6870b57cec5SDimitry Andric // Handle Objective-C objects first. Note that while the '%@' specifier will 6880b57cec5SDimitry Andric // not warn for structure pointer or void pointer arguments (because that's 6890b57cec5SDimitry Andric // how CoreFoundation objects are implemented), we only show a fixit for '%@' 6900b57cec5SDimitry Andric // if we know it's an object (block, id, class, or __attribute__((NSObject))). 6910b57cec5SDimitry Andric if (QT->isObjCRetainableType()) { 6920b57cec5SDimitry Andric if (!IsObjCLiteral) 6930b57cec5SDimitry Andric return false; 6940b57cec5SDimitry Andric 6950b57cec5SDimitry Andric CS.setKind(ConversionSpecifier::ObjCObjArg); 6960b57cec5SDimitry Andric 6970b57cec5SDimitry Andric // Disable irrelevant flags 6980b57cec5SDimitry Andric HasThousandsGrouping = false; 6990b57cec5SDimitry Andric HasPlusPrefix = false; 7000b57cec5SDimitry Andric HasSpacePrefix = false; 7010b57cec5SDimitry Andric HasAlternativeForm = false; 7020b57cec5SDimitry Andric HasLeadingZeroes = false; 7030b57cec5SDimitry Andric Precision.setHowSpecified(OptionalAmount::NotSpecified); 7040b57cec5SDimitry Andric LM.setKind(LengthModifier::None); 7050b57cec5SDimitry Andric 7060b57cec5SDimitry Andric return true; 7070b57cec5SDimitry Andric } 7080b57cec5SDimitry Andric 7090b57cec5SDimitry Andric // Handle strings next (char *, wchar_t *) 7100b57cec5SDimitry Andric if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { 7110b57cec5SDimitry Andric CS.setKind(ConversionSpecifier::sArg); 7120b57cec5SDimitry Andric 7130b57cec5SDimitry Andric // Disable irrelevant flags 7140b57cec5SDimitry Andric HasAlternativeForm = 0; 7150b57cec5SDimitry Andric HasLeadingZeroes = 0; 7160b57cec5SDimitry Andric 7170b57cec5SDimitry Andric // Set the long length modifier for wide characters 7180b57cec5SDimitry Andric if (QT->getPointeeType()->isWideCharType()) 7190b57cec5SDimitry Andric LM.setKind(LengthModifier::AsWideChar); 7200b57cec5SDimitry Andric else 7210b57cec5SDimitry Andric LM.setKind(LengthModifier::None); 7220b57cec5SDimitry Andric 7230b57cec5SDimitry Andric return true; 7240b57cec5SDimitry Andric } 7250b57cec5SDimitry Andric 7260b57cec5SDimitry Andric // If it's an enum, get its underlying type. 7270b57cec5SDimitry Andric if (const EnumType *ETy = QT->getAs<EnumType>()) 7280b57cec5SDimitry Andric QT = ETy->getDecl()->getIntegerType(); 7290b57cec5SDimitry Andric 7300b57cec5SDimitry Andric const BuiltinType *BT = QT->getAs<BuiltinType>(); 7310b57cec5SDimitry Andric if (!BT) { 7320b57cec5SDimitry Andric const VectorType *VT = QT->getAs<VectorType>(); 7330b57cec5SDimitry Andric if (VT) { 7340b57cec5SDimitry Andric QT = VT->getElementType(); 7350b57cec5SDimitry Andric BT = QT->getAs<BuiltinType>(); 7360b57cec5SDimitry Andric VectorNumElts = OptionalAmount(VT->getNumElements()); 7370b57cec5SDimitry Andric } 7380b57cec5SDimitry Andric } 7390b57cec5SDimitry Andric 7400b57cec5SDimitry Andric // We can only work with builtin types. 7410b57cec5SDimitry Andric if (!BT) 7420b57cec5SDimitry Andric return false; 7430b57cec5SDimitry Andric 7440b57cec5SDimitry Andric // Set length modifier 7450b57cec5SDimitry Andric switch (BT->getKind()) { 7460b57cec5SDimitry Andric case BuiltinType::Bool: 7470b57cec5SDimitry Andric case BuiltinType::WChar_U: 7480b57cec5SDimitry Andric case BuiltinType::WChar_S: 7490b57cec5SDimitry Andric case BuiltinType::Char8: // FIXME: Treat like 'char'? 7500b57cec5SDimitry Andric case BuiltinType::Char16: 7510b57cec5SDimitry Andric case BuiltinType::Char32: 7520b57cec5SDimitry Andric case BuiltinType::UInt128: 7530b57cec5SDimitry Andric case BuiltinType::Int128: 7540b57cec5SDimitry Andric case BuiltinType::Half: 7555ffd83dbSDimitry Andric case BuiltinType::BFloat16: 7560b57cec5SDimitry Andric case BuiltinType::Float16: 7570b57cec5SDimitry Andric case BuiltinType::Float128: 7580b57cec5SDimitry Andric case BuiltinType::ShortAccum: 7590b57cec5SDimitry Andric case BuiltinType::Accum: 7600b57cec5SDimitry Andric case BuiltinType::LongAccum: 7610b57cec5SDimitry Andric case BuiltinType::UShortAccum: 7620b57cec5SDimitry Andric case BuiltinType::UAccum: 7630b57cec5SDimitry Andric case BuiltinType::ULongAccum: 7640b57cec5SDimitry Andric case BuiltinType::ShortFract: 7650b57cec5SDimitry Andric case BuiltinType::Fract: 7660b57cec5SDimitry Andric case BuiltinType::LongFract: 7670b57cec5SDimitry Andric case BuiltinType::UShortFract: 7680b57cec5SDimitry Andric case BuiltinType::UFract: 7690b57cec5SDimitry Andric case BuiltinType::ULongFract: 7700b57cec5SDimitry Andric case BuiltinType::SatShortAccum: 7710b57cec5SDimitry Andric case BuiltinType::SatAccum: 7720b57cec5SDimitry Andric case BuiltinType::SatLongAccum: 7730b57cec5SDimitry Andric case BuiltinType::SatUShortAccum: 7740b57cec5SDimitry Andric case BuiltinType::SatUAccum: 7750b57cec5SDimitry Andric case BuiltinType::SatULongAccum: 7760b57cec5SDimitry Andric case BuiltinType::SatShortFract: 7770b57cec5SDimitry Andric case BuiltinType::SatFract: 7780b57cec5SDimitry Andric case BuiltinType::SatLongFract: 7790b57cec5SDimitry Andric case BuiltinType::SatUShortFract: 7800b57cec5SDimitry Andric case BuiltinType::SatUFract: 7810b57cec5SDimitry Andric case BuiltinType::SatULongFract: 7820b57cec5SDimitry Andric // Various types which are non-trivial to correct. 7830b57cec5SDimitry Andric return false; 7840b57cec5SDimitry Andric 7850b57cec5SDimitry Andric #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ 7860b57cec5SDimitry Andric case BuiltinType::Id: 7870b57cec5SDimitry Andric #include "clang/Basic/OpenCLImageTypes.def" 7880b57cec5SDimitry Andric #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ 7890b57cec5SDimitry Andric case BuiltinType::Id: 7900b57cec5SDimitry Andric #include "clang/Basic/OpenCLExtensionTypes.def" 791a7dea167SDimitry Andric #define SVE_TYPE(Name, Id, SingletonId) \ 792a7dea167SDimitry Andric case BuiltinType::Id: 793a7dea167SDimitry Andric #include "clang/Basic/AArch64SVEACLETypes.def" 794*e8d8bef9SDimitry Andric #define PPC_VECTOR_TYPE(Name, Id, Size) \ 795*e8d8bef9SDimitry Andric case BuiltinType::Id: 796*e8d8bef9SDimitry Andric #include "clang/Basic/PPCTypes.def" 7970b57cec5SDimitry Andric #define SIGNED_TYPE(Id, SingletonId) 7980b57cec5SDimitry Andric #define UNSIGNED_TYPE(Id, SingletonId) 7990b57cec5SDimitry Andric #define FLOATING_TYPE(Id, SingletonId) 8000b57cec5SDimitry Andric #define BUILTIN_TYPE(Id, SingletonId) \ 8010b57cec5SDimitry Andric case BuiltinType::Id: 8020b57cec5SDimitry Andric #include "clang/AST/BuiltinTypes.def" 8030b57cec5SDimitry Andric // Misc other stuff which doesn't make sense here. 8040b57cec5SDimitry Andric return false; 8050b57cec5SDimitry Andric 8060b57cec5SDimitry Andric case BuiltinType::UInt: 8070b57cec5SDimitry Andric case BuiltinType::Int: 8080b57cec5SDimitry Andric case BuiltinType::Float: 8090b57cec5SDimitry Andric LM.setKind(VectorNumElts.isInvalid() ? 8100b57cec5SDimitry Andric LengthModifier::None : LengthModifier::AsShortLong); 8110b57cec5SDimitry Andric break; 8120b57cec5SDimitry Andric case BuiltinType::Double: 8130b57cec5SDimitry Andric LM.setKind(VectorNumElts.isInvalid() ? 8140b57cec5SDimitry Andric LengthModifier::None : LengthModifier::AsLong); 8150b57cec5SDimitry Andric break; 8160b57cec5SDimitry Andric case BuiltinType::Char_U: 8170b57cec5SDimitry Andric case BuiltinType::UChar: 8180b57cec5SDimitry Andric case BuiltinType::Char_S: 8190b57cec5SDimitry Andric case BuiltinType::SChar: 8200b57cec5SDimitry Andric LM.setKind(LengthModifier::AsChar); 8210b57cec5SDimitry Andric break; 8220b57cec5SDimitry Andric 8230b57cec5SDimitry Andric case BuiltinType::Short: 8240b57cec5SDimitry Andric case BuiltinType::UShort: 8250b57cec5SDimitry Andric LM.setKind(LengthModifier::AsShort); 8260b57cec5SDimitry Andric break; 8270b57cec5SDimitry Andric 8280b57cec5SDimitry Andric case BuiltinType::Long: 8290b57cec5SDimitry Andric case BuiltinType::ULong: 8300b57cec5SDimitry Andric LM.setKind(LengthModifier::AsLong); 8310b57cec5SDimitry Andric break; 8320b57cec5SDimitry Andric 8330b57cec5SDimitry Andric case BuiltinType::LongLong: 8340b57cec5SDimitry Andric case BuiltinType::ULongLong: 8350b57cec5SDimitry Andric LM.setKind(LengthModifier::AsLongLong); 8360b57cec5SDimitry Andric break; 8370b57cec5SDimitry Andric 8380b57cec5SDimitry Andric case BuiltinType::LongDouble: 8390b57cec5SDimitry Andric LM.setKind(LengthModifier::AsLongDouble); 8400b57cec5SDimitry Andric break; 8410b57cec5SDimitry Andric } 8420b57cec5SDimitry Andric 8430b57cec5SDimitry Andric // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. 8440b57cec5SDimitry Andric if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11)) 8450b57cec5SDimitry Andric namedTypeToLengthModifier(QT, LM); 8460b57cec5SDimitry Andric 8470b57cec5SDimitry Andric // If fixing the length modifier was enough, we might be done. 8480b57cec5SDimitry Andric if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) { 8490b57cec5SDimitry Andric // If we're going to offer a fix anyway, make sure the sign matches. 8500b57cec5SDimitry Andric switch (CS.getKind()) { 8510b57cec5SDimitry Andric case ConversionSpecifier::uArg: 8520b57cec5SDimitry Andric case ConversionSpecifier::UArg: 8530b57cec5SDimitry Andric if (QT->isSignedIntegerType()) 8540b57cec5SDimitry Andric CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg); 8550b57cec5SDimitry Andric break; 8560b57cec5SDimitry Andric case ConversionSpecifier::dArg: 8570b57cec5SDimitry Andric case ConversionSpecifier::DArg: 8580b57cec5SDimitry Andric case ConversionSpecifier::iArg: 8590b57cec5SDimitry Andric if (QT->isUnsignedIntegerType() && !HasPlusPrefix) 8600b57cec5SDimitry Andric CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg); 8610b57cec5SDimitry Andric break; 8620b57cec5SDimitry Andric default: 8630b57cec5SDimitry Andric // Other specifiers do not have signed/unsigned variants. 8640b57cec5SDimitry Andric break; 8650b57cec5SDimitry Andric } 8660b57cec5SDimitry Andric 8670b57cec5SDimitry Andric const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral); 8680b57cec5SDimitry Andric if (ATR.isValid() && ATR.matchesType(Ctx, QT)) 8690b57cec5SDimitry Andric return true; 8700b57cec5SDimitry Andric } 8710b57cec5SDimitry Andric 8720b57cec5SDimitry Andric // Set conversion specifier and disable any flags which do not apply to it. 8730b57cec5SDimitry Andric // Let typedefs to char fall through to int, as %c is silly for uint8_t. 8740b57cec5SDimitry Andric if (!isa<TypedefType>(QT) && QT->isCharType()) { 8750b57cec5SDimitry Andric CS.setKind(ConversionSpecifier::cArg); 8760b57cec5SDimitry Andric LM.setKind(LengthModifier::None); 8770b57cec5SDimitry Andric Precision.setHowSpecified(OptionalAmount::NotSpecified); 8780b57cec5SDimitry Andric HasAlternativeForm = 0; 8790b57cec5SDimitry Andric HasLeadingZeroes = 0; 8800b57cec5SDimitry Andric HasPlusPrefix = 0; 8810b57cec5SDimitry Andric } 8820b57cec5SDimitry Andric // Test for Floating type first as LongDouble can pass isUnsignedIntegerType 8830b57cec5SDimitry Andric else if (QT->isRealFloatingType()) { 8840b57cec5SDimitry Andric CS.setKind(ConversionSpecifier::fArg); 8850b57cec5SDimitry Andric } 8860b57cec5SDimitry Andric else if (QT->isSignedIntegerType()) { 8870b57cec5SDimitry Andric CS.setKind(ConversionSpecifier::dArg); 8880b57cec5SDimitry Andric HasAlternativeForm = 0; 8890b57cec5SDimitry Andric } 8900b57cec5SDimitry Andric else if (QT->isUnsignedIntegerType()) { 8910b57cec5SDimitry Andric CS.setKind(ConversionSpecifier::uArg); 8920b57cec5SDimitry Andric HasAlternativeForm = 0; 8930b57cec5SDimitry Andric HasPlusPrefix = 0; 8940b57cec5SDimitry Andric } else { 8950b57cec5SDimitry Andric llvm_unreachable("Unexpected type"); 8960b57cec5SDimitry Andric } 8970b57cec5SDimitry Andric 8980b57cec5SDimitry Andric return true; 8990b57cec5SDimitry Andric } 9000b57cec5SDimitry Andric 9010b57cec5SDimitry Andric void PrintfSpecifier::toString(raw_ostream &os) const { 9020b57cec5SDimitry Andric // Whilst some features have no defined order, we are using the order 9030b57cec5SDimitry Andric // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1) 9040b57cec5SDimitry Andric os << "%"; 9050b57cec5SDimitry Andric 9060b57cec5SDimitry Andric // Positional args 9070b57cec5SDimitry Andric if (usesPositionalArg()) { 9080b57cec5SDimitry Andric os << getPositionalArgIndex() << "$"; 9090b57cec5SDimitry Andric } 9100b57cec5SDimitry Andric 9110b57cec5SDimitry Andric // Conversion flags 9120b57cec5SDimitry Andric if (IsLeftJustified) os << "-"; 9130b57cec5SDimitry Andric if (HasPlusPrefix) os << "+"; 9140b57cec5SDimitry Andric if (HasSpacePrefix) os << " "; 9150b57cec5SDimitry Andric if (HasAlternativeForm) os << "#"; 9160b57cec5SDimitry Andric if (HasLeadingZeroes) os << "0"; 9170b57cec5SDimitry Andric 9180b57cec5SDimitry Andric // Minimum field width 9190b57cec5SDimitry Andric FieldWidth.toString(os); 9200b57cec5SDimitry Andric // Precision 9210b57cec5SDimitry Andric Precision.toString(os); 9220b57cec5SDimitry Andric 9230b57cec5SDimitry Andric // Vector modifier 9240b57cec5SDimitry Andric if (!VectorNumElts.isInvalid()) 9250b57cec5SDimitry Andric os << 'v' << VectorNumElts.getConstantAmount(); 9260b57cec5SDimitry Andric 9270b57cec5SDimitry Andric // Length modifier 9280b57cec5SDimitry Andric os << LM.toString(); 9290b57cec5SDimitry Andric // Conversion specifier 9300b57cec5SDimitry Andric os << CS.toString(); 9310b57cec5SDimitry Andric } 9320b57cec5SDimitry Andric 9330b57cec5SDimitry Andric bool PrintfSpecifier::hasValidPlusPrefix() const { 9340b57cec5SDimitry Andric if (!HasPlusPrefix) 9350b57cec5SDimitry Andric return true; 9360b57cec5SDimitry Andric 9370b57cec5SDimitry Andric // The plus prefix only makes sense for signed conversions 9380b57cec5SDimitry Andric switch (CS.getKind()) { 9390b57cec5SDimitry Andric case ConversionSpecifier::dArg: 9400b57cec5SDimitry Andric case ConversionSpecifier::DArg: 9410b57cec5SDimitry Andric case ConversionSpecifier::iArg: 9420b57cec5SDimitry Andric case ConversionSpecifier::fArg: 9430b57cec5SDimitry Andric case ConversionSpecifier::FArg: 9440b57cec5SDimitry Andric case ConversionSpecifier::eArg: 9450b57cec5SDimitry Andric case ConversionSpecifier::EArg: 9460b57cec5SDimitry Andric case ConversionSpecifier::gArg: 9470b57cec5SDimitry Andric case ConversionSpecifier::GArg: 9480b57cec5SDimitry Andric case ConversionSpecifier::aArg: 9490b57cec5SDimitry Andric case ConversionSpecifier::AArg: 9500b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDrArg: 9510b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDyArg: 9520b57cec5SDimitry Andric return true; 9530b57cec5SDimitry Andric 9540b57cec5SDimitry Andric default: 9550b57cec5SDimitry Andric return false; 9560b57cec5SDimitry Andric } 9570b57cec5SDimitry Andric } 9580b57cec5SDimitry Andric 9590b57cec5SDimitry Andric bool PrintfSpecifier::hasValidAlternativeForm() const { 9600b57cec5SDimitry Andric if (!HasAlternativeForm) 9610b57cec5SDimitry Andric return true; 9620b57cec5SDimitry Andric 9630b57cec5SDimitry Andric // Alternate form flag only valid with the oxXaAeEfFgG conversions 9640b57cec5SDimitry Andric switch (CS.getKind()) { 9650b57cec5SDimitry Andric case ConversionSpecifier::oArg: 9660b57cec5SDimitry Andric case ConversionSpecifier::OArg: 9670b57cec5SDimitry Andric case ConversionSpecifier::xArg: 9680b57cec5SDimitry Andric case ConversionSpecifier::XArg: 9690b57cec5SDimitry Andric case ConversionSpecifier::aArg: 9700b57cec5SDimitry Andric case ConversionSpecifier::AArg: 9710b57cec5SDimitry Andric case ConversionSpecifier::eArg: 9720b57cec5SDimitry Andric case ConversionSpecifier::EArg: 9730b57cec5SDimitry Andric case ConversionSpecifier::fArg: 9740b57cec5SDimitry Andric case ConversionSpecifier::FArg: 9750b57cec5SDimitry Andric case ConversionSpecifier::gArg: 9760b57cec5SDimitry Andric case ConversionSpecifier::GArg: 9770b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDrArg: 9780b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDyArg: 9790b57cec5SDimitry Andric return true; 9800b57cec5SDimitry Andric 9810b57cec5SDimitry Andric default: 9820b57cec5SDimitry Andric return false; 9830b57cec5SDimitry Andric } 9840b57cec5SDimitry Andric } 9850b57cec5SDimitry Andric 9860b57cec5SDimitry Andric bool PrintfSpecifier::hasValidLeadingZeros() const { 9870b57cec5SDimitry Andric if (!HasLeadingZeroes) 9880b57cec5SDimitry Andric return true; 9890b57cec5SDimitry Andric 9900b57cec5SDimitry Andric // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions 9910b57cec5SDimitry Andric switch (CS.getKind()) { 9920b57cec5SDimitry Andric case ConversionSpecifier::dArg: 9930b57cec5SDimitry Andric case ConversionSpecifier::DArg: 9940b57cec5SDimitry Andric case ConversionSpecifier::iArg: 9950b57cec5SDimitry Andric case ConversionSpecifier::oArg: 9960b57cec5SDimitry Andric case ConversionSpecifier::OArg: 9970b57cec5SDimitry Andric case ConversionSpecifier::uArg: 9980b57cec5SDimitry Andric case ConversionSpecifier::UArg: 9990b57cec5SDimitry Andric case ConversionSpecifier::xArg: 10000b57cec5SDimitry Andric case ConversionSpecifier::XArg: 10010b57cec5SDimitry Andric case ConversionSpecifier::aArg: 10020b57cec5SDimitry Andric case ConversionSpecifier::AArg: 10030b57cec5SDimitry Andric case ConversionSpecifier::eArg: 10040b57cec5SDimitry Andric case ConversionSpecifier::EArg: 10050b57cec5SDimitry Andric case ConversionSpecifier::fArg: 10060b57cec5SDimitry Andric case ConversionSpecifier::FArg: 10070b57cec5SDimitry Andric case ConversionSpecifier::gArg: 10080b57cec5SDimitry Andric case ConversionSpecifier::GArg: 10090b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDrArg: 10100b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDyArg: 10110b57cec5SDimitry Andric return true; 10120b57cec5SDimitry Andric 10130b57cec5SDimitry Andric default: 10140b57cec5SDimitry Andric return false; 10150b57cec5SDimitry Andric } 10160b57cec5SDimitry Andric } 10170b57cec5SDimitry Andric 10180b57cec5SDimitry Andric bool PrintfSpecifier::hasValidSpacePrefix() const { 10190b57cec5SDimitry Andric if (!HasSpacePrefix) 10200b57cec5SDimitry Andric return true; 10210b57cec5SDimitry Andric 10220b57cec5SDimitry Andric // The space prefix only makes sense for signed conversions 10230b57cec5SDimitry Andric switch (CS.getKind()) { 10240b57cec5SDimitry Andric case ConversionSpecifier::dArg: 10250b57cec5SDimitry Andric case ConversionSpecifier::DArg: 10260b57cec5SDimitry Andric case ConversionSpecifier::iArg: 10270b57cec5SDimitry Andric case ConversionSpecifier::fArg: 10280b57cec5SDimitry Andric case ConversionSpecifier::FArg: 10290b57cec5SDimitry Andric case ConversionSpecifier::eArg: 10300b57cec5SDimitry Andric case ConversionSpecifier::EArg: 10310b57cec5SDimitry Andric case ConversionSpecifier::gArg: 10320b57cec5SDimitry Andric case ConversionSpecifier::GArg: 10330b57cec5SDimitry Andric case ConversionSpecifier::aArg: 10340b57cec5SDimitry Andric case ConversionSpecifier::AArg: 10350b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDrArg: 10360b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDyArg: 10370b57cec5SDimitry Andric return true; 10380b57cec5SDimitry Andric 10390b57cec5SDimitry Andric default: 10400b57cec5SDimitry Andric return false; 10410b57cec5SDimitry Andric } 10420b57cec5SDimitry Andric } 10430b57cec5SDimitry Andric 10440b57cec5SDimitry Andric bool PrintfSpecifier::hasValidLeftJustified() const { 10450b57cec5SDimitry Andric if (!IsLeftJustified) 10460b57cec5SDimitry Andric return true; 10470b57cec5SDimitry Andric 10480b57cec5SDimitry Andric // The left justified flag is valid for all conversions except n 10490b57cec5SDimitry Andric switch (CS.getKind()) { 10500b57cec5SDimitry Andric case ConversionSpecifier::nArg: 10510b57cec5SDimitry Andric return false; 10520b57cec5SDimitry Andric 10530b57cec5SDimitry Andric default: 10540b57cec5SDimitry Andric return true; 10550b57cec5SDimitry Andric } 10560b57cec5SDimitry Andric } 10570b57cec5SDimitry Andric 10580b57cec5SDimitry Andric bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const { 10590b57cec5SDimitry Andric if (!HasThousandsGrouping) 10600b57cec5SDimitry Andric return true; 10610b57cec5SDimitry Andric 10620b57cec5SDimitry Andric switch (CS.getKind()) { 10630b57cec5SDimitry Andric case ConversionSpecifier::dArg: 10640b57cec5SDimitry Andric case ConversionSpecifier::DArg: 10650b57cec5SDimitry Andric case ConversionSpecifier::iArg: 10660b57cec5SDimitry Andric case ConversionSpecifier::uArg: 10670b57cec5SDimitry Andric case ConversionSpecifier::UArg: 10680b57cec5SDimitry Andric case ConversionSpecifier::fArg: 10690b57cec5SDimitry Andric case ConversionSpecifier::FArg: 10700b57cec5SDimitry Andric case ConversionSpecifier::gArg: 10710b57cec5SDimitry Andric case ConversionSpecifier::GArg: 10720b57cec5SDimitry Andric return true; 10730b57cec5SDimitry Andric default: 10740b57cec5SDimitry Andric return false; 10750b57cec5SDimitry Andric } 10760b57cec5SDimitry Andric } 10770b57cec5SDimitry Andric 10780b57cec5SDimitry Andric bool PrintfSpecifier::hasValidPrecision() const { 10790b57cec5SDimitry Andric if (Precision.getHowSpecified() == OptionalAmount::NotSpecified) 10800b57cec5SDimitry Andric return true; 10810b57cec5SDimitry Andric 10820b57cec5SDimitry Andric // Precision is only valid with the diouxXaAeEfFgGsP conversions 10830b57cec5SDimitry Andric switch (CS.getKind()) { 10840b57cec5SDimitry Andric case ConversionSpecifier::dArg: 10850b57cec5SDimitry Andric case ConversionSpecifier::DArg: 10860b57cec5SDimitry Andric case ConversionSpecifier::iArg: 10870b57cec5SDimitry Andric case ConversionSpecifier::oArg: 10880b57cec5SDimitry Andric case ConversionSpecifier::OArg: 10890b57cec5SDimitry Andric case ConversionSpecifier::uArg: 10900b57cec5SDimitry Andric case ConversionSpecifier::UArg: 10910b57cec5SDimitry Andric case ConversionSpecifier::xArg: 10920b57cec5SDimitry Andric case ConversionSpecifier::XArg: 10930b57cec5SDimitry Andric case ConversionSpecifier::aArg: 10940b57cec5SDimitry Andric case ConversionSpecifier::AArg: 10950b57cec5SDimitry Andric case ConversionSpecifier::eArg: 10960b57cec5SDimitry Andric case ConversionSpecifier::EArg: 10970b57cec5SDimitry Andric case ConversionSpecifier::fArg: 10980b57cec5SDimitry Andric case ConversionSpecifier::FArg: 10990b57cec5SDimitry Andric case ConversionSpecifier::gArg: 11000b57cec5SDimitry Andric case ConversionSpecifier::GArg: 11010b57cec5SDimitry Andric case ConversionSpecifier::sArg: 11020b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDrArg: 11030b57cec5SDimitry Andric case ConversionSpecifier::FreeBSDyArg: 11040b57cec5SDimitry Andric case ConversionSpecifier::PArg: 11050b57cec5SDimitry Andric return true; 11060b57cec5SDimitry Andric 11070b57cec5SDimitry Andric default: 11080b57cec5SDimitry Andric return false; 11090b57cec5SDimitry Andric } 11100b57cec5SDimitry Andric } 11110b57cec5SDimitry Andric bool PrintfSpecifier::hasValidFieldWidth() const { 11120b57cec5SDimitry Andric if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified) 11130b57cec5SDimitry Andric return true; 11140b57cec5SDimitry Andric 11150b57cec5SDimitry Andric // The field width is valid for all conversions except n 11160b57cec5SDimitry Andric switch (CS.getKind()) { 11170b57cec5SDimitry Andric case ConversionSpecifier::nArg: 11180b57cec5SDimitry Andric return false; 11190b57cec5SDimitry Andric 11200b57cec5SDimitry Andric default: 11210b57cec5SDimitry Andric return true; 11220b57cec5SDimitry Andric } 11230b57cec5SDimitry Andric } 1124