Path: blob/main/contrib/llvm-project/clang/lib/AST/FormatString.cpp
35260 views
// FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*-1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Shared details for processing format strings of printf and scanf9// (and friends).10//11//===----------------------------------------------------------------------===//1213#include "FormatStringParsing.h"14#include "clang/Basic/LangOptions.h"15#include "clang/Basic/TargetInfo.h"16#include "llvm/Support/ConvertUTF.h"17#include <optional>1819using clang::analyze_format_string::ArgType;20using clang::analyze_format_string::FormatStringHandler;21using clang::analyze_format_string::FormatSpecifier;22using clang::analyze_format_string::LengthModifier;23using clang::analyze_format_string::OptionalAmount;24using clang::analyze_format_string::ConversionSpecifier;25using namespace clang;2627// Key function to FormatStringHandler.28FormatStringHandler::~FormatStringHandler() {}2930//===----------------------------------------------------------------------===//31// Functions for parsing format strings components in both printf and32// scanf format strings.33//===----------------------------------------------------------------------===//3435OptionalAmount36clang::analyze_format_string::ParseAmount(const char *&Beg, const char *E) {37const char *I = Beg;38UpdateOnReturn <const char*> UpdateBeg(Beg, I);3940unsigned accumulator = 0;41bool hasDigits = false;4243for ( ; I != E; ++I) {44char c = *I;45if (c >= '0' && c <= '9') {46hasDigits = true;47accumulator = (accumulator * 10) + (c - '0');48continue;49}5051if (hasDigits)52return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg,53false);5455break;56}5758return OptionalAmount();59}6061OptionalAmount62clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg,63const char *E,64unsigned &argIndex) {65if (*Beg == '*') {66++Beg;67return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);68}6970return ParseAmount(Beg, E);71}7273OptionalAmount74clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H,75const char *Start,76const char *&Beg,77const char *E,78PositionContext p) {79if (*Beg == '*') {80const char *I = Beg + 1;81const OptionalAmount &Amt = ParseAmount(I, E);8283if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {84H.HandleInvalidPosition(Beg, I - Beg, p);85return OptionalAmount(false);86}8788if (I == E) {89// No more characters left?90H.HandleIncompleteSpecifier(Start, E - Start);91return OptionalAmount(false);92}9394assert(Amt.getHowSpecified() == OptionalAmount::Constant);9596if (*I == '$') {97// Handle positional arguments9899// Special case: '*0$', since this is an easy mistake.100if (Amt.getConstantAmount() == 0) {101H.HandleZeroPosition(Beg, I - Beg + 1);102return OptionalAmount(false);103}104105const char *Tmp = Beg;106Beg = ++I;107108return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,109Tmp, 0, true);110}111112H.HandleInvalidPosition(Beg, I - Beg, p);113return OptionalAmount(false);114}115116return ParseAmount(Beg, E);117}118119120bool121clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H,122FormatSpecifier &CS,123const char *Start,124const char *&Beg, const char *E,125unsigned *argIndex) {126// FIXME: Support negative field widths.127if (argIndex) {128CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));129}130else {131const OptionalAmount Amt =132ParsePositionAmount(H, Start, Beg, E,133analyze_format_string::FieldWidthPos);134135if (Amt.isInvalid())136return true;137CS.setFieldWidth(Amt);138}139return false;140}141142bool143clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,144FormatSpecifier &FS,145const char *Start,146const char *&Beg,147const char *E) {148const char *I = Beg;149150const OptionalAmount &Amt = ParseAmount(I, E);151152if (I == E) {153// No more characters left?154H.HandleIncompleteSpecifier(Start, E - Start);155return true;156}157158if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {159// Warn that positional arguments are non-standard.160H.HandlePosition(Start, I - Start);161162// Special case: '%0$', since this is an easy mistake.163if (Amt.getConstantAmount() == 0) {164H.HandleZeroPosition(Start, I - Start);165return true;166}167168FS.setArgIndex(Amt.getConstantAmount() - 1);169FS.setUsesPositionalArg();170// Update the caller's pointer if we decided to consume171// these characters.172Beg = I;173return false;174}175176return false;177}178179bool180clang::analyze_format_string::ParseVectorModifier(FormatStringHandler &H,181FormatSpecifier &FS,182const char *&I,183const char *E,184const LangOptions &LO) {185if (!LO.OpenCL)186return false;187188const char *Start = I;189if (*I == 'v') {190++I;191192if (I == E) {193H.HandleIncompleteSpecifier(Start, E - Start);194return true;195}196197OptionalAmount NumElts = ParseAmount(I, E);198if (NumElts.getHowSpecified() != OptionalAmount::Constant) {199H.HandleIncompleteSpecifier(Start, E - Start);200return true;201}202203FS.setVectorNumElts(NumElts);204}205206return false;207}208209bool210clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,211const char *&I,212const char *E,213const LangOptions &LO,214bool IsScanf) {215LengthModifier::Kind lmKind = LengthModifier::None;216const char *lmPosition = I;217switch (*I) {218default:219return false;220case 'h':221++I;222if (I != E && *I == 'h') {223++I;224lmKind = LengthModifier::AsChar;225} else if (I != E && *I == 'l' && LO.OpenCL) {226++I;227lmKind = LengthModifier::AsShortLong;228} else {229lmKind = LengthModifier::AsShort;230}231break;232case 'l':233++I;234if (I != E && *I == 'l') {235++I;236lmKind = LengthModifier::AsLongLong;237} else {238lmKind = LengthModifier::AsLong;239}240break;241case 'j': lmKind = LengthModifier::AsIntMax; ++I; break;242case 'z': lmKind = LengthModifier::AsSizeT; ++I; break;243case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break;244case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;245case 'q': lmKind = LengthModifier::AsQuad; ++I; break;246case 'a':247if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {248// For scanf in C90, look at the next character to see if this should249// be parsed as the GNU extension 'a' length modifier. If not, this250// will be parsed as a conversion specifier.251++I;252if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {253lmKind = LengthModifier::AsAllocate;254break;255}256--I;257}258return false;259case 'm':260if (IsScanf) {261lmKind = LengthModifier::AsMAllocate;262++I;263break;264}265return false;266// printf: AsInt64, AsInt32, AsInt3264267// scanf: AsInt64268case 'I':269if (I + 1 != E && I + 2 != E) {270if (I[1] == '6' && I[2] == '4') {271I += 3;272lmKind = LengthModifier::AsInt64;273break;274}275if (IsScanf)276return false;277278if (I[1] == '3' && I[2] == '2') {279I += 3;280lmKind = LengthModifier::AsInt32;281break;282}283}284++I;285lmKind = LengthModifier::AsInt3264;286break;287case 'w':288lmKind = LengthModifier::AsWide; ++I; break;289}290LengthModifier lm(lmPosition, lmKind);291FS.setLengthModifier(lm);292return true;293}294295bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(296const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len) {297if (SpecifierBegin + 1 >= FmtStrEnd)298return false;299300const llvm::UTF8 *SB =301reinterpret_cast<const llvm::UTF8 *>(SpecifierBegin + 1);302const llvm::UTF8 *SE = reinterpret_cast<const llvm::UTF8 *>(FmtStrEnd);303const char FirstByte = *SB;304305// If the invalid specifier is a multibyte UTF-8 string, return the306// total length accordingly so that the conversion specifier can be307// properly updated to reflect a complete UTF-8 specifier.308unsigned NumBytes = llvm::getNumBytesForUTF8(FirstByte);309if (NumBytes == 1)310return false;311if (SB + NumBytes > SE)312return false;313314Len = NumBytes + 1;315return true;316}317318//===----------------------------------------------------------------------===//319// Methods on ArgType.320//===----------------------------------------------------------------------===//321322clang::analyze_format_string::ArgType::MatchKind323ArgType::matchesType(ASTContext &C, QualType argTy) const {324// When using the format attribute in C++, you can receive a function or an325// array that will necessarily decay to a pointer when passed to the final326// format consumer. Apply decay before type comparison.327if (argTy->canDecayToPointerType())328argTy = C.getDecayedType(argTy);329330if (Ptr) {331// It has to be a pointer.332const PointerType *PT = argTy->getAs<PointerType>();333if (!PT)334return NoMatch;335336// We cannot write through a const qualified pointer.337if (PT->getPointeeType().isConstQualified())338return NoMatch;339340argTy = PT->getPointeeType();341}342343switch (K) {344case InvalidTy:345llvm_unreachable("ArgType must be valid");346347case UnknownTy:348return Match;349350case AnyCharTy: {351if (const auto *ETy = argTy->getAs<EnumType>()) {352// If the enum is incomplete we know nothing about the underlying type.353// Assume that it's 'int'. Do not use the underlying type for a scoped354// enumeration.355if (!ETy->getDecl()->isComplete())356return NoMatch;357if (ETy->isUnscopedEnumerationType())358argTy = ETy->getDecl()->getIntegerType();359}360361if (const auto *BT = argTy->getAs<BuiltinType>()) {362// The types are perfectly matched?363switch (BT->getKind()) {364default:365break;366case BuiltinType::Char_S:367case BuiltinType::SChar:368case BuiltinType::UChar:369case BuiltinType::Char_U:370return Match;371case BuiltinType::Bool:372if (!Ptr)373return Match;374break;375}376// "Partially matched" because of promotions?377if (!Ptr) {378switch (BT->getKind()) {379default:380break;381case BuiltinType::Int:382case BuiltinType::UInt:383return MatchPromotion;384case BuiltinType::Short:385case BuiltinType::UShort:386case BuiltinType::WChar_S:387case BuiltinType::WChar_U:388return NoMatchPromotionTypeConfusion;389}390}391}392return NoMatch;393}394395case SpecificTy: {396if (const EnumType *ETy = argTy->getAs<EnumType>()) {397// If the enum is incomplete we know nothing about the underlying type.398// Assume that it's 'int'. Do not use the underlying type for a scoped399// enumeration as that needs an exact match.400if (!ETy->getDecl()->isComplete())401argTy = C.IntTy;402else if (ETy->isUnscopedEnumerationType())403argTy = ETy->getDecl()->getIntegerType();404}405406if (argTy->isSaturatedFixedPointType())407argTy = C.getCorrespondingUnsaturatedType(argTy);408409argTy = C.getCanonicalType(argTy).getUnqualifiedType();410411if (T == argTy)412return Match;413if (const auto *BT = argTy->getAs<BuiltinType>()) {414// Check if the only difference between them is signed vs unsigned415// if true, return match signedness.416switch (BT->getKind()) {417default:418break;419case BuiltinType::Bool:420if (Ptr && (T == C.UnsignedCharTy || T == C.SignedCharTy))421return NoMatch;422[[fallthrough]];423case BuiltinType::Char_S:424case BuiltinType::SChar:425if (T == C.UnsignedShortTy || T == C.ShortTy)426return NoMatchTypeConfusion;427if (T == C.UnsignedCharTy)428return NoMatchSignedness;429if (T == C.SignedCharTy)430return Match;431break;432case BuiltinType::Char_U:433case BuiltinType::UChar:434if (T == C.UnsignedShortTy || T == C.ShortTy)435return NoMatchTypeConfusion;436if (T == C.UnsignedCharTy)437return Match;438if (T == C.SignedCharTy)439return NoMatchSignedness;440break;441case BuiltinType::Short:442if (T == C.UnsignedShortTy)443return NoMatchSignedness;444break;445case BuiltinType::UShort:446if (T == C.ShortTy)447return NoMatchSignedness;448break;449case BuiltinType::Int:450if (T == C.UnsignedIntTy)451return NoMatchSignedness;452break;453case BuiltinType::UInt:454if (T == C.IntTy)455return NoMatchSignedness;456break;457case BuiltinType::Long:458if (T == C.UnsignedLongTy)459return NoMatchSignedness;460break;461case BuiltinType::ULong:462if (T == C.LongTy)463return NoMatchSignedness;464break;465case BuiltinType::LongLong:466if (T == C.UnsignedLongLongTy)467return NoMatchSignedness;468break;469case BuiltinType::ULongLong:470if (T == C.LongLongTy)471return NoMatchSignedness;472break;473}474// "Partially matched" because of promotions?475if (!Ptr) {476switch (BT->getKind()) {477default:478break;479case BuiltinType::Bool:480if (T == C.IntTy || T == C.UnsignedIntTy)481return MatchPromotion;482break;483case BuiltinType::Int:484case BuiltinType::UInt:485if (T == C.SignedCharTy || T == C.UnsignedCharTy ||486T == C.ShortTy || T == C.UnsignedShortTy || T == C.WCharTy ||487T == C.WideCharTy)488return MatchPromotion;489break;490case BuiltinType::Char_U:491if (T == C.UnsignedIntTy)492return MatchPromotion;493if (T == C.UnsignedShortTy)494return NoMatchPromotionTypeConfusion;495break;496case BuiltinType::Char_S:497if (T == C.IntTy)498return MatchPromotion;499if (T == C.ShortTy)500return NoMatchPromotionTypeConfusion;501break;502case BuiltinType::Half:503case BuiltinType::Float:504if (T == C.DoubleTy)505return MatchPromotion;506break;507case BuiltinType::Short:508case BuiltinType::UShort:509if (T == C.SignedCharTy || T == C.UnsignedCharTy)510return NoMatchPromotionTypeConfusion;511break;512case BuiltinType::WChar_U:513case BuiltinType::WChar_S:514if (T != C.WCharTy && T != C.WideCharTy)515return NoMatchPromotionTypeConfusion;516}517}518}519return NoMatch;520}521522case CStrTy: {523const PointerType *PT = argTy->getAs<PointerType>();524if (!PT)525return NoMatch;526QualType pointeeTy = PT->getPointeeType();527if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())528switch (BT->getKind()) {529case BuiltinType::Char_U:530case BuiltinType::UChar:531case BuiltinType::Char_S:532case BuiltinType::SChar:533return Match;534default:535break;536}537538return NoMatch;539}540541case WCStrTy: {542const PointerType *PT = argTy->getAs<PointerType>();543if (!PT)544return NoMatch;545QualType pointeeTy =546C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();547return pointeeTy == C.getWideCharType() ? Match : NoMatch;548}549550case WIntTy: {551QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType();552553if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)554return Match;555556QualType PromoArg = C.isPromotableIntegerType(argTy)557? C.getPromotedIntegerType(argTy)558: argTy;559PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();560561// If the promoted argument is the corresponding signed type of the562// wint_t type, then it should match.563if (PromoArg->hasSignedIntegerRepresentation() &&564C.getCorrespondingUnsignedType(PromoArg) == WInt)565return Match;566567return WInt == PromoArg ? Match : NoMatch;568}569570case CPointerTy:571if (argTy->isVoidPointerType()) {572return Match;573} if (argTy->isPointerType() || argTy->isObjCObjectPointerType() ||574argTy->isBlockPointerType() || argTy->isNullPtrType()) {575return NoMatchPedantic;576} else {577return NoMatch;578}579580case ObjCPointerTy: {581if (argTy->getAs<ObjCObjectPointerType>() ||582argTy->getAs<BlockPointerType>())583return Match;584585// Handle implicit toll-free bridging.586if (const PointerType *PT = argTy->getAs<PointerType>()) {587// Things such as CFTypeRef are really just opaque pointers588// to C structs representing CF types that can often be bridged589// to Objective-C objects. Since the compiler doesn't know which590// structs can be toll-free bridged, we just accept them all.591QualType pointee = PT->getPointeeType();592if (pointee->getAsStructureType() || pointee->isVoidType())593return Match;594}595return NoMatch;596}597}598599llvm_unreachable("Invalid ArgType Kind!");600}601602ArgType ArgType::makeVectorType(ASTContext &C, unsigned NumElts) const {603// Check for valid vector element types.604if (T.isNull())605return ArgType::Invalid();606607QualType Vec = C.getExtVectorType(T, NumElts);608return ArgType(Vec, Name);609}610611QualType ArgType::getRepresentativeType(ASTContext &C) const {612QualType Res;613switch (K) {614case InvalidTy:615llvm_unreachable("No representative type for Invalid ArgType");616case UnknownTy:617llvm_unreachable("No representative type for Unknown ArgType");618case AnyCharTy:619Res = C.CharTy;620break;621case SpecificTy:622Res = T;623break;624case CStrTy:625Res = C.getPointerType(C.CharTy);626break;627case WCStrTy:628Res = C.getPointerType(C.getWideCharType());629break;630case ObjCPointerTy:631Res = C.ObjCBuiltinIdTy;632break;633case CPointerTy:634Res = C.VoidPtrTy;635break;636case WIntTy: {637Res = C.getWIntType();638break;639}640}641642if (Ptr)643Res = C.getPointerType(Res);644return Res;645}646647std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {648std::string S = getRepresentativeType(C).getAsString(C.getPrintingPolicy());649650std::string Alias;651if (Name) {652// Use a specific name for this type, e.g. "size_t".653Alias = Name;654if (Ptr) {655// If ArgType is actually a pointer to T, append an asterisk.656Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *";657}658// If Alias is the same as the underlying type, e.g. wchar_t, then drop it.659if (S == Alias)660Alias.clear();661}662663if (!Alias.empty())664return std::string("'") + Alias + "' (aka '" + S + "')";665return std::string("'") + S + "'";666}667668669//===----------------------------------------------------------------------===//670// Methods on OptionalAmount.671//===----------------------------------------------------------------------===//672673ArgType674analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {675return Ctx.IntTy;676}677678//===----------------------------------------------------------------------===//679// Methods on LengthModifier.680//===----------------------------------------------------------------------===//681682const char *683analyze_format_string::LengthModifier::toString() const {684switch (kind) {685case AsChar:686return "hh";687case AsShort:688return "h";689case AsShortLong:690return "hl";691case AsLong: // or AsWideChar692return "l";693case AsLongLong:694return "ll";695case AsQuad:696return "q";697case AsIntMax:698return "j";699case AsSizeT:700return "z";701case AsPtrDiff:702return "t";703case AsInt32:704return "I32";705case AsInt3264:706return "I";707case AsInt64:708return "I64";709case AsLongDouble:710return "L";711case AsAllocate:712return "a";713case AsMAllocate:714return "m";715case AsWide:716return "w";717case None:718return "";719}720return nullptr;721}722723//===----------------------------------------------------------------------===//724// Methods on ConversionSpecifier.725//===----------------------------------------------------------------------===//726727const char *ConversionSpecifier::toString() const {728switch (kind) {729case bArg: return "b";730case BArg: return "B";731case dArg: return "d";732case DArg: return "D";733case iArg: return "i";734case oArg: return "o";735case OArg: return "O";736case uArg: return "u";737case UArg: return "U";738case xArg: return "x";739case XArg: return "X";740case fArg: return "f";741case FArg: return "F";742case eArg: return "e";743case EArg: return "E";744case gArg: return "g";745case GArg: return "G";746case aArg: return "a";747case AArg: return "A";748case cArg: return "c";749case sArg: return "s";750case pArg: return "p";751case PArg:752return "P";753case nArg: return "n";754case PercentArg: return "%";755case ScanListArg: return "[";756case InvalidSpecifier: return nullptr;757758// POSIX unicode extensions.759case CArg: return "C";760case SArg: return "S";761762// Objective-C specific specifiers.763case ObjCObjArg: return "@";764765// FreeBSD kernel specific specifiers.766case FreeBSDbArg: return "b";767case FreeBSDDArg: return "D";768case FreeBSDrArg: return "r";769case FreeBSDyArg: return "y";770771// GlibC specific specifiers.772case PrintErrno: return "m";773774// MS specific specifiers.775case ZArg: return "Z";776777// ISO/IEC TR 18037 (fixed-point) specific specifiers.778case rArg:779return "r";780case RArg:781return "R";782case kArg:783return "k";784case KArg:785return "K";786}787return nullptr;788}789790std::optional<ConversionSpecifier>791ConversionSpecifier::getStandardSpecifier() const {792ConversionSpecifier::Kind NewKind;793794switch (getKind()) {795default:796return std::nullopt;797case DArg:798NewKind = dArg;799break;800case UArg:801NewKind = uArg;802break;803case OArg:804NewKind = oArg;805break;806}807808ConversionSpecifier FixedCS(*this);809FixedCS.setKind(NewKind);810return FixedCS;811}812813//===----------------------------------------------------------------------===//814// Methods on OptionalAmount.815//===----------------------------------------------------------------------===//816817void OptionalAmount::toString(raw_ostream &os) const {818switch (hs) {819case Invalid:820case NotSpecified:821return;822case Arg:823if (UsesDotPrefix)824os << ".";825if (usesPositionalArg())826os << "*" << getPositionalArgIndex() << "$";827else828os << "*";829break;830case Constant:831if (UsesDotPrefix)832os << ".";833os << amt;834break;835}836}837838bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,839const LangOptions &LO) const {840switch (LM.getKind()) {841case LengthModifier::None:842return true;843844// Handle most integer flags845case LengthModifier::AsShort:846// Length modifier only applies to FP vectors.847if (LO.OpenCL && CS.isDoubleArg())848return !VectorNumElts.isInvalid();849850if (CS.isFixedPointArg())851return true;852853if (Target.getTriple().isOSMSVCRT()) {854switch (CS.getKind()) {855case ConversionSpecifier::cArg:856case ConversionSpecifier::CArg:857case ConversionSpecifier::sArg:858case ConversionSpecifier::SArg:859case ConversionSpecifier::ZArg:860return true;861default:862break;863}864}865[[fallthrough]];866case LengthModifier::AsChar:867case LengthModifier::AsLongLong:868case LengthModifier::AsQuad:869case LengthModifier::AsIntMax:870case LengthModifier::AsSizeT:871case LengthModifier::AsPtrDiff:872switch (CS.getKind()) {873case ConversionSpecifier::bArg:874case ConversionSpecifier::BArg:875case ConversionSpecifier::dArg:876case ConversionSpecifier::DArg:877case ConversionSpecifier::iArg:878case ConversionSpecifier::oArg:879case ConversionSpecifier::OArg:880case ConversionSpecifier::uArg:881case ConversionSpecifier::UArg:882case ConversionSpecifier::xArg:883case ConversionSpecifier::XArg:884case ConversionSpecifier::nArg:885return true;886case ConversionSpecifier::FreeBSDrArg:887case ConversionSpecifier::FreeBSDyArg:888return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS();889default:890return false;891}892893case LengthModifier::AsShortLong:894return LO.OpenCL && !VectorNumElts.isInvalid();895896// Handle 'l' flag897case LengthModifier::AsLong: // or AsWideChar898if (CS.isDoubleArg()) {899// Invalid for OpenCL FP scalars.900if (LO.OpenCL && VectorNumElts.isInvalid())901return false;902return true;903}904905if (CS.isFixedPointArg())906return true;907908switch (CS.getKind()) {909case ConversionSpecifier::bArg:910case ConversionSpecifier::BArg:911case ConversionSpecifier::dArg:912case ConversionSpecifier::DArg:913case ConversionSpecifier::iArg:914case ConversionSpecifier::oArg:915case ConversionSpecifier::OArg:916case ConversionSpecifier::uArg:917case ConversionSpecifier::UArg:918case ConversionSpecifier::xArg:919case ConversionSpecifier::XArg:920case ConversionSpecifier::nArg:921case ConversionSpecifier::cArg:922case ConversionSpecifier::sArg:923case ConversionSpecifier::ScanListArg:924case ConversionSpecifier::ZArg:925return true;926case ConversionSpecifier::FreeBSDrArg:927case ConversionSpecifier::FreeBSDyArg:928return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS();929default:930return false;931}932933case LengthModifier::AsLongDouble:934switch (CS.getKind()) {935case ConversionSpecifier::aArg:936case ConversionSpecifier::AArg:937case ConversionSpecifier::fArg:938case ConversionSpecifier::FArg:939case ConversionSpecifier::eArg:940case ConversionSpecifier::EArg:941case ConversionSpecifier::gArg:942case ConversionSpecifier::GArg:943return true;944// GNU libc extension.945case ConversionSpecifier::dArg:946case ConversionSpecifier::iArg:947case ConversionSpecifier::oArg:948case ConversionSpecifier::uArg:949case ConversionSpecifier::xArg:950case ConversionSpecifier::XArg:951return !Target.getTriple().isOSDarwin() &&952!Target.getTriple().isOSWindows();953default:954return false;955}956957case LengthModifier::AsAllocate:958switch (CS.getKind()) {959case ConversionSpecifier::sArg:960case ConversionSpecifier::SArg:961case ConversionSpecifier::ScanListArg:962return true;963default:964return false;965}966967case LengthModifier::AsMAllocate:968switch (CS.getKind()) {969case ConversionSpecifier::cArg:970case ConversionSpecifier::CArg:971case ConversionSpecifier::sArg:972case ConversionSpecifier::SArg:973case ConversionSpecifier::ScanListArg:974return true;975default:976return false;977}978case LengthModifier::AsInt32:979case LengthModifier::AsInt3264:980case LengthModifier::AsInt64:981switch (CS.getKind()) {982case ConversionSpecifier::dArg:983case ConversionSpecifier::iArg:984case ConversionSpecifier::oArg:985case ConversionSpecifier::uArg:986case ConversionSpecifier::xArg:987case ConversionSpecifier::XArg:988return Target.getTriple().isOSMSVCRT();989default:990return false;991}992case LengthModifier::AsWide:993switch (CS.getKind()) {994case ConversionSpecifier::cArg:995case ConversionSpecifier::CArg:996case ConversionSpecifier::sArg:997case ConversionSpecifier::SArg:998case ConversionSpecifier::ZArg:999return Target.getTriple().isOSMSVCRT();1000default:1001return false;1002}1003}1004llvm_unreachable("Invalid LengthModifier Kind!");1005}10061007bool FormatSpecifier::hasStandardLengthModifier() const {1008switch (LM.getKind()) {1009case LengthModifier::None:1010case LengthModifier::AsChar:1011case LengthModifier::AsShort:1012case LengthModifier::AsLong:1013case LengthModifier::AsLongLong:1014case LengthModifier::AsIntMax:1015case LengthModifier::AsSizeT:1016case LengthModifier::AsPtrDiff:1017case LengthModifier::AsLongDouble:1018return true;1019case LengthModifier::AsAllocate:1020case LengthModifier::AsMAllocate:1021case LengthModifier::AsQuad:1022case LengthModifier::AsInt32:1023case LengthModifier::AsInt3264:1024case LengthModifier::AsInt64:1025case LengthModifier::AsWide:1026case LengthModifier::AsShortLong: // ???1027return false;1028}1029llvm_unreachable("Invalid LengthModifier Kind!");1030}10311032bool FormatSpecifier::hasStandardConversionSpecifier(1033const LangOptions &LangOpt) const {1034switch (CS.getKind()) {1035case ConversionSpecifier::bArg:1036case ConversionSpecifier::BArg:1037case ConversionSpecifier::cArg:1038case ConversionSpecifier::dArg:1039case ConversionSpecifier::iArg:1040case ConversionSpecifier::oArg:1041case ConversionSpecifier::uArg:1042case ConversionSpecifier::xArg:1043case ConversionSpecifier::XArg:1044case ConversionSpecifier::fArg:1045case ConversionSpecifier::FArg:1046case ConversionSpecifier::eArg:1047case ConversionSpecifier::EArg:1048case ConversionSpecifier::gArg:1049case ConversionSpecifier::GArg:1050case ConversionSpecifier::aArg:1051case ConversionSpecifier::AArg:1052case ConversionSpecifier::sArg:1053case ConversionSpecifier::pArg:1054case ConversionSpecifier::nArg:1055case ConversionSpecifier::ObjCObjArg:1056case ConversionSpecifier::ScanListArg:1057case ConversionSpecifier::PercentArg:1058case ConversionSpecifier::PArg:1059return true;1060case ConversionSpecifier::CArg:1061case ConversionSpecifier::SArg:1062return LangOpt.ObjC;1063case ConversionSpecifier::InvalidSpecifier:1064case ConversionSpecifier::FreeBSDbArg:1065case ConversionSpecifier::FreeBSDDArg:1066case ConversionSpecifier::FreeBSDrArg:1067case ConversionSpecifier::FreeBSDyArg:1068case ConversionSpecifier::PrintErrno:1069case ConversionSpecifier::DArg:1070case ConversionSpecifier::OArg:1071case ConversionSpecifier::UArg:1072case ConversionSpecifier::ZArg:1073return false;1074case ConversionSpecifier::rArg:1075case ConversionSpecifier::RArg:1076case ConversionSpecifier::kArg:1077case ConversionSpecifier::KArg:1078return LangOpt.FixedPoint;1079}1080llvm_unreachable("Invalid ConversionSpecifier Kind!");1081}10821083bool FormatSpecifier::hasStandardLengthConversionCombination() const {1084if (LM.getKind() == LengthModifier::AsLongDouble) {1085switch(CS.getKind()) {1086case ConversionSpecifier::dArg:1087case ConversionSpecifier::iArg:1088case ConversionSpecifier::oArg:1089case ConversionSpecifier::uArg:1090case ConversionSpecifier::xArg:1091case ConversionSpecifier::XArg:1092return false;1093default:1094return true;1095}1096}1097return true;1098}10991100std::optional<LengthModifier>1101FormatSpecifier::getCorrectedLengthModifier() const {1102if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {1103if (LM.getKind() == LengthModifier::AsLongDouble ||1104LM.getKind() == LengthModifier::AsQuad) {1105LengthModifier FixedLM(LM);1106FixedLM.setKind(LengthModifier::AsLongLong);1107return FixedLM;1108}1109}11101111return std::nullopt;1112}11131114bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,1115LengthModifier &LM) {1116for (/**/; const auto *TT = QT->getAs<TypedefType>();1117QT = TT->getDecl()->getUnderlyingType()) {1118const TypedefNameDecl *Typedef = TT->getDecl();1119const IdentifierInfo *Identifier = Typedef->getIdentifier();1120if (Identifier->getName() == "size_t") {1121LM.setKind(LengthModifier::AsSizeT);1122return true;1123} else if (Identifier->getName() == "ssize_t") {1124// Not C99, but common in Unix.1125LM.setKind(LengthModifier::AsSizeT);1126return true;1127} else if (Identifier->getName() == "intmax_t") {1128LM.setKind(LengthModifier::AsIntMax);1129return true;1130} else if (Identifier->getName() == "uintmax_t") {1131LM.setKind(LengthModifier::AsIntMax);1132return true;1133} else if (Identifier->getName() == "ptrdiff_t") {1134LM.setKind(LengthModifier::AsPtrDiff);1135return true;1136}1137}1138return false;1139}114011411142