Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:37

0001 //= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // This file defines APIs for analyzing the format strings of printf, fscanf,
0010 // and friends.
0011 //
0012 // The structure of format strings for fprintf are described in C99 7.19.6.1.
0013 //
0014 // The structure of format strings for fscanf are described in C99 7.19.6.2.
0015 //
0016 //===----------------------------------------------------------------------===//
0017 
0018 #ifndef LLVM_CLANG_AST_FORMATSTRING_H
0019 #define LLVM_CLANG_AST_FORMATSTRING_H
0020 
0021 #include "clang/AST/CanonicalType.h"
0022 #include <optional>
0023 
0024 namespace clang {
0025 
0026 class TargetInfo;
0027 
0028 //===----------------------------------------------------------------------===//
0029 /// Common components of both fprintf and fscanf format strings.
0030 namespace analyze_format_string {
0031 
0032 /// Class representing optional flags with location and representation
0033 /// information.
0034 class OptionalFlag {
0035 public:
0036   OptionalFlag(const char *Representation)
0037       : representation(Representation), flag(false) {}
0038   bool isSet() const { return flag; }
0039   void set() { flag = true; }
0040   void clear() { flag = false; }
0041   void setPosition(const char *position) {
0042     assert(position);
0043     flag = true;
0044     this->position = position;
0045   }
0046   const char *getPosition() const {
0047     assert(position);
0048     return position;
0049   }
0050   const char *toString() const { return representation; }
0051 
0052   // Overloaded operators for bool like qualities
0053   explicit operator bool() const { return flag; }
0054   OptionalFlag& operator=(const bool &rhs) {
0055     flag = rhs;
0056     return *this;  // Return a reference to myself.
0057   }
0058 private:
0059   const char *representation;
0060   const char *position;
0061   bool flag;
0062 };
0063 
0064 /// Represents the length modifier in a format string in scanf/printf.
0065 class LengthModifier {
0066 public:
0067   enum Kind {
0068     None,
0069     AsChar,       // 'hh'
0070     AsShort,      // 'h'
0071     AsShortLong,  // 'hl' (OpenCL float/int vector element)
0072     AsLong,       // 'l'
0073     AsLongLong,   // 'll'
0074     AsQuad,       // 'q' (BSD, deprecated, for 64-bit integer types)
0075     AsIntMax,     // 'j'
0076     AsSizeT,      // 'z'
0077     AsPtrDiff,    // 't'
0078     AsInt32,      // 'I32' (MSVCRT, like __int32)
0079     AsInt3264,    // 'I'   (MSVCRT, like __int3264 from MIDL)
0080     AsInt64,      // 'I64' (MSVCRT, like __int64)
0081     AsLongDouble, // 'L'
0082     AsAllocate,   // for '%as', GNU extension to C90 scanf
0083     AsMAllocate,  // for '%ms', GNU extension to scanf
0084     AsWide,       // 'w' (MSVCRT, like l but only for c, C, s, S, or Z
0085     AsWideChar = AsLong // for '%ls', only makes sense for printf
0086   };
0087 
0088   LengthModifier()
0089     : Position(nullptr), kind(None) {}
0090   LengthModifier(const char *pos, Kind k)
0091     : Position(pos), kind(k) {}
0092 
0093   const char *getStart() const {
0094     return Position;
0095   }
0096 
0097   unsigned getLength() const {
0098     switch (kind) {
0099       default:
0100         return 1;
0101       case AsLongLong:
0102       case AsChar:
0103         return 2;
0104       case AsInt32:
0105       case AsInt64:
0106         return 3;
0107       case None:
0108         return 0;
0109     }
0110   }
0111 
0112   Kind getKind() const { return kind; }
0113   void setKind(Kind k) { kind = k; }
0114 
0115   const char *toString() const;
0116 
0117 private:
0118   const char *Position;
0119   Kind kind;
0120 };
0121 
0122 class ConversionSpecifier {
0123 public:
0124   enum Kind {
0125     InvalidSpecifier = 0,
0126     // C99 conversion specifiers.
0127     cArg,
0128     dArg,
0129     DArg, // Apple extension
0130     iArg,
0131     // C23 conversion specifiers.
0132     bArg,
0133     BArg,
0134 
0135     IntArgBeg = dArg,
0136     IntArgEnd = BArg,
0137 
0138     oArg,
0139     OArg, // Apple extension
0140     uArg,
0141     UArg, // Apple extension
0142     xArg,
0143     XArg,
0144     UIntArgBeg = oArg,
0145     UIntArgEnd = XArg,
0146 
0147     fArg,
0148     FArg,
0149     eArg,
0150     EArg,
0151     gArg,
0152     GArg,
0153     aArg,
0154     AArg,
0155     DoubleArgBeg = fArg,
0156     DoubleArgEnd = AArg,
0157 
0158     sArg,
0159     pArg,
0160     nArg,
0161     PercentArg,
0162     CArg,
0163     SArg,
0164 
0165     // Apple extension: P specifies to os_log that the data being pointed to is
0166     // to be copied by os_log. The precision indicates the number of bytes to
0167     // copy.
0168     PArg,
0169 
0170     // ** Printf-specific **
0171 
0172     ZArg, // MS extension
0173 
0174     // ISO/IEC TR 18037 (fixed-point) specific specifiers.
0175     kArg, // %k for signed accum types
0176     KArg, // %K for unsigned accum types
0177     rArg, // %r for signed fract types
0178     RArg, // %R for unsigned fract types
0179     FixedPointArgBeg = kArg,
0180     FixedPointArgEnd = RArg,
0181 
0182     // Objective-C specific specifiers.
0183     ObjCObjArg, // '@'
0184     ObjCBeg = ObjCObjArg,
0185     ObjCEnd = ObjCObjArg,
0186 
0187     // FreeBSD kernel specific specifiers.
0188     FreeBSDbArg,
0189     FreeBSDDArg,
0190     FreeBSDrArg,
0191     FreeBSDyArg,
0192 
0193     // GlibC specific specifiers.
0194     PrintErrno, // 'm'
0195 
0196     PrintfConvBeg = ObjCObjArg,
0197     PrintfConvEnd = PrintErrno,
0198 
0199     // ** Scanf-specific **
0200     ScanListArg, // '['
0201     ScanfConvBeg = ScanListArg,
0202     ScanfConvEnd = ScanListArg
0203   };
0204 
0205   ConversionSpecifier(bool isPrintf = true)
0206     : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
0207       kind(InvalidSpecifier) {}
0208 
0209   ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
0210     : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
0211 
0212   const char *getStart() const {
0213     return Position;
0214   }
0215 
0216   StringRef getCharacters() const {
0217     return StringRef(getStart(), getLength());
0218   }
0219 
0220   bool consumesDataArgument() const {
0221     switch (kind) {
0222       case PrintErrno:
0223         assert(IsPrintf);
0224         return false;
0225       case PercentArg:
0226         return false;
0227       case InvalidSpecifier:
0228         return false;
0229       default:
0230         return true;
0231     }
0232   }
0233 
0234   Kind getKind() const { return kind; }
0235   void setKind(Kind k) { kind = k; }
0236   unsigned getLength() const {
0237     return EndScanList ? EndScanList - Position : 1;
0238   }
0239   void setEndScanList(const char *pos) { EndScanList = pos; }
0240 
0241   bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
0242     kind == FreeBSDrArg || kind == FreeBSDyArg; }
0243   bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
0244   bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
0245   bool isDoubleArg() const {
0246     return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
0247   }
0248   bool isFixedPointArg() const {
0249     return kind >= FixedPointArgBeg && kind <= FixedPointArgEnd;
0250   }
0251 
0252   const char *toString() const;
0253 
0254   bool isPrintfKind() const { return IsPrintf; }
0255 
0256   std::optional<ConversionSpecifier> getStandardSpecifier() const;
0257 
0258 protected:
0259   bool IsPrintf;
0260   const char *Position;
0261   const char *EndScanList;
0262   Kind kind;
0263 };
0264 
0265 class ArgType {
0266 public:
0267   enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
0268               AnyCharTy, CStrTy, WCStrTy, WIntTy };
0269 
0270   /// How well a given conversion specifier matches its argument.
0271   enum MatchKind {
0272     /// The conversion specifier and the argument types are incompatible. For
0273     /// instance, "%d" and float.
0274     NoMatch = 0,
0275     /// The conversion specifier and the argument type are compatible. For
0276     /// instance, "%d" and int.
0277     Match = 1,
0278     /// The conversion specifier and the argument type are compatible because of
0279     /// default argument promotions. For instance, "%hhd" and int.
0280     MatchPromotion,
0281     /// The conversion specifier and the argument type are compatible but still
0282     /// seems likely to be an error. For instanace, "%hhd" and short.
0283     NoMatchPromotionTypeConfusion,
0284     /// The conversion specifier and the argument type are disallowed by the C
0285     /// standard, but are in practice harmless. For instance, "%p" and int*.
0286     NoMatchPedantic,
0287     /// The conversion specifier and the argument type have different sign.
0288     NoMatchSignedness,
0289     /// The conversion specifier and the argument type are compatible, but still
0290     /// seems likely to be an error. For instance, "%hd" and _Bool.
0291     NoMatchTypeConfusion,
0292   };
0293 
0294 private:
0295   const Kind K;
0296   QualType T;
0297   const char *Name = nullptr;
0298   bool Ptr = false;
0299 
0300   /// The TypeKind identifies certain well-known types like size_t and
0301   /// ptrdiff_t.
0302   enum class TypeKind { DontCare, SizeT, PtrdiffT };
0303   TypeKind TK = TypeKind::DontCare;
0304 
0305 public:
0306   ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
0307   ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}
0308   ArgType(CanQualType T) : K(SpecificTy), T(T) {}
0309 
0310   static ArgType Invalid() { return ArgType(InvalidTy); }
0311   bool isValid() const { return K != InvalidTy; }
0312 
0313   bool isSizeT() const { return TK == TypeKind::SizeT; }
0314 
0315   bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }
0316 
0317   /// Create an ArgType which corresponds to the type pointer to A.
0318   static ArgType PtrTo(const ArgType& A) {
0319     assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
0320     ArgType Res = A;
0321     Res.Ptr = true;
0322     return Res;
0323   }
0324 
0325   /// Create an ArgType which corresponds to the size_t/ssize_t type.
0326   static ArgType makeSizeT(const ArgType &A) {
0327     ArgType Res = A;
0328     Res.TK = TypeKind::SizeT;
0329     return Res;
0330   }
0331 
0332   /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t
0333   /// type.
0334   static ArgType makePtrdiffT(const ArgType &A) {
0335     ArgType Res = A;
0336     Res.TK = TypeKind::PtrdiffT;
0337     return Res;
0338   }
0339 
0340   MatchKind matchesType(ASTContext &C, QualType argTy) const;
0341 
0342   QualType getRepresentativeType(ASTContext &C) const;
0343 
0344   ArgType makeVectorType(ASTContext &C, unsigned NumElts) const;
0345 
0346   std::string getRepresentativeTypeName(ASTContext &C) const;
0347 };
0348 
0349 class OptionalAmount {
0350 public:
0351   enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
0352 
0353   OptionalAmount(HowSpecified howSpecified,
0354                  unsigned amount,
0355                  const char *amountStart,
0356                  unsigned amountLength,
0357                  bool usesPositionalArg)
0358   : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
0359   UsesPositionalArg(usesPositionalArg), UsesDotPrefix(false) {}
0360 
0361   OptionalAmount(bool valid = true)
0362   : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
0363   UsesPositionalArg(false), UsesDotPrefix(false) {}
0364 
0365   explicit OptionalAmount(unsigned Amount)
0366     : start(nullptr), length(0), hs(Constant), amt(Amount),
0367     UsesPositionalArg(false), UsesDotPrefix(false) {}
0368 
0369   bool isInvalid() const {
0370     return hs == Invalid;
0371   }
0372 
0373   HowSpecified getHowSpecified() const { return hs; }
0374   void setHowSpecified(HowSpecified h) { hs = h; }
0375 
0376   bool hasDataArgument() const { return hs == Arg; }
0377 
0378   unsigned getArgIndex() const {
0379     assert(hasDataArgument());
0380     return amt;
0381   }
0382 
0383   unsigned getConstantAmount() const {
0384     assert(hs == Constant);
0385     return amt;
0386   }
0387 
0388   const char *getStart() const {
0389       // We include the . character if it is given.
0390     return start - UsesDotPrefix;
0391   }
0392 
0393   unsigned getConstantLength() const {
0394     assert(hs == Constant);
0395     return length + UsesDotPrefix;
0396   }
0397 
0398   ArgType getArgType(ASTContext &Ctx) const;
0399 
0400   void toString(raw_ostream &os) const;
0401 
0402   bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
0403   unsigned getPositionalArgIndex() const {
0404     assert(hasDataArgument());
0405     return amt + 1;
0406   }
0407 
0408   bool usesDotPrefix() const { return UsesDotPrefix; }
0409   void setUsesDotPrefix() { UsesDotPrefix = true; }
0410 
0411 private:
0412   const char *start;
0413   unsigned length;
0414   HowSpecified hs;
0415   unsigned amt;
0416   bool UsesPositionalArg : 1;
0417   bool UsesDotPrefix;
0418 };
0419 
0420 
0421 class FormatSpecifier {
0422 protected:
0423   LengthModifier LM;
0424   OptionalAmount FieldWidth;
0425   ConversionSpecifier CS;
0426   OptionalAmount VectorNumElts;
0427 
0428   /// Positional arguments, an IEEE extension:
0429   ///  IEEE Std 1003.1, 2004 Edition
0430   ///  http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
0431   bool UsesPositionalArg;
0432   unsigned argIndex;
0433 public:
0434   FormatSpecifier(bool isPrintf)
0435     : CS(isPrintf), VectorNumElts(false),
0436       UsesPositionalArg(false), argIndex(0) {}
0437 
0438   void setLengthModifier(LengthModifier lm) {
0439     LM = lm;
0440   }
0441 
0442   void setUsesPositionalArg() { UsesPositionalArg = true; }
0443 
0444   void setArgIndex(unsigned i) {
0445     argIndex = i;
0446   }
0447 
0448   unsigned getArgIndex() const {
0449     return argIndex;
0450   }
0451 
0452   unsigned getPositionalArgIndex() const {
0453     return argIndex + 1;
0454   }
0455 
0456   const LengthModifier &getLengthModifier() const {
0457     return LM;
0458   }
0459 
0460   const OptionalAmount &getFieldWidth() const {
0461     return FieldWidth;
0462   }
0463 
0464   void setVectorNumElts(const OptionalAmount &Amt) {
0465     VectorNumElts = Amt;
0466   }
0467 
0468   const OptionalAmount &getVectorNumElts() const {
0469     return VectorNumElts;
0470   }
0471 
0472   void setFieldWidth(const OptionalAmount &Amt) {
0473     FieldWidth = Amt;
0474   }
0475 
0476   bool usesPositionalArg() const { return UsesPositionalArg; }
0477 
0478   bool hasValidLengthModifier(const TargetInfo &Target,
0479                               const LangOptions &LO) const;
0480 
0481   bool hasStandardLengthModifier() const;
0482 
0483   std::optional<LengthModifier> getCorrectedLengthModifier() const;
0484 
0485   bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
0486 
0487   bool hasStandardLengthConversionCombination() const;
0488 
0489   /// For a TypedefType QT, if it is a named integer type such as size_t,
0490   /// assign the appropriate value to LM and return true.
0491   static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
0492 };
0493 
0494 } // end analyze_format_string namespace
0495 
0496 //===----------------------------------------------------------------------===//
0497 /// Pieces specific to fprintf format strings.
0498 
0499 namespace analyze_printf {
0500 
0501 class PrintfConversionSpecifier :
0502   public analyze_format_string::ConversionSpecifier  {
0503 public:
0504   PrintfConversionSpecifier()
0505     : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
0506 
0507   PrintfConversionSpecifier(const char *pos, Kind k)
0508     : ConversionSpecifier(true, pos, k) {}
0509 
0510   bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
0511   bool isDoubleArg() const { return kind >= DoubleArgBeg &&
0512                                     kind <= DoubleArgEnd; }
0513 
0514   static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
0515     return CS->isPrintfKind();
0516   }
0517 };
0518 
0519 using analyze_format_string::ArgType;
0520 using analyze_format_string::LengthModifier;
0521 using analyze_format_string::OptionalAmount;
0522 using analyze_format_string::OptionalFlag;
0523 
0524 class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
0525   OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
0526   OptionalFlag IsLeftJustified; // '-'
0527   OptionalFlag HasPlusPrefix; // '+'
0528   OptionalFlag HasSpacePrefix; // ' '
0529   OptionalFlag HasAlternativeForm; // '#'
0530   OptionalFlag HasLeadingZeroes; // '0'
0531   OptionalFlag HasObjCTechnicalTerm; // '[tt]'
0532   OptionalFlag IsPrivate;            // '{private}'
0533   OptionalFlag IsPublic;             // '{public}'
0534   OptionalFlag IsSensitive;          // '{sensitive}'
0535   OptionalAmount Precision;
0536   StringRef MaskType;
0537 
0538   ArgType getScalarArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
0539 
0540 public:
0541   PrintfSpecifier()
0542       : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
0543         IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
0544         HasAlternativeForm("#"), HasLeadingZeroes("0"),
0545         HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public"),
0546         IsSensitive("sensitive") {}
0547 
0548   static PrintfSpecifier Parse(const char *beg, const char *end);
0549 
0550     // Methods for incrementally constructing the PrintfSpecifier.
0551   void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
0552     CS = cs;
0553   }
0554   void setHasThousandsGrouping(const char *position) {
0555     HasThousandsGrouping.setPosition(position);
0556   }
0557   void setIsLeftJustified(const char *position) {
0558     IsLeftJustified.setPosition(position);
0559   }
0560   void setHasPlusPrefix(const char *position) {
0561     HasPlusPrefix.setPosition(position);
0562   }
0563   void setHasSpacePrefix(const char *position) {
0564     HasSpacePrefix.setPosition(position);
0565   }
0566   void setHasAlternativeForm(const char *position) {
0567     HasAlternativeForm.setPosition(position);
0568   }
0569   void setHasLeadingZeros(const char *position) {
0570     HasLeadingZeroes.setPosition(position);
0571   }
0572   void setHasObjCTechnicalTerm(const char *position) {
0573     HasObjCTechnicalTerm.setPosition(position);
0574   }
0575   void setIsPrivate(const char *position) { IsPrivate.setPosition(position); }
0576   void setIsPublic(const char *position) { IsPublic.setPosition(position); }
0577   void setIsSensitive(const char *position) {
0578     IsSensitive.setPosition(position);
0579   }
0580   void setUsesPositionalArg() { UsesPositionalArg = true; }
0581 
0582     // Methods for querying the format specifier.
0583 
0584   const PrintfConversionSpecifier &getConversionSpecifier() const {
0585     return cast<PrintfConversionSpecifier>(CS);
0586   }
0587 
0588   void setPrecision(const OptionalAmount &Amt) {
0589     Precision = Amt;
0590     Precision.setUsesDotPrefix();
0591   }
0592 
0593   const OptionalAmount &getPrecision() const {
0594     return Precision;
0595   }
0596 
0597   bool consumesDataArgument() const {
0598     return getConversionSpecifier().consumesDataArgument();
0599   }
0600 
0601   /// Returns the builtin type that a data argument
0602   /// paired with this format specifier should have.  This method
0603   /// will return null if the format specifier does not have
0604   /// a matching data argument or the matching argument matches
0605   /// more than one type.
0606   ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
0607 
0608   const OptionalFlag &hasThousandsGrouping() const {
0609       return HasThousandsGrouping;
0610   }
0611   const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
0612   const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
0613   const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
0614   const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
0615   const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
0616   const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }
0617   const OptionalFlag &isPrivate() const { return IsPrivate; }
0618   const OptionalFlag &isPublic() const { return IsPublic; }
0619   const OptionalFlag &isSensitive() const { return IsSensitive; }
0620   bool usesPositionalArg() const { return UsesPositionalArg; }
0621 
0622   StringRef getMaskType() const { return MaskType; }
0623   void setMaskType(StringRef S) { MaskType = S; }
0624 
0625   /// Changes the specifier and length according to a QualType, retaining any
0626   /// flags or options. Returns true on success, or false when a conversion
0627   /// was not successful.
0628   bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
0629                bool IsObjCLiteral);
0630 
0631   void toString(raw_ostream &os) const;
0632 
0633   // Validation methods - to check if any element results in undefined behavior
0634   bool hasValidPlusPrefix() const;
0635   bool hasValidAlternativeForm() const;
0636   bool hasValidLeadingZeros() const;
0637   bool hasValidSpacePrefix() const;
0638   bool hasValidLeftJustified() const;
0639   bool hasValidThousandsGroupingPrefix() const;
0640 
0641   bool hasValidPrecision() const;
0642   bool hasValidFieldWidth() const;
0643 };
0644 }  // end analyze_printf namespace
0645 
0646 //===----------------------------------------------------------------------===//
0647 /// Pieces specific to fscanf format strings.
0648 
0649 namespace analyze_scanf {
0650 
0651 class ScanfConversionSpecifier :
0652     public analyze_format_string::ConversionSpecifier  {
0653 public:
0654   ScanfConversionSpecifier()
0655     : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
0656 
0657   ScanfConversionSpecifier(const char *pos, Kind k)
0658     : ConversionSpecifier(false, pos, k) {}
0659 
0660   static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
0661     return !CS->isPrintfKind();
0662   }
0663 };
0664 
0665 using analyze_format_string::ArgType;
0666 using analyze_format_string::LengthModifier;
0667 using analyze_format_string::OptionalAmount;
0668 using analyze_format_string::OptionalFlag;
0669 
0670 class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
0671   OptionalFlag SuppressAssignment; // '*'
0672 public:
0673   ScanfSpecifier() :
0674     FormatSpecifier(/* isPrintf = */ false),
0675     SuppressAssignment("*") {}
0676 
0677   void setSuppressAssignment(const char *position) {
0678     SuppressAssignment.setPosition(position);
0679   }
0680 
0681   const OptionalFlag &getSuppressAssignment() const {
0682     return SuppressAssignment;
0683   }
0684 
0685   void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
0686     CS = cs;
0687   }
0688 
0689   const ScanfConversionSpecifier &getConversionSpecifier() const {
0690     return cast<ScanfConversionSpecifier>(CS);
0691   }
0692 
0693   bool consumesDataArgument() const {
0694     return CS.consumesDataArgument() && !SuppressAssignment;
0695   }
0696 
0697   ArgType getArgType(ASTContext &Ctx) const;
0698 
0699   bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
0700                ASTContext &Ctx);
0701 
0702   void toString(raw_ostream &os) const;
0703 
0704   static ScanfSpecifier Parse(const char *beg, const char *end);
0705 };
0706 
0707 } // end analyze_scanf namespace
0708 
0709 //===----------------------------------------------------------------------===//
0710 // Parsing and processing of format strings (both fprintf and fscanf).
0711 
0712 namespace analyze_format_string {
0713 
0714 enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
0715 
0716 class FormatStringHandler {
0717 public:
0718   FormatStringHandler() {}
0719   virtual ~FormatStringHandler();
0720 
0721   virtual void HandleNullChar(const char *nullCharacter) {}
0722 
0723   virtual void HandlePosition(const char *startPos, unsigned posLen) {}
0724 
0725   virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
0726                                      PositionContext p) {}
0727 
0728   virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
0729 
0730   virtual void HandleIncompleteSpecifier(const char *startSpecifier,
0731                                          unsigned specifierLen) {}
0732 
0733   virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
0734                                            unsigned flagsLen) {}
0735 
0736   virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
0737                                              unsigned flagLen) {}
0738 
0739   virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
0740                                             const char *flagsEnd,
0741                                             const char *conversionPosition) {}
0742   // Printf-specific handlers.
0743 
0744   virtual bool HandleInvalidPrintfConversionSpecifier(
0745                                       const analyze_printf::PrintfSpecifier &FS,
0746                                       const char *startSpecifier,
0747                                       unsigned specifierLen) {
0748     return true;
0749   }
0750 
0751   virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
0752                                      const char *startSpecifier,
0753                                      unsigned specifierLen,
0754                                      const TargetInfo &Target) {
0755     return true;
0756   }
0757 
0758   /// Handle mask types whose sizes are not between one and eight bytes.
0759   virtual void handleInvalidMaskType(StringRef MaskType) {}
0760 
0761     // Scanf-specific handlers.
0762 
0763   virtual bool HandleInvalidScanfConversionSpecifier(
0764                                         const analyze_scanf::ScanfSpecifier &FS,
0765                                         const char *startSpecifier,
0766                                         unsigned specifierLen) {
0767     return true;
0768   }
0769 
0770   virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
0771                                     const char *startSpecifier,
0772                                     unsigned specifierLen) {
0773     return true;
0774   }
0775 
0776   virtual void HandleIncompleteScanList(const char *start, const char *end) {}
0777 };
0778 
0779 bool ParsePrintfString(FormatStringHandler &H,
0780                        const char *beg, const char *end, const LangOptions &LO,
0781                        const TargetInfo &Target, bool isFreeBSDKPrintf);
0782 
0783 bool ParseFormatStringHasSArg(const char *beg, const char *end,
0784                               const LangOptions &LO, const TargetInfo &Target);
0785 
0786 bool ParseScanfString(FormatStringHandler &H,
0787                       const char *beg, const char *end, const LangOptions &LO,
0788                       const TargetInfo &Target);
0789 
0790 /// Return true if the given string has at least one formatting specifier.
0791 bool parseFormatStringHasFormattingSpecifiers(const char *Begin,
0792                                               const char *End,
0793                                               const LangOptions &LO,
0794                                               const TargetInfo &Target);
0795 
0796 } // end analyze_format_string namespace
0797 } // end clang namespace
0798 #endif