brintos

brintos / llvm-project-archived public Read only

0
0
Text · 38.7 KiB · d4cb89b Raw
1287 lines · cpp
1// FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*-2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Shared details for processing format strings of printf and scanf10// (and friends).11//12//===----------------------------------------------------------------------===//13 14#include "FormatStringParsing.h"15#include "clang/Basic/LangOptions.h"16#include "clang/Basic/TargetInfo.h"17#include "llvm/Support/ConvertUTF.h"18#include <optional>19 20using clang::analyze_format_string::ArgType;21using clang::analyze_format_string::FormatStringHandler;22using clang::analyze_format_string::FormatSpecifier;23using clang::analyze_format_string::LengthModifier;24using clang::analyze_format_string::OptionalAmount;25using clang::analyze_format_string::ConversionSpecifier;26using namespace clang;27 28// Key function to FormatStringHandler.29FormatStringHandler::~FormatStringHandler() {}30 31//===----------------------------------------------------------------------===//32// Functions for parsing format strings components in both printf and33// scanf format strings.34//===----------------------------------------------------------------------===//35 36OptionalAmount37clang::analyze_format_string::ParseAmount(const char *&Beg, const char *E) {38  const char *I = Beg;39  UpdateOnReturn <const char*> UpdateBeg(Beg, I);40 41  unsigned accumulator = 0;42  bool hasDigits = false;43 44  for ( ; I != E; ++I) {45    char c = *I;46    if (c >= '0' && c <= '9') {47      hasDigits = true;48      accumulator = (accumulator * 10) + (c - '0');49      continue;50    }51 52    if (hasDigits)53      return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg,54          false);55 56    break;57  }58 59  return OptionalAmount();60}61 62OptionalAmount63clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg,64                                                     const char *E,65                                                     unsigned &argIndex) {66  if (*Beg == '*') {67    ++Beg;68    return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);69  }70 71  return ParseAmount(Beg, E);72}73 74OptionalAmount75clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H,76                                                  const char *Start,77                                                  const char *&Beg,78                                                  const char *E,79                                                  PositionContext p) {80  if (*Beg == '*') {81    const char *I = Beg + 1;82    const OptionalAmount &Amt = ParseAmount(I, E);83 84    if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {85      H.HandleInvalidPosition(Beg, I - Beg, p);86      return OptionalAmount(false);87    }88 89    if (I == E) {90      // No more characters left?91      H.HandleIncompleteSpecifier(Start, E - Start);92      return OptionalAmount(false);93    }94 95    assert(Amt.getHowSpecified() == OptionalAmount::Constant);96 97    if (*I == '$') {98      // Handle positional arguments99 100      // Special case: '*0$', since this is an easy mistake.101      if (Amt.getConstantAmount() == 0) {102        H.HandleZeroPosition(Beg, I - Beg + 1);103        return OptionalAmount(false);104      }105 106      const char *Tmp = Beg;107      Beg = ++I;108 109      return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,110                            Tmp, 0, true);111    }112 113    H.HandleInvalidPosition(Beg, I - Beg, p);114    return OptionalAmount(false);115  }116 117  return ParseAmount(Beg, E);118}119 120 121bool122clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H,123                                              FormatSpecifier &CS,124                                              const char *Start,125                                              const char *&Beg, const char *E,126                                              unsigned *argIndex) {127  // FIXME: Support negative field widths.128  if (argIndex) {129    CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));130  }131  else {132    const OptionalAmount Amt =133      ParsePositionAmount(H, Start, Beg, E,134                          analyze_format_string::FieldWidthPos);135 136    if (Amt.isInvalid())137      return true;138    CS.setFieldWidth(Amt);139  }140  return false;141}142 143bool144clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,145                                               FormatSpecifier &FS,146                                               const char *Start,147                                               const char *&Beg,148                                               const char *E) {149  const char *I = Beg;150 151  const OptionalAmount &Amt = ParseAmount(I, E);152 153  if (I == E) {154    // No more characters left?155    H.HandleIncompleteSpecifier(Start, E - Start);156    return true;157  }158 159  if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {160    // Warn that positional arguments are non-standard.161    H.HandlePosition(Start, I - Start);162 163    // Special case: '%0$', since this is an easy mistake.164    if (Amt.getConstantAmount() == 0) {165      H.HandleZeroPosition(Start, I - Start);166      return true;167    }168 169    FS.setArgIndex(Amt.getConstantAmount() - 1);170    FS.setUsesPositionalArg();171    // Update the caller's pointer if we decided to consume172    // these characters.173    Beg = I;174    return false;175  }176 177  return false;178}179 180bool181clang::analyze_format_string::ParseVectorModifier(FormatStringHandler &H,182                                                  FormatSpecifier &FS,183                                                  const char *&I,184                                                  const char *E,185                                                  const LangOptions &LO) {186  if (!LO.OpenCL)187    return false;188 189  const char *Start = I;190  if (*I == 'v') {191    ++I;192 193    if (I == E) {194      H.HandleIncompleteSpecifier(Start, E - Start);195      return true;196    }197 198    OptionalAmount NumElts = ParseAmount(I, E);199    if (NumElts.getHowSpecified() != OptionalAmount::Constant) {200      H.HandleIncompleteSpecifier(Start, E - Start);201      return true;202    }203 204    FS.setVectorNumElts(NumElts);205  }206 207  return false;208}209 210bool211clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,212                                                  const char *&I,213                                                  const char *E,214                                                  const LangOptions &LO,215                                                  bool IsScanf) {216  LengthModifier::Kind lmKind = LengthModifier::None;217  const char *lmPosition = I;218  switch (*I) {219    default:220      return false;221    case 'h':222      ++I;223      if (I != E && *I == 'h') {224        ++I;225        lmKind = LengthModifier::AsChar;226      } else if (I != E && *I == 'l' && LO.OpenCL) {227        ++I;228        lmKind = LengthModifier::AsShortLong;229      } else {230        lmKind = LengthModifier::AsShort;231      }232      break;233    case 'l':234      ++I;235      if (I != E && *I == 'l') {236        ++I;237        lmKind = LengthModifier::AsLongLong;238      } else {239        lmKind = LengthModifier::AsLong;240      }241      break;242    case 'j': lmKind = LengthModifier::AsIntMax;     ++I; break;243    case 'z': lmKind = LengthModifier::AsSizeT;      ++I; break;244    case 't': lmKind = LengthModifier::AsPtrDiff;    ++I; break;245    case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;246    case 'q': lmKind = LengthModifier::AsQuad;       ++I; break;247    case 'a':248      if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {249        // For scanf in C90, look at the next character to see if this should250        // be parsed as the GNU extension 'a' length modifier. If not, this251        // will be parsed as a conversion specifier.252        ++I;253        if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {254          lmKind = LengthModifier::AsAllocate;255          break;256        }257        --I;258      }259      return false;260    case 'm':261      if (IsScanf) {262        lmKind = LengthModifier::AsMAllocate;263        ++I;264        break;265      }266      return false;267    // printf: AsInt64, AsInt32, AsInt3264268    // scanf:  AsInt64269    case 'I':270      if (I + 1 != E && I + 2 != E) {271        if (I[1] == '6' && I[2] == '4') {272          I += 3;273          lmKind = LengthModifier::AsInt64;274          break;275        }276        if (IsScanf)277          return false;278 279        if (I[1] == '3' && I[2] == '2') {280          I += 3;281          lmKind = LengthModifier::AsInt32;282          break;283        }284      }285      ++I;286      lmKind = LengthModifier::AsInt3264;287      break;288    case 'w':289      lmKind = LengthModifier::AsWide; ++I; break;290  }291  LengthModifier lm(lmPosition, lmKind);292  FS.setLengthModifier(lm);293  return true;294}295 296bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(297    const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len) {298  if (SpecifierBegin + 1 >= FmtStrEnd)299    return false;300 301  const llvm::UTF8 *SB =302      reinterpret_cast<const llvm::UTF8 *>(SpecifierBegin + 1);303  const llvm::UTF8 *SE = reinterpret_cast<const llvm::UTF8 *>(FmtStrEnd);304  const char FirstByte = *SB;305 306  // If the invalid specifier is a multibyte UTF-8 string, return the307  // total length accordingly so that the conversion specifier can be308  // properly updated to reflect a complete UTF-8 specifier.309  unsigned NumBytes = llvm::getNumBytesForUTF8(FirstByte);310  if (NumBytes == 1)311    return false;312  if (SB + NumBytes > SE)313    return false;314 315  Len = NumBytes + 1;316  return true;317}318 319//===----------------------------------------------------------------------===//320// Methods on ArgType.321//===----------------------------------------------------------------------===//322 323static bool namedTypeToLengthModifierKind(ASTContext &Ctx, QualType QT,324                                          LengthModifier::Kind &K) {325  if (!Ctx.getLangOpts().C99 && !Ctx.getLangOpts().CPlusPlus)326    return false;327  for (/**/; const auto *TT = QT->getAs<TypedefType>(); QT = TT->desugar()) {328    const auto *TD = TT->getDecl();329    const auto *DC = TT->getDecl()->getDeclContext();330    if (DC->isTranslationUnit() || DC->isStdNamespace()) {331      StringRef Name = TD->getIdentifier()->getName();332      if (Name == "size_t") {333        K = LengthModifier::AsSizeT;334        return true;335      } else if (Name == "ssize_t" /*Not C99, but common in Unix.*/) {336        K = LengthModifier::AsSizeT;337        return true;338      } else if (Name == "ptrdiff_t") {339        K = LengthModifier::AsPtrDiff;340        return true;341      } else if (Name == "intmax_t") {342        K = LengthModifier::AsIntMax;343        return true;344      } else if (Name == "uintmax_t") {345        K = LengthModifier::AsIntMax;346        return true;347      }348    }349  }350  if (const auto *PST = QT->getAs<PredefinedSugarType>()) {351    using Kind = PredefinedSugarType::Kind;352    switch (PST->getKind()) {353    case Kind::SizeT:354    case Kind::SignedSizeT:355      K = LengthModifier::AsSizeT;356      return true;357    case Kind::PtrdiffT:358      K = LengthModifier::AsPtrDiff;359      return true;360    }361    llvm_unreachable("unexpected kind");362  }363  return false;364}365 366// Check whether T and E are compatible size_t/ptrdiff_t types. E must be367// consistent with LE.368// T is the type of the actual expression in the code to be checked, and E is369// the expected type parsed from the format string.370static clang::analyze_format_string::ArgType::MatchKind371matchesSizeTPtrdiffT(ASTContext &C, QualType T, QualType E) {372  using MatchKind = clang::analyze_format_string::ArgType::MatchKind;373 374  if (!T->isIntegerType())375    return MatchKind::NoMatch;376 377  if (C.hasSameType(T, E))378    return MatchKind::Match;379 380  if (C.getCorrespondingSignedType(T.getCanonicalType()) !=381      C.getCorrespondingSignedType(E.getCanonicalType()))382    return MatchKind::NoMatch;383 384  return MatchKind::NoMatchSignedness;385}386 387clang::analyze_format_string::ArgType::MatchKind388ArgType::matchesType(ASTContext &C, QualType argTy) const {389  // When using the format attribute in C++, you can receive a function or an390  // array that will necessarily decay to a pointer when passed to the final391  // format consumer. Apply decay before type comparison.392  if (argTy->canDecayToPointerType())393    argTy = C.getDecayedType(argTy);394 395  if (Ptr) {396    // It has to be a pointer.397    const PointerType *PT = argTy->getAs<PointerType>();398    if (!PT)399      return NoMatch;400 401    // We cannot write through a const qualified pointer.402    if (PT->getPointeeType().isConstQualified())403      return NoMatch;404 405    argTy = PT->getPointeeType();406  }407 408  switch (K) {409    case InvalidTy:410      llvm_unreachable("ArgType must be valid");411 412    case UnknownTy:413      return Match;414 415    case AnyCharTy: {416      if (const auto *ED = argTy->getAsEnumDecl()) {417        // If the enum is incomplete we know nothing about the underlying type.418        // Assume that it's 'int'. Do not use the underlying type for a scoped419        // enumeration.420        if (!ED->isComplete())421          return NoMatch;422        if (!ED->isScoped())423          argTy = ED->getIntegerType();424      }425 426      if (const auto *BT = argTy->getAs<BuiltinType>()) {427        // The types are perfectly matched?428        switch (BT->getKind()) {429        default:430          break;431        case BuiltinType::Char_S:432        case BuiltinType::SChar:433        case BuiltinType::UChar:434        case BuiltinType::Char_U:435            return Match;436        case BuiltinType::Bool:437          if (!Ptr)438            return Match;439          break;440        }441        // "Partially matched" because of promotions?442        if (!Ptr) {443          switch (BT->getKind()) {444          default:445            break;446          case BuiltinType::Int:447          case BuiltinType::UInt:448            return MatchPromotion;449          case BuiltinType::Short:450          case BuiltinType::UShort:451          case BuiltinType::WChar_S:452          case BuiltinType::WChar_U:453            return NoMatchPromotionTypeConfusion;454          }455        }456      }457      return NoMatch;458    }459 460    case SpecificTy: {461      if (TK != TypeKind::DontCare) {462        return matchesSizeTPtrdiffT(C, argTy, T);463      }464 465      if (const auto *ED = argTy->getAsEnumDecl()) {466        // If the enum is incomplete we know nothing about the underlying type.467        // Assume that it's 'int'. Do not use the underlying type for a scoped468        // enumeration as that needs an exact match.469        if (!ED->isComplete())470          argTy = C.IntTy;471        else if (!ED->isScoped())472          argTy = ED->getIntegerType();473      }474 475      if (argTy->isSaturatedFixedPointType())476        argTy = C.getCorrespondingUnsaturatedType(argTy);477 478      argTy = C.getCanonicalType(argTy).getUnqualifiedType();479 480      if (T == argTy)481        return Match;482      if (const auto *BT = argTy->getAs<BuiltinType>()) {483        // Check if the only difference between them is signed vs unsigned484        // if true, return match signedness.485        switch (BT->getKind()) {486          default:487            break;488          case BuiltinType::Bool:489            if (Ptr && (T == C.UnsignedCharTy || T == C.SignedCharTy))490              return NoMatch;491            [[fallthrough]];492          case BuiltinType::Char_S:493          case BuiltinType::SChar:494            if (T == C.UnsignedShortTy || T == C.ShortTy)495              return NoMatchTypeConfusion;496            if (T == C.UnsignedCharTy)497              return NoMatchSignedness;498            if (T == C.SignedCharTy)499              return Match;500            break;501          case BuiltinType::Char_U:502          case BuiltinType::UChar:503            if (T == C.UnsignedShortTy || T == C.ShortTy)504              return NoMatchTypeConfusion;505            if (T == C.UnsignedCharTy)506              return Match;507            if (T == C.SignedCharTy)508              return NoMatchSignedness;509            break;510          case BuiltinType::Short:511            if (T == C.UnsignedShortTy)512              return NoMatchSignedness;513            break;514          case BuiltinType::UShort:515            if (T == C.ShortTy)516              return NoMatchSignedness;517            break;518          case BuiltinType::Int:519            if (T == C.UnsignedIntTy)520              return NoMatchSignedness;521            break;522          case BuiltinType::UInt:523            if (T == C.IntTy)524              return NoMatchSignedness;525            break;526          case BuiltinType::Long:527            if (T == C.UnsignedLongTy)528              return NoMatchSignedness;529            break;530          case BuiltinType::ULong:531            if (T == C.LongTy)532              return NoMatchSignedness;533            break;534          case BuiltinType::LongLong:535            if (T == C.UnsignedLongLongTy)536              return NoMatchSignedness;537            break;538          case BuiltinType::ULongLong:539            if (T == C.LongLongTy)540              return NoMatchSignedness;541            break;542          }543          // "Partially matched" because of promotions?544          if (!Ptr) {545            switch (BT->getKind()) {546            default:547              break;548            case BuiltinType::Bool:549              if (T == C.IntTy || T == C.UnsignedIntTy)550                return MatchPromotion;551              break;552            case BuiltinType::Int:553            case BuiltinType::UInt:554              if (T == C.SignedCharTy || T == C.UnsignedCharTy ||555                  T == C.ShortTy || T == C.UnsignedShortTy || T == C.WCharTy ||556                  T == C.WideCharTy)557                return MatchPromotion;558              break;559            case BuiltinType::Char_U:560              if (T == C.UnsignedIntTy)561                return MatchPromotion;562              if (T == C.UnsignedShortTy)563                return NoMatchPromotionTypeConfusion;564              break;565            case BuiltinType::Char_S:566              if (T == C.IntTy)567                return MatchPromotion;568              if (T == C.ShortTy)569                return NoMatchPromotionTypeConfusion;570              break;571            case BuiltinType::Half:572            case BuiltinType::Float:573              if (T == C.DoubleTy)574                return MatchPromotion;575              break;576            case BuiltinType::Short:577            case BuiltinType::UShort:578              if (T == C.SignedCharTy || T == C.UnsignedCharTy)579                return NoMatchPromotionTypeConfusion;580              break;581            case BuiltinType::WChar_U:582            case BuiltinType::WChar_S:583              if (T != C.WCharTy && T != C.WideCharTy)584                return NoMatchPromotionTypeConfusion;585            }586          }587      }588      return NoMatch;589    }590 591    case CStrTy:592      if (const auto *PT = argTy->getAs<PointerType>();593          PT && PT->getPointeeType()->isCharType())594        return Match;595      return NoMatch;596 597    case WCStrTy:598      if (const auto *PT = argTy->getAs<PointerType>();599          PT &&600          C.hasSameUnqualifiedType(PT->getPointeeType(), C.getWideCharType()))601        return Match;602      return NoMatch;603 604    case WIntTy: {605      QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType();606 607      if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)608        return Match;609 610      QualType PromoArg = C.isPromotableIntegerType(argTy)611                              ? C.getPromotedIntegerType(argTy)612                              : argTy;613      PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();614 615      // If the promoted argument is the corresponding signed type of the616      // wint_t type, then it should match.617      if (PromoArg->hasSignedIntegerRepresentation() &&618          C.getCorrespondingUnsignedType(PromoArg) == WInt)619        return Match;620 621      return WInt == PromoArg ? Match : NoMatch;622    }623 624    case CPointerTy:625      if (const auto *PT = argTy->getAs<PointerType>()) {626        QualType PointeeTy = PT->getPointeeType();627        if (PointeeTy->isVoidType() || (!Ptr && PointeeTy->isCharType()))628          return Match;629        return NoMatchPedantic;630      }631 632      // nullptr_t* is not a double pointer, so reject when something like633      // void** is expected.634      // In C++, nullptr is promoted to void*. In C23, va_arg(ap, void*) is not635      // undefined when the next argument is of type nullptr_t.636      if (!Ptr && argTy->isNullPtrType())637        return C.getLangOpts().CPlusPlus ? MatchPromotion : Match;638 639      if (argTy->isObjCObjectPointerType() || argTy->isBlockPointerType())640        return NoMatchPedantic;641 642      return NoMatch;643 644    case ObjCPointerTy: {645      if (argTy->getAs<ObjCObjectPointerType>() ||646          argTy->getAs<BlockPointerType>())647        return Match;648 649      // Handle implicit toll-free bridging.650      if (const PointerType *PT = argTy->getAs<PointerType>()) {651        // Things such as CFTypeRef are really just opaque pointers652        // to C structs representing CF types that can often be bridged653        // to Objective-C objects.  Since the compiler doesn't know which654        // structs can be toll-free bridged, we just accept them all.655        QualType pointee = PT->getPointeeType();656        if (pointee->isStructureType() || pointee->isVoidType())657          return Match;658      }659      return NoMatch;660    }661  }662 663  llvm_unreachable("Invalid ArgType Kind!");664}665 666static analyze_format_string::ArgType::MatchKind667integerTypeMatch(ASTContext &C, QualType A, QualType B, bool CheckSign) {668  using MK = analyze_format_string::ArgType::MatchKind;669 670  uint64_t IntSize = C.getTypeSize(C.IntTy);671  uint64_t ASize = C.getTypeSize(A);672  uint64_t BSize = C.getTypeSize(B);673  if (std::max(ASize, IntSize) != std::max(BSize, IntSize))674    return MK::NoMatch;675  if (CheckSign && A->isSignedIntegerType() != B->isSignedIntegerType())676    return MK::NoMatchSignedness;677  if (ASize != BSize)678    return MK::MatchPromotion;679  return MK::Match;680}681 682analyze_format_string::ArgType::MatchKind683ArgType::matchesArgType(ASTContext &C, const ArgType &Other) const {684  using AK = analyze_format_string::ArgType::Kind;685 686  // Per matchesType.687  if (K == AK::InvalidTy || Other.K == AK::InvalidTy)688    return NoMatch;689  if (K == AK::UnknownTy || Other.K == AK::UnknownTy)690    return Match;691 692  // Handle whether either (or both, or neither) sides has Ptr set,693  // in addition to whether either (or both, or neither) sides is a SpecificTy694  // that is a pointer.695  ArgType Left = *this;696  bool LeftWasPointer = false;697  ArgType Right = Other;698  bool RightWasPointer = false;699  if (Left.Ptr) {700    Left.Ptr = false;701    LeftWasPointer = true;702  } else if (Left.K == AK::SpecificTy && Left.T->isPointerType()) {703    Left.T = Left.T->getPointeeType();704    LeftWasPointer = true;705  }706  if (Right.Ptr) {707    Right.Ptr = false;708    RightWasPointer = true;709  } else if (Right.K == AK::SpecificTy && Right.T->isPointerType()) {710    Right.T = Right.T->getPointeeType();711    RightWasPointer = true;712  }713 714  if (LeftWasPointer != RightWasPointer)715    return NoMatch;716 717  // Ensure that if at least one side is a SpecificTy, then Left is a718  // SpecificTy.719  if (Right.K == AK::SpecificTy)720    std::swap(Left, Right);721 722  if (Left.K == AK::SpecificTy) {723    if (Right.K == AK::SpecificTy) {724      if (Left.TK != TypeKind::DontCare) {725        return matchesSizeTPtrdiffT(C, Right.T, Left.T);726      } else if (Right.TK != TypeKind::DontCare) {727        return matchesSizeTPtrdiffT(C, Left.T, Right.T);728      }729 730      auto Canon1 = C.getCanonicalType(Left.T);731      auto Canon2 = C.getCanonicalType(Right.T);732      if (Canon1 == Canon2)733        return Match;734 735      auto *BT1 = QualType(Canon1)->getAs<BuiltinType>();736      auto *BT2 = QualType(Canon2)->getAs<BuiltinType>();737      if (BT1 == nullptr || BT2 == nullptr)738        return NoMatch;739      if (BT1 == BT2)740        return Match;741 742      if (!LeftWasPointer && BT1->isInteger() && BT2->isInteger())743        return integerTypeMatch(C, Canon1, Canon2, true);744      return NoMatch;745    } else if (Right.K == AK::AnyCharTy) {746      if (!LeftWasPointer && Left.T->isIntegerType())747        return integerTypeMatch(C, Left.T, C.CharTy, false);748      return NoMatch;749    } else if (Right.K == AK::WIntTy) {750      if (!LeftWasPointer && Left.T->isIntegerType())751        return integerTypeMatch(C, Left.T, C.WIntTy, true);752      return NoMatch;753    }754    // It's hypothetically possible to create an AK::SpecificTy ArgType755    // that matches another kind of ArgType, but in practice Clang doesn't756    // do that, so ignore that case.757    return NoMatch;758  }759 760  return Left.K == Right.K ? Match : NoMatch;761}762 763ArgType ArgType::makeVectorType(ASTContext &C, unsigned NumElts) const {764  // Check for valid vector element types.765  if (T.isNull())766    return ArgType::Invalid();767 768  QualType Vec = C.getExtVectorType(T, NumElts);769  return ArgType(Vec, Name);770}771 772QualType ArgType::getRepresentativeType(ASTContext &C) const {773  QualType Res;774  switch (K) {775    case InvalidTy:776      llvm_unreachable("No representative type for Invalid ArgType");777    case UnknownTy:778      llvm_unreachable("No representative type for Unknown ArgType");779    case AnyCharTy:780      Res = C.CharTy;781      break;782    case SpecificTy:783      if (TK == TypeKind::PtrdiffT || TK == TypeKind::SizeT)784        // Using Name as name, so no need to show the uglified name.785        Res = T->getCanonicalTypeInternal();786      else787        Res = T;788      break;789    case CStrTy:790      Res = C.getPointerType(C.CharTy);791      break;792    case WCStrTy:793      Res = C.getPointerType(C.getWideCharType());794      break;795    case ObjCPointerTy:796      Res = C.ObjCBuiltinIdTy;797      break;798    case CPointerTy:799      Res = C.VoidPtrTy;800      break;801    case WIntTy: {802      Res = C.getWIntType();803      break;804    }805  }806 807  if (Ptr)808    Res = C.getPointerType(Res);809  return Res;810}811 812std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {813  std::string S = getRepresentativeType(C).getAsString(C.getPrintingPolicy());814  std::string Alias;815  if (Name) {816    // Use a specific name for this type, e.g. "size_t".817    Alias = Name;818    if (Ptr) {819      // If ArgType is actually a pointer to T, append an asterisk.820      Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *";821    }822    // If Alias is the same as the underlying type, e.g. wchar_t, then drop it.823    if (S == Alias)824      Alias.clear();825  }826 827  if (!Alias.empty())828    return std::string("'") + Alias + "' (aka '" + S + "')";829  return std::string("'") + S + "'";830}831 832 833//===----------------------------------------------------------------------===//834// Methods on OptionalAmount.835//===----------------------------------------------------------------------===//836 837ArgType838analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {839  return Ctx.IntTy;840}841 842//===----------------------------------------------------------------------===//843// Methods on LengthModifier.844//===----------------------------------------------------------------------===//845 846const char *847analyze_format_string::LengthModifier::toString() const {848  switch (kind) {849  case AsChar:850    return "hh";851  case AsShort:852    return "h";853  case AsShortLong:854    return "hl";855  case AsLong: // or AsWideChar856    return "l";857  case AsLongLong:858    return "ll";859  case AsQuad:860    return "q";861  case AsIntMax:862    return "j";863  case AsSizeT:864    return "z";865  case AsPtrDiff:866    return "t";867  case AsInt32:868    return "I32";869  case AsInt3264:870    return "I";871  case AsInt64:872    return "I64";873  case AsLongDouble:874    return "L";875  case AsAllocate:876    return "a";877  case AsMAllocate:878    return "m";879  case AsWide:880    return "w";881  case None:882    return "";883  }884  return nullptr;885}886 887//===----------------------------------------------------------------------===//888// Methods on ConversionSpecifier.889//===----------------------------------------------------------------------===//890 891const char *ConversionSpecifier::toString() const {892  switch (kind) {893  case bArg: return "b";894  case BArg: return "B";895  case dArg: return "d";896  case DArg: return "D";897  case iArg: return "i";898  case oArg: return "o";899  case OArg: return "O";900  case uArg: return "u";901  case UArg: return "U";902  case xArg: return "x";903  case XArg: return "X";904  case fArg: return "f";905  case FArg: return "F";906  case eArg: return "e";907  case EArg: return "E";908  case gArg: return "g";909  case GArg: return "G";910  case aArg: return "a";911  case AArg: return "A";912  case cArg: return "c";913  case sArg: return "s";914  case pArg: return "p";915  case PArg:916    return "P";917  case nArg: return "n";918  case PercentArg:  return "%";919  case ScanListArg: return "[";920  case InvalidSpecifier: return nullptr;921 922  // POSIX unicode extensions.923  case CArg: return "C";924  case SArg: return "S";925 926  // Objective-C specific specifiers.927  case ObjCObjArg: return "@";928 929  // FreeBSD kernel specific specifiers.930  case FreeBSDbArg: return "b";931  case FreeBSDDArg: return "D";932  case FreeBSDrArg: return "r";933  case FreeBSDyArg: return "y";934 935  // GlibC specific specifiers.936  case PrintErrno: return "m";937 938  // MS specific specifiers.939  case ZArg: return "Z";940 941  // ISO/IEC TR 18037 (fixed-point) specific specifiers.942  case rArg:943    return "r";944  case RArg:945    return "R";946  case kArg:947    return "k";948  case KArg:949    return "K";950  }951  return nullptr;952}953 954std::optional<ConversionSpecifier>955ConversionSpecifier::getStandardSpecifier() const {956  ConversionSpecifier::Kind NewKind;957 958  switch (getKind()) {959  default:960    return std::nullopt;961  case DArg:962    NewKind = dArg;963    break;964  case UArg:965    NewKind = uArg;966    break;967  case OArg:968    NewKind = oArg;969    break;970  }971 972  ConversionSpecifier FixedCS(*this);973  FixedCS.setKind(NewKind);974  return FixedCS;975}976 977//===----------------------------------------------------------------------===//978// Methods on OptionalAmount.979//===----------------------------------------------------------------------===//980 981void OptionalAmount::toString(raw_ostream &os) const {982  switch (hs) {983  case Invalid:984  case NotSpecified:985    return;986  case Arg:987    if (UsesDotPrefix)988        os << ".";989    if (usesPositionalArg())990      os << "*" << getPositionalArgIndex() << "$";991    else992      os << "*";993    break;994  case Constant:995    if (UsesDotPrefix)996        os << ".";997    os << amt;998    break;999  }1000}1001 1002bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,1003                                             const LangOptions &LO) const {1004  switch (LM.getKind()) {1005    case LengthModifier::None:1006      return true;1007 1008    // Handle most integer flags1009    case LengthModifier::AsShort:1010      // Length modifier only applies to FP vectors.1011      if (LO.OpenCL && CS.isDoubleArg())1012        return !VectorNumElts.isInvalid();1013 1014      if (CS.isFixedPointArg())1015        return true;1016 1017      if (Target.getTriple().isOSMSVCRT()) {1018        switch (CS.getKind()) {1019          case ConversionSpecifier::cArg:1020          case ConversionSpecifier::CArg:1021          case ConversionSpecifier::sArg:1022          case ConversionSpecifier::SArg:1023          case ConversionSpecifier::ZArg:1024            return true;1025          default:1026            break;1027        }1028      }1029      [[fallthrough]];1030    case LengthModifier::AsChar:1031    case LengthModifier::AsLongLong:1032    case LengthModifier::AsQuad:1033    case LengthModifier::AsIntMax:1034    case LengthModifier::AsSizeT:1035    case LengthModifier::AsPtrDiff:1036      switch (CS.getKind()) {1037        case ConversionSpecifier::bArg:1038        case ConversionSpecifier::BArg:1039        case ConversionSpecifier::dArg:1040        case ConversionSpecifier::DArg:1041        case ConversionSpecifier::iArg:1042        case ConversionSpecifier::oArg:1043        case ConversionSpecifier::OArg:1044        case ConversionSpecifier::uArg:1045        case ConversionSpecifier::UArg:1046        case ConversionSpecifier::xArg:1047        case ConversionSpecifier::XArg:1048        case ConversionSpecifier::nArg:1049          return true;1050        case ConversionSpecifier::FreeBSDrArg:1051        case ConversionSpecifier::FreeBSDyArg:1052          return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS();1053        default:1054          return false;1055      }1056 1057    case LengthModifier::AsShortLong:1058      return LO.OpenCL && !VectorNumElts.isInvalid();1059 1060    // Handle 'l' flag1061    case LengthModifier::AsLong: // or AsWideChar1062      if (CS.isDoubleArg()) {1063        // Invalid for OpenCL FP scalars.1064        if (LO.OpenCL && VectorNumElts.isInvalid())1065          return false;1066        return true;1067      }1068 1069      if (CS.isFixedPointArg())1070        return true;1071 1072      switch (CS.getKind()) {1073        case ConversionSpecifier::bArg:1074        case ConversionSpecifier::BArg:1075        case ConversionSpecifier::dArg:1076        case ConversionSpecifier::DArg:1077        case ConversionSpecifier::iArg:1078        case ConversionSpecifier::oArg:1079        case ConversionSpecifier::OArg:1080        case ConversionSpecifier::uArg:1081        case ConversionSpecifier::UArg:1082        case ConversionSpecifier::xArg:1083        case ConversionSpecifier::XArg:1084        case ConversionSpecifier::nArg:1085        case ConversionSpecifier::cArg:1086        case ConversionSpecifier::sArg:1087        case ConversionSpecifier::ScanListArg:1088        case ConversionSpecifier::ZArg:1089          return true;1090        case ConversionSpecifier::FreeBSDrArg:1091        case ConversionSpecifier::FreeBSDyArg:1092          return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS();1093        default:1094          return false;1095      }1096 1097    case LengthModifier::AsLongDouble:1098      switch (CS.getKind()) {1099        case ConversionSpecifier::aArg:1100        case ConversionSpecifier::AArg:1101        case ConversionSpecifier::fArg:1102        case ConversionSpecifier::FArg:1103        case ConversionSpecifier::eArg:1104        case ConversionSpecifier::EArg:1105        case ConversionSpecifier::gArg:1106        case ConversionSpecifier::GArg:1107          return true;1108        // GNU libc extension.1109        case ConversionSpecifier::dArg:1110        case ConversionSpecifier::iArg:1111        case ConversionSpecifier::oArg:1112        case ConversionSpecifier::uArg:1113        case ConversionSpecifier::xArg:1114        case ConversionSpecifier::XArg:1115          return !Target.getTriple().isOSDarwin() &&1116                 !Target.getTriple().isOSWindows();1117        default:1118          return false;1119      }1120 1121    case LengthModifier::AsAllocate:1122      switch (CS.getKind()) {1123        case ConversionSpecifier::sArg:1124        case ConversionSpecifier::SArg:1125        case ConversionSpecifier::ScanListArg:1126          return true;1127        default:1128          return false;1129      }1130 1131    case LengthModifier::AsMAllocate:1132      switch (CS.getKind()) {1133        case ConversionSpecifier::cArg:1134        case ConversionSpecifier::CArg:1135        case ConversionSpecifier::sArg:1136        case ConversionSpecifier::SArg:1137        case ConversionSpecifier::ScanListArg:1138          return true;1139        default:1140          return false;1141      }1142    case LengthModifier::AsInt32:1143    case LengthModifier::AsInt3264:1144    case LengthModifier::AsInt64:1145      switch (CS.getKind()) {1146        case ConversionSpecifier::dArg:1147        case ConversionSpecifier::iArg:1148        case ConversionSpecifier::oArg:1149        case ConversionSpecifier::uArg:1150        case ConversionSpecifier::xArg:1151        case ConversionSpecifier::XArg:1152          return Target.getTriple().isOSMSVCRT();1153        default:1154          return false;1155      }1156    case LengthModifier::AsWide:1157      switch (CS.getKind()) {1158        case ConversionSpecifier::cArg:1159        case ConversionSpecifier::CArg:1160        case ConversionSpecifier::sArg:1161        case ConversionSpecifier::SArg:1162        case ConversionSpecifier::ZArg:1163          return Target.getTriple().isOSMSVCRT();1164        default:1165          return false;1166      }1167  }1168  llvm_unreachable("Invalid LengthModifier Kind!");1169}1170 1171bool FormatSpecifier::hasStandardLengthModifier() const {1172  switch (LM.getKind()) {1173    case LengthModifier::None:1174    case LengthModifier::AsChar:1175    case LengthModifier::AsShort:1176    case LengthModifier::AsLong:1177    case LengthModifier::AsLongLong:1178    case LengthModifier::AsIntMax:1179    case LengthModifier::AsSizeT:1180    case LengthModifier::AsPtrDiff:1181    case LengthModifier::AsLongDouble:1182      return true;1183    case LengthModifier::AsAllocate:1184    case LengthModifier::AsMAllocate:1185    case LengthModifier::AsQuad:1186    case LengthModifier::AsInt32:1187    case LengthModifier::AsInt3264:1188    case LengthModifier::AsInt64:1189    case LengthModifier::AsWide:1190    case LengthModifier::AsShortLong: // ???1191      return false;1192  }1193  llvm_unreachable("Invalid LengthModifier Kind!");1194}1195 1196bool FormatSpecifier::hasStandardConversionSpecifier(1197    const LangOptions &LangOpt) const {1198  switch (CS.getKind()) {1199    case ConversionSpecifier::bArg:1200    case ConversionSpecifier::BArg:1201    case ConversionSpecifier::cArg:1202    case ConversionSpecifier::dArg:1203    case ConversionSpecifier::iArg:1204    case ConversionSpecifier::oArg:1205    case ConversionSpecifier::uArg:1206    case ConversionSpecifier::xArg:1207    case ConversionSpecifier::XArg:1208    case ConversionSpecifier::fArg:1209    case ConversionSpecifier::FArg:1210    case ConversionSpecifier::eArg:1211    case ConversionSpecifier::EArg:1212    case ConversionSpecifier::gArg:1213    case ConversionSpecifier::GArg:1214    case ConversionSpecifier::aArg:1215    case ConversionSpecifier::AArg:1216    case ConversionSpecifier::sArg:1217    case ConversionSpecifier::pArg:1218    case ConversionSpecifier::nArg:1219    case ConversionSpecifier::ObjCObjArg:1220    case ConversionSpecifier::ScanListArg:1221    case ConversionSpecifier::PercentArg:1222    case ConversionSpecifier::PArg:1223      return true;1224    case ConversionSpecifier::CArg:1225    case ConversionSpecifier::SArg:1226      return LangOpt.ObjC;1227    case ConversionSpecifier::InvalidSpecifier:1228    case ConversionSpecifier::FreeBSDbArg:1229    case ConversionSpecifier::FreeBSDDArg:1230    case ConversionSpecifier::FreeBSDrArg:1231    case ConversionSpecifier::FreeBSDyArg:1232    case ConversionSpecifier::PrintErrno:1233    case ConversionSpecifier::DArg:1234    case ConversionSpecifier::OArg:1235    case ConversionSpecifier::UArg:1236    case ConversionSpecifier::ZArg:1237      return false;1238    case ConversionSpecifier::rArg:1239    case ConversionSpecifier::RArg:1240    case ConversionSpecifier::kArg:1241    case ConversionSpecifier::KArg:1242      return LangOpt.FixedPoint;1243  }1244  llvm_unreachable("Invalid ConversionSpecifier Kind!");1245}1246 1247bool FormatSpecifier::hasStandardLengthConversionCombination() const {1248  if (LM.getKind() == LengthModifier::AsLongDouble) {1249    switch(CS.getKind()) {1250        case ConversionSpecifier::dArg:1251        case ConversionSpecifier::iArg:1252        case ConversionSpecifier::oArg:1253        case ConversionSpecifier::uArg:1254        case ConversionSpecifier::xArg:1255        case ConversionSpecifier::XArg:1256          return false;1257        default:1258          return true;1259    }1260  }1261  return true;1262}1263 1264std::optional<LengthModifier>1265FormatSpecifier::getCorrectedLengthModifier() const {1266  if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {1267    if (LM.getKind() == LengthModifier::AsLongDouble ||1268        LM.getKind() == LengthModifier::AsQuad) {1269      LengthModifier FixedLM(LM);1270      FixedLM.setKind(LengthModifier::AsLongLong);1271      return FixedLM;1272    }1273  }1274 1275  return std::nullopt;1276}1277 1278bool FormatSpecifier::namedTypeToLengthModifier(ASTContext &Ctx, QualType QT,1279                                                LengthModifier &LM) {1280  if (LengthModifier::Kind Out = LengthModifier::Kind::None;1281      namedTypeToLengthModifierKind(Ctx, QT, Out)) {1282    LM.setKind(Out);1283    return true;1284  }1285  return false;1286}1287