10b57cec5SDimitry Andric //= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines APIs for analyzing the format strings of printf, fscanf,
100b57cec5SDimitry Andric // and friends.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric // The structure of format strings for fprintf are described in C99 7.19.6.1.
130b57cec5SDimitry Andric //
140b57cec5SDimitry Andric // The structure of format strings for fscanf are described in C99 7.19.6.2.
150b57cec5SDimitry Andric //
160b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
190b57cec5SDimitry Andric #define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric #include "clang/AST/CanonicalType.h"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric namespace clang {
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric class TargetInfo;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
280b57cec5SDimitry Andric /// Common components of both fprintf and fscanf format strings.
290b57cec5SDimitry Andric namespace analyze_format_string {
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric /// Class representing optional flags with location and representation
320b57cec5SDimitry Andric /// information.
330b57cec5SDimitry Andric class OptionalFlag {
340b57cec5SDimitry Andric public:
350b57cec5SDimitry Andric   OptionalFlag(const char *Representation)
360b57cec5SDimitry Andric       : representation(Representation), flag(false) {}
370b57cec5SDimitry Andric   bool isSet() const { return flag; }
380b57cec5SDimitry Andric   void set() { flag = true; }
390b57cec5SDimitry Andric   void clear() { flag = false; }
400b57cec5SDimitry Andric   void setPosition(const char *position) {
410b57cec5SDimitry Andric     assert(position);
420b57cec5SDimitry Andric     flag = true;
430b57cec5SDimitry Andric     this->position = position;
440b57cec5SDimitry Andric   }
450b57cec5SDimitry Andric   const char *getPosition() const {
460b57cec5SDimitry Andric     assert(position);
470b57cec5SDimitry Andric     return position;
480b57cec5SDimitry Andric   }
490b57cec5SDimitry Andric   const char *toString() const { return representation; }
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   // Overloaded operators for bool like qualities
520b57cec5SDimitry Andric   explicit operator bool() const { return flag; }
530b57cec5SDimitry Andric   OptionalFlag& operator=(const bool &rhs) {
540b57cec5SDimitry Andric     flag = rhs;
550b57cec5SDimitry Andric     return *this;  // Return a reference to myself.
560b57cec5SDimitry Andric   }
570b57cec5SDimitry Andric private:
580b57cec5SDimitry Andric   const char *representation;
590b57cec5SDimitry Andric   const char *position;
600b57cec5SDimitry Andric   bool flag;
610b57cec5SDimitry Andric };
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric /// Represents the length modifier in a format string in scanf/printf.
640b57cec5SDimitry Andric class LengthModifier {
650b57cec5SDimitry Andric public:
660b57cec5SDimitry Andric   enum Kind {
670b57cec5SDimitry Andric     None,
680b57cec5SDimitry Andric     AsChar,       // 'hh'
690b57cec5SDimitry Andric     AsShort,      // 'h'
700b57cec5SDimitry Andric     AsShortLong,  // 'hl' (OpenCL float/int vector element)
710b57cec5SDimitry Andric     AsLong,       // 'l'
720b57cec5SDimitry Andric     AsLongLong,   // 'll'
730b57cec5SDimitry Andric     AsQuad,       // 'q' (BSD, deprecated, for 64-bit integer types)
740b57cec5SDimitry Andric     AsIntMax,     // 'j'
750b57cec5SDimitry Andric     AsSizeT,      // 'z'
760b57cec5SDimitry Andric     AsPtrDiff,    // 't'
770b57cec5SDimitry Andric     AsInt32,      // 'I32' (MSVCRT, like __int32)
780b57cec5SDimitry Andric     AsInt3264,    // 'I'   (MSVCRT, like __int3264 from MIDL)
790b57cec5SDimitry Andric     AsInt64,      // 'I64' (MSVCRT, like __int64)
800b57cec5SDimitry Andric     AsLongDouble, // 'L'
810b57cec5SDimitry Andric     AsAllocate,   // for '%as', GNU extension to C90 scanf
820b57cec5SDimitry Andric     AsMAllocate,  // for '%ms', GNU extension to scanf
830b57cec5SDimitry Andric     AsWide,       // 'w' (MSVCRT, like l but only for c, C, s, S, or Z
840b57cec5SDimitry Andric     AsWideChar = AsLong // for '%ls', only makes sense for printf
850b57cec5SDimitry Andric   };
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   LengthModifier()
880b57cec5SDimitry Andric     : Position(nullptr), kind(None) {}
890b57cec5SDimitry Andric   LengthModifier(const char *pos, Kind k)
900b57cec5SDimitry Andric     : Position(pos), kind(k) {}
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   const char *getStart() const {
930b57cec5SDimitry Andric     return Position;
940b57cec5SDimitry Andric   }
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric   unsigned getLength() const {
970b57cec5SDimitry Andric     switch (kind) {
980b57cec5SDimitry Andric       default:
990b57cec5SDimitry Andric         return 1;
1000b57cec5SDimitry Andric       case AsLongLong:
1010b57cec5SDimitry Andric       case AsChar:
1020b57cec5SDimitry Andric         return 2;
1030b57cec5SDimitry Andric       case AsInt32:
1040b57cec5SDimitry Andric       case AsInt64:
1050b57cec5SDimitry Andric         return 3;
1060b57cec5SDimitry Andric       case None:
1070b57cec5SDimitry Andric         return 0;
1080b57cec5SDimitry Andric     }
1090b57cec5SDimitry Andric   }
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric   Kind getKind() const { return kind; }
1120b57cec5SDimitry Andric   void setKind(Kind k) { kind = k; }
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   const char *toString() const;
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric private:
1170b57cec5SDimitry Andric   const char *Position;
1180b57cec5SDimitry Andric   Kind kind;
1190b57cec5SDimitry Andric };
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric class ConversionSpecifier {
1220b57cec5SDimitry Andric public:
1230b57cec5SDimitry Andric   enum Kind {
1240b57cec5SDimitry Andric     InvalidSpecifier = 0,
1250b57cec5SDimitry Andric     // C99 conversion specifiers.
1260b57cec5SDimitry Andric     cArg,
1270b57cec5SDimitry Andric     dArg,
1280b57cec5SDimitry Andric     DArg, // Apple extension
1290b57cec5SDimitry Andric     iArg,
1300b57cec5SDimitry Andric     IntArgBeg = dArg,
1310b57cec5SDimitry Andric     IntArgEnd = iArg,
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric     oArg,
1340b57cec5SDimitry Andric     OArg, // Apple extension
1350b57cec5SDimitry Andric     uArg,
1360b57cec5SDimitry Andric     UArg, // Apple extension
1370b57cec5SDimitry Andric     xArg,
1380b57cec5SDimitry Andric     XArg,
1390b57cec5SDimitry Andric     UIntArgBeg = oArg,
1400b57cec5SDimitry Andric     UIntArgEnd = XArg,
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric     fArg,
1430b57cec5SDimitry Andric     FArg,
1440b57cec5SDimitry Andric     eArg,
1450b57cec5SDimitry Andric     EArg,
1460b57cec5SDimitry Andric     gArg,
1470b57cec5SDimitry Andric     GArg,
1480b57cec5SDimitry Andric     aArg,
1490b57cec5SDimitry Andric     AArg,
1500b57cec5SDimitry Andric     DoubleArgBeg = fArg,
1510b57cec5SDimitry Andric     DoubleArgEnd = AArg,
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric     sArg,
1540b57cec5SDimitry Andric     pArg,
1550b57cec5SDimitry Andric     nArg,
1560b57cec5SDimitry Andric     PercentArg,
1570b57cec5SDimitry Andric     CArg,
1580b57cec5SDimitry Andric     SArg,
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric     // Apple extension: P specifies to os_log that the data being pointed to is
1610b57cec5SDimitry Andric     // to be copied by os_log. The precision indicates the number of bytes to
1620b57cec5SDimitry Andric     // copy.
1630b57cec5SDimitry Andric     PArg,
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric     // ** Printf-specific **
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric     ZArg, // MS extension
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric     // Objective-C specific specifiers.
1700b57cec5SDimitry Andric     ObjCObjArg, // '@'
1710b57cec5SDimitry Andric     ObjCBeg = ObjCObjArg,
1720b57cec5SDimitry Andric     ObjCEnd = ObjCObjArg,
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric     // FreeBSD kernel specific specifiers.
1750b57cec5SDimitry Andric     FreeBSDbArg,
1760b57cec5SDimitry Andric     FreeBSDDArg,
1770b57cec5SDimitry Andric     FreeBSDrArg,
1780b57cec5SDimitry Andric     FreeBSDyArg,
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric     // GlibC specific specifiers.
1810b57cec5SDimitry Andric     PrintErrno, // 'm'
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric     PrintfConvBeg = ObjCObjArg,
1840b57cec5SDimitry Andric     PrintfConvEnd = PrintErrno,
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric     // ** Scanf-specific **
1870b57cec5SDimitry Andric     ScanListArg, // '['
1880b57cec5SDimitry Andric     ScanfConvBeg = ScanListArg,
1890b57cec5SDimitry Andric     ScanfConvEnd = ScanListArg
1900b57cec5SDimitry Andric   };
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric   ConversionSpecifier(bool isPrintf = true)
1930b57cec5SDimitry Andric     : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
1940b57cec5SDimitry Andric       kind(InvalidSpecifier) {}
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric   ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
1970b57cec5SDimitry Andric     : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric   const char *getStart() const {
2000b57cec5SDimitry Andric     return Position;
2010b57cec5SDimitry Andric   }
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric   StringRef getCharacters() const {
2040b57cec5SDimitry Andric     return StringRef(getStart(), getLength());
2050b57cec5SDimitry Andric   }
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric   bool consumesDataArgument() const {
2080b57cec5SDimitry Andric     switch (kind) {
2090b57cec5SDimitry Andric       case PrintErrno:
2100b57cec5SDimitry Andric         assert(IsPrintf);
2110b57cec5SDimitry Andric         return false;
2120b57cec5SDimitry Andric       case PercentArg:
2130b57cec5SDimitry Andric         return false;
2140b57cec5SDimitry Andric       case InvalidSpecifier:
2150b57cec5SDimitry Andric         return false;
2160b57cec5SDimitry Andric       default:
2170b57cec5SDimitry Andric         return true;
2180b57cec5SDimitry Andric     }
2190b57cec5SDimitry Andric   }
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric   Kind getKind() const { return kind; }
2220b57cec5SDimitry Andric   void setKind(Kind k) { kind = k; }
2230b57cec5SDimitry Andric   unsigned getLength() const {
2240b57cec5SDimitry Andric     return EndScanList ? EndScanList - Position : 1;
2250b57cec5SDimitry Andric   }
2260b57cec5SDimitry Andric   void setEndScanList(const char *pos) { EndScanList = pos; }
2270b57cec5SDimitry Andric 
2280b57cec5SDimitry Andric   bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
2290b57cec5SDimitry Andric     kind == FreeBSDrArg || kind == FreeBSDyArg; }
2300b57cec5SDimitry Andric   bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
2310b57cec5SDimitry Andric   bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
2320b57cec5SDimitry Andric   bool isDoubleArg() const {
2330b57cec5SDimitry Andric     return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
2340b57cec5SDimitry Andric   }
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric   const char *toString() const;
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   bool isPrintfKind() const { return IsPrintf; }
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric   Optional<ConversionSpecifier> getStandardSpecifier() const;
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric protected:
2430b57cec5SDimitry Andric   bool IsPrintf;
2440b57cec5SDimitry Andric   const char *Position;
2450b57cec5SDimitry Andric   const char *EndScanList;
2460b57cec5SDimitry Andric   Kind kind;
2470b57cec5SDimitry Andric };
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric class ArgType {
2500b57cec5SDimitry Andric public:
2510b57cec5SDimitry Andric   enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
2520b57cec5SDimitry Andric               AnyCharTy, CStrTy, WCStrTy, WIntTy };
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric   enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic };
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric private:
2570b57cec5SDimitry Andric   const Kind K;
2580b57cec5SDimitry Andric   QualType T;
2590b57cec5SDimitry Andric   const char *Name = nullptr;
2600b57cec5SDimitry Andric   bool Ptr = false;
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric   /// The TypeKind identifies certain well-known types like size_t and
2630b57cec5SDimitry Andric   /// ptrdiff_t.
2640b57cec5SDimitry Andric   enum class TypeKind { DontCare, SizeT, PtrdiffT };
2650b57cec5SDimitry Andric   TypeKind TK = TypeKind::DontCare;
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric public:
2680b57cec5SDimitry Andric   ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
2690b57cec5SDimitry Andric   ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}
2700b57cec5SDimitry Andric   ArgType(CanQualType T) : K(SpecificTy), T(T) {}
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric   static ArgType Invalid() { return ArgType(InvalidTy); }
2730b57cec5SDimitry Andric   bool isValid() const { return K != InvalidTy; }
2740b57cec5SDimitry Andric 
2750b57cec5SDimitry Andric   bool isSizeT() const { return TK == TypeKind::SizeT; }
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric   bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }
2780b57cec5SDimitry Andric 
2790b57cec5SDimitry Andric   /// Create an ArgType which corresponds to the type pointer to A.
2800b57cec5SDimitry Andric   static ArgType PtrTo(const ArgType& A) {
2810b57cec5SDimitry Andric     assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
2820b57cec5SDimitry Andric     ArgType Res = A;
2830b57cec5SDimitry Andric     Res.Ptr = true;
2840b57cec5SDimitry Andric     return Res;
2850b57cec5SDimitry Andric   }
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric   /// Create an ArgType which corresponds to the size_t/ssize_t type.
2880b57cec5SDimitry Andric   static ArgType makeSizeT(const ArgType &A) {
2890b57cec5SDimitry Andric     ArgType Res = A;
2900b57cec5SDimitry Andric     Res.TK = TypeKind::SizeT;
2910b57cec5SDimitry Andric     return Res;
2920b57cec5SDimitry Andric   }
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric   /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t
2950b57cec5SDimitry Andric   /// type.
2960b57cec5SDimitry Andric   static ArgType makePtrdiffT(const ArgType &A) {
2970b57cec5SDimitry Andric     ArgType Res = A;
2980b57cec5SDimitry Andric     Res.TK = TypeKind::PtrdiffT;
2990b57cec5SDimitry Andric     return Res;
3000b57cec5SDimitry Andric   }
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric   MatchKind matchesType(ASTContext &C, QualType argTy) const;
3030b57cec5SDimitry Andric 
3040b57cec5SDimitry Andric   QualType getRepresentativeType(ASTContext &C) const;
3050b57cec5SDimitry Andric 
3060b57cec5SDimitry Andric   ArgType makeVectorType(ASTContext &C, unsigned NumElts) const;
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric   std::string getRepresentativeTypeName(ASTContext &C) const;
3090b57cec5SDimitry Andric };
3100b57cec5SDimitry Andric 
3110b57cec5SDimitry Andric class OptionalAmount {
3120b57cec5SDimitry Andric public:
3130b57cec5SDimitry Andric   enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric   OptionalAmount(HowSpecified howSpecified,
3160b57cec5SDimitry Andric                  unsigned amount,
3170b57cec5SDimitry Andric                  const char *amountStart,
3180b57cec5SDimitry Andric                  unsigned amountLength,
3190b57cec5SDimitry Andric                  bool usesPositionalArg)
3200b57cec5SDimitry Andric   : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
3210b57cec5SDimitry Andric   UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric   OptionalAmount(bool valid = true)
3240b57cec5SDimitry Andric   : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
3250b57cec5SDimitry Andric   UsesPositionalArg(0), UsesDotPrefix(0) {}
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric   explicit OptionalAmount(unsigned Amount)
3280b57cec5SDimitry Andric     : start(nullptr), length(0), hs(Constant), amt(Amount),
3290b57cec5SDimitry Andric     UsesPositionalArg(false), UsesDotPrefix(false) {}
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric   bool isInvalid() const {
3320b57cec5SDimitry Andric     return hs == Invalid;
3330b57cec5SDimitry Andric   }
3340b57cec5SDimitry Andric 
3350b57cec5SDimitry Andric   HowSpecified getHowSpecified() const { return hs; }
3360b57cec5SDimitry Andric   void setHowSpecified(HowSpecified h) { hs = h; }
3370b57cec5SDimitry Andric 
3380b57cec5SDimitry Andric   bool hasDataArgument() const { return hs == Arg; }
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric   unsigned getArgIndex() const {
3410b57cec5SDimitry Andric     assert(hasDataArgument());
3420b57cec5SDimitry Andric     return amt;
3430b57cec5SDimitry Andric   }
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric   unsigned getConstantAmount() const {
3460b57cec5SDimitry Andric     assert(hs == Constant);
3470b57cec5SDimitry Andric     return amt;
3480b57cec5SDimitry Andric   }
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric   const char *getStart() const {
3510b57cec5SDimitry Andric       // We include the . character if it is given.
3520b57cec5SDimitry Andric     return start - UsesDotPrefix;
3530b57cec5SDimitry Andric   }
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric   unsigned getConstantLength() const {
3560b57cec5SDimitry Andric     assert(hs == Constant);
3570b57cec5SDimitry Andric     return length + UsesDotPrefix;
3580b57cec5SDimitry Andric   }
3590b57cec5SDimitry Andric 
3600b57cec5SDimitry Andric   ArgType getArgType(ASTContext &Ctx) const;
3610b57cec5SDimitry Andric 
3620b57cec5SDimitry Andric   void toString(raw_ostream &os) const;
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric   bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
3650b57cec5SDimitry Andric   unsigned getPositionalArgIndex() const {
3660b57cec5SDimitry Andric     assert(hasDataArgument());
3670b57cec5SDimitry Andric     return amt + 1;
3680b57cec5SDimitry Andric   }
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric   bool usesDotPrefix() const { return UsesDotPrefix; }
3710b57cec5SDimitry Andric   void setUsesDotPrefix() { UsesDotPrefix = true; }
3720b57cec5SDimitry Andric 
3730b57cec5SDimitry Andric private:
3740b57cec5SDimitry Andric   const char *start;
3750b57cec5SDimitry Andric   unsigned length;
3760b57cec5SDimitry Andric   HowSpecified hs;
3770b57cec5SDimitry Andric   unsigned amt;
3780b57cec5SDimitry Andric   bool UsesPositionalArg : 1;
3790b57cec5SDimitry Andric   bool UsesDotPrefix;
3800b57cec5SDimitry Andric };
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric 
3830b57cec5SDimitry Andric class FormatSpecifier {
3840b57cec5SDimitry Andric protected:
3850b57cec5SDimitry Andric   LengthModifier LM;
3860b57cec5SDimitry Andric   OptionalAmount FieldWidth;
3870b57cec5SDimitry Andric   ConversionSpecifier CS;
3880b57cec5SDimitry Andric   OptionalAmount VectorNumElts;
3890b57cec5SDimitry Andric 
3900b57cec5SDimitry Andric   /// Positional arguments, an IEEE extension:
3910b57cec5SDimitry Andric   ///  IEEE Std 1003.1, 2004 Edition
3920b57cec5SDimitry Andric   ///  http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
3930b57cec5SDimitry Andric   bool UsesPositionalArg;
3940b57cec5SDimitry Andric   unsigned argIndex;
3950b57cec5SDimitry Andric public:
3960b57cec5SDimitry Andric   FormatSpecifier(bool isPrintf)
3970b57cec5SDimitry Andric     : CS(isPrintf), VectorNumElts(false),
3980b57cec5SDimitry Andric       UsesPositionalArg(false), argIndex(0) {}
3990b57cec5SDimitry Andric 
4000b57cec5SDimitry Andric   void setLengthModifier(LengthModifier lm) {
4010b57cec5SDimitry Andric     LM = lm;
4020b57cec5SDimitry Andric   }
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric   void setUsesPositionalArg() { UsesPositionalArg = true; }
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric   void setArgIndex(unsigned i) {
4070b57cec5SDimitry Andric     argIndex = i;
4080b57cec5SDimitry Andric   }
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric   unsigned getArgIndex() const {
4110b57cec5SDimitry Andric     return argIndex;
4120b57cec5SDimitry Andric   }
4130b57cec5SDimitry Andric 
4140b57cec5SDimitry Andric   unsigned getPositionalArgIndex() const {
4150b57cec5SDimitry Andric     return argIndex + 1;
4160b57cec5SDimitry Andric   }
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric   const LengthModifier &getLengthModifier() const {
4190b57cec5SDimitry Andric     return LM;
4200b57cec5SDimitry Andric   }
4210b57cec5SDimitry Andric 
4220b57cec5SDimitry Andric   const OptionalAmount &getFieldWidth() const {
4230b57cec5SDimitry Andric     return FieldWidth;
4240b57cec5SDimitry Andric   }
4250b57cec5SDimitry Andric 
4260b57cec5SDimitry Andric   void setVectorNumElts(const OptionalAmount &Amt) {
4270b57cec5SDimitry Andric     VectorNumElts = Amt;
4280b57cec5SDimitry Andric   }
4290b57cec5SDimitry Andric 
4300b57cec5SDimitry Andric   const OptionalAmount &getVectorNumElts() const {
4310b57cec5SDimitry Andric     return VectorNumElts;
4320b57cec5SDimitry Andric   }
4330b57cec5SDimitry Andric 
4340b57cec5SDimitry Andric   void setFieldWidth(const OptionalAmount &Amt) {
4350b57cec5SDimitry Andric     FieldWidth = Amt;
4360b57cec5SDimitry Andric   }
4370b57cec5SDimitry Andric 
4380b57cec5SDimitry Andric   bool usesPositionalArg() const { return UsesPositionalArg; }
4390b57cec5SDimitry Andric 
4400b57cec5SDimitry Andric   bool hasValidLengthModifier(const TargetInfo &Target,
4410b57cec5SDimitry Andric                               const LangOptions &LO) const;
4420b57cec5SDimitry Andric 
4430b57cec5SDimitry Andric   bool hasStandardLengthModifier() const;
4440b57cec5SDimitry Andric 
4450b57cec5SDimitry Andric   Optional<LengthModifier> getCorrectedLengthModifier() const;
4460b57cec5SDimitry Andric 
4470b57cec5SDimitry Andric   bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
4480b57cec5SDimitry Andric 
4490b57cec5SDimitry Andric   bool hasStandardLengthConversionCombination() const;
4500b57cec5SDimitry Andric 
4510b57cec5SDimitry Andric   /// For a TypedefType QT, if it is a named integer type such as size_t,
4520b57cec5SDimitry Andric   /// assign the appropriate value to LM and return true.
4530b57cec5SDimitry Andric   static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
4540b57cec5SDimitry Andric };
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric } // end analyze_format_string namespace
4570b57cec5SDimitry Andric 
4580b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4590b57cec5SDimitry Andric /// Pieces specific to fprintf format strings.
4600b57cec5SDimitry Andric 
4610b57cec5SDimitry Andric namespace analyze_printf {
4620b57cec5SDimitry Andric 
4630b57cec5SDimitry Andric class PrintfConversionSpecifier :
4640b57cec5SDimitry Andric   public analyze_format_string::ConversionSpecifier  {
4650b57cec5SDimitry Andric public:
4660b57cec5SDimitry Andric   PrintfConversionSpecifier()
4670b57cec5SDimitry Andric     : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric   PrintfConversionSpecifier(const char *pos, Kind k)
4700b57cec5SDimitry Andric     : ConversionSpecifier(true, pos, k) {}
4710b57cec5SDimitry Andric 
4720b57cec5SDimitry Andric   bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
4730b57cec5SDimitry Andric   bool isDoubleArg() const { return kind >= DoubleArgBeg &&
4740b57cec5SDimitry Andric                                     kind <= DoubleArgEnd; }
4750b57cec5SDimitry Andric 
4760b57cec5SDimitry Andric   static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
4770b57cec5SDimitry Andric     return CS->isPrintfKind();
4780b57cec5SDimitry Andric   }
4790b57cec5SDimitry Andric };
4800b57cec5SDimitry Andric 
4810b57cec5SDimitry Andric using analyze_format_string::ArgType;
4820b57cec5SDimitry Andric using analyze_format_string::LengthModifier;
4830b57cec5SDimitry Andric using analyze_format_string::OptionalAmount;
4840b57cec5SDimitry Andric using analyze_format_string::OptionalFlag;
4850b57cec5SDimitry Andric 
4860b57cec5SDimitry Andric class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
4870b57cec5SDimitry Andric   OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
4880b57cec5SDimitry Andric   OptionalFlag IsLeftJustified; // '-'
4890b57cec5SDimitry Andric   OptionalFlag HasPlusPrefix; // '+'
4900b57cec5SDimitry Andric   OptionalFlag HasSpacePrefix; // ' '
4910b57cec5SDimitry Andric   OptionalFlag HasAlternativeForm; // '#'
4920b57cec5SDimitry Andric   OptionalFlag HasLeadingZeroes; // '0'
4930b57cec5SDimitry Andric   OptionalFlag HasObjCTechnicalTerm; // '[tt]'
4940b57cec5SDimitry Andric   OptionalFlag IsPrivate;            // '{private}'
4950b57cec5SDimitry Andric   OptionalFlag IsPublic;             // '{public}'
4960b57cec5SDimitry Andric   OptionalFlag IsSensitive;          // '{sensitive}'
4970b57cec5SDimitry Andric   OptionalAmount Precision;
4980b57cec5SDimitry Andric   StringRef MaskType;
4990b57cec5SDimitry Andric 
5000b57cec5SDimitry Andric   ArgType getScalarArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric public:
5030b57cec5SDimitry Andric   PrintfSpecifier()
5040b57cec5SDimitry Andric       : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
5050b57cec5SDimitry Andric         IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
5060b57cec5SDimitry Andric         HasAlternativeForm("#"), HasLeadingZeroes("0"),
5070b57cec5SDimitry Andric         HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public"),
5080b57cec5SDimitry Andric         IsSensitive("sensitive") {}
5090b57cec5SDimitry Andric 
5100b57cec5SDimitry Andric   static PrintfSpecifier Parse(const char *beg, const char *end);
5110b57cec5SDimitry Andric 
5120b57cec5SDimitry Andric     // Methods for incrementally constructing the PrintfSpecifier.
5130b57cec5SDimitry Andric   void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
5140b57cec5SDimitry Andric     CS = cs;
5150b57cec5SDimitry Andric   }
5160b57cec5SDimitry Andric   void setHasThousandsGrouping(const char *position) {
5170b57cec5SDimitry Andric     HasThousandsGrouping.setPosition(position);
5180b57cec5SDimitry Andric   }
5190b57cec5SDimitry Andric   void setIsLeftJustified(const char *position) {
5200b57cec5SDimitry Andric     IsLeftJustified.setPosition(position);
5210b57cec5SDimitry Andric   }
5220b57cec5SDimitry Andric   void setHasPlusPrefix(const char *position) {
5230b57cec5SDimitry Andric     HasPlusPrefix.setPosition(position);
5240b57cec5SDimitry Andric   }
5250b57cec5SDimitry Andric   void setHasSpacePrefix(const char *position) {
5260b57cec5SDimitry Andric     HasSpacePrefix.setPosition(position);
5270b57cec5SDimitry Andric   }
5280b57cec5SDimitry Andric   void setHasAlternativeForm(const char *position) {
5290b57cec5SDimitry Andric     HasAlternativeForm.setPosition(position);
5300b57cec5SDimitry Andric   }
5310b57cec5SDimitry Andric   void setHasLeadingZeros(const char *position) {
5320b57cec5SDimitry Andric     HasLeadingZeroes.setPosition(position);
5330b57cec5SDimitry Andric   }
5340b57cec5SDimitry Andric   void setHasObjCTechnicalTerm(const char *position) {
5350b57cec5SDimitry Andric     HasObjCTechnicalTerm.setPosition(position);
5360b57cec5SDimitry Andric   }
5370b57cec5SDimitry Andric   void setIsPrivate(const char *position) { IsPrivate.setPosition(position); }
5380b57cec5SDimitry Andric   void setIsPublic(const char *position) { IsPublic.setPosition(position); }
5390b57cec5SDimitry Andric   void setIsSensitive(const char *position) {
5400b57cec5SDimitry Andric     IsSensitive.setPosition(position);
5410b57cec5SDimitry Andric   }
5420b57cec5SDimitry Andric   void setUsesPositionalArg() { UsesPositionalArg = true; }
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric     // Methods for querying the format specifier.
5450b57cec5SDimitry Andric 
5460b57cec5SDimitry Andric   const PrintfConversionSpecifier &getConversionSpecifier() const {
5470b57cec5SDimitry Andric     return cast<PrintfConversionSpecifier>(CS);
5480b57cec5SDimitry Andric   }
5490b57cec5SDimitry Andric 
5500b57cec5SDimitry Andric   void setPrecision(const OptionalAmount &Amt) {
5510b57cec5SDimitry Andric     Precision = Amt;
5520b57cec5SDimitry Andric     Precision.setUsesDotPrefix();
5530b57cec5SDimitry Andric   }
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric   const OptionalAmount &getPrecision() const {
5560b57cec5SDimitry Andric     return Precision;
5570b57cec5SDimitry Andric   }
5580b57cec5SDimitry Andric 
5590b57cec5SDimitry Andric   bool consumesDataArgument() const {
5600b57cec5SDimitry Andric     return getConversionSpecifier().consumesDataArgument();
5610b57cec5SDimitry Andric   }
5620b57cec5SDimitry Andric 
5630b57cec5SDimitry Andric   /// Returns the builtin type that a data argument
5640b57cec5SDimitry Andric   /// paired with this format specifier should have.  This method
5650b57cec5SDimitry Andric   /// will return null if the format specifier does not have
5660b57cec5SDimitry Andric   /// a matching data argument or the matching argument matches
5670b57cec5SDimitry Andric   /// more than one type.
5680b57cec5SDimitry Andric   ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
5690b57cec5SDimitry Andric 
5700b57cec5SDimitry Andric   const OptionalFlag &hasThousandsGrouping() const {
5710b57cec5SDimitry Andric       return HasThousandsGrouping;
5720b57cec5SDimitry Andric   }
5730b57cec5SDimitry Andric   const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
5740b57cec5SDimitry Andric   const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
5750b57cec5SDimitry Andric   const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
5760b57cec5SDimitry Andric   const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
5770b57cec5SDimitry Andric   const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
5780b57cec5SDimitry Andric   const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }
5790b57cec5SDimitry Andric   const OptionalFlag &isPrivate() const { return IsPrivate; }
5800b57cec5SDimitry Andric   const OptionalFlag &isPublic() const { return IsPublic; }
5810b57cec5SDimitry Andric   const OptionalFlag &isSensitive() const { return IsSensitive; }
5820b57cec5SDimitry Andric   bool usesPositionalArg() const { return UsesPositionalArg; }
5830b57cec5SDimitry Andric 
5840b57cec5SDimitry Andric   StringRef getMaskType() const { return MaskType; }
5850b57cec5SDimitry Andric   void setMaskType(StringRef S) { MaskType = S; }
5860b57cec5SDimitry Andric 
5870b57cec5SDimitry Andric   /// Changes the specifier and length according to a QualType, retaining any
5880b57cec5SDimitry Andric   /// flags or options. Returns true on success, or false when a conversion
5890b57cec5SDimitry Andric   /// was not successful.
5900b57cec5SDimitry Andric   bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
5910b57cec5SDimitry Andric                bool IsObjCLiteral);
5920b57cec5SDimitry Andric 
5930b57cec5SDimitry Andric   void toString(raw_ostream &os) const;
5940b57cec5SDimitry Andric 
5950b57cec5SDimitry Andric   // Validation methods - to check if any element results in undefined behavior
5960b57cec5SDimitry Andric   bool hasValidPlusPrefix() const;
5970b57cec5SDimitry Andric   bool hasValidAlternativeForm() const;
5980b57cec5SDimitry Andric   bool hasValidLeadingZeros() const;
5990b57cec5SDimitry Andric   bool hasValidSpacePrefix() const;
6000b57cec5SDimitry Andric   bool hasValidLeftJustified() const;
6010b57cec5SDimitry Andric   bool hasValidThousandsGroupingPrefix() const;
6020b57cec5SDimitry Andric 
6030b57cec5SDimitry Andric   bool hasValidPrecision() const;
6040b57cec5SDimitry Andric   bool hasValidFieldWidth() const;
6050b57cec5SDimitry Andric };
6060b57cec5SDimitry Andric }  // end analyze_printf namespace
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
6090b57cec5SDimitry Andric /// Pieces specific to fscanf format strings.
6100b57cec5SDimitry Andric 
6110b57cec5SDimitry Andric namespace analyze_scanf {
6120b57cec5SDimitry Andric 
6130b57cec5SDimitry Andric class ScanfConversionSpecifier :
6140b57cec5SDimitry Andric     public analyze_format_string::ConversionSpecifier  {
6150b57cec5SDimitry Andric public:
6160b57cec5SDimitry Andric   ScanfConversionSpecifier()
6170b57cec5SDimitry Andric     : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
6180b57cec5SDimitry Andric 
6190b57cec5SDimitry Andric   ScanfConversionSpecifier(const char *pos, Kind k)
6200b57cec5SDimitry Andric     : ConversionSpecifier(false, pos, k) {}
6210b57cec5SDimitry Andric 
6220b57cec5SDimitry Andric   static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
6230b57cec5SDimitry Andric     return !CS->isPrintfKind();
6240b57cec5SDimitry Andric   }
6250b57cec5SDimitry Andric };
6260b57cec5SDimitry Andric 
6270b57cec5SDimitry Andric using analyze_format_string::ArgType;
6280b57cec5SDimitry Andric using analyze_format_string::LengthModifier;
6290b57cec5SDimitry Andric using analyze_format_string::OptionalAmount;
6300b57cec5SDimitry Andric using analyze_format_string::OptionalFlag;
6310b57cec5SDimitry Andric 
6320b57cec5SDimitry Andric class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
6330b57cec5SDimitry Andric   OptionalFlag SuppressAssignment; // '*'
6340b57cec5SDimitry Andric public:
6350b57cec5SDimitry Andric   ScanfSpecifier() :
6360b57cec5SDimitry Andric     FormatSpecifier(/* isPrintf = */ false),
6370b57cec5SDimitry Andric     SuppressAssignment("*") {}
6380b57cec5SDimitry Andric 
6390b57cec5SDimitry Andric   void setSuppressAssignment(const char *position) {
6400b57cec5SDimitry Andric     SuppressAssignment.setPosition(position);
6410b57cec5SDimitry Andric   }
6420b57cec5SDimitry Andric 
6430b57cec5SDimitry Andric   const OptionalFlag &getSuppressAssignment() const {
6440b57cec5SDimitry Andric     return SuppressAssignment;
6450b57cec5SDimitry Andric   }
6460b57cec5SDimitry Andric 
6470b57cec5SDimitry Andric   void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
6480b57cec5SDimitry Andric     CS = cs;
6490b57cec5SDimitry Andric   }
6500b57cec5SDimitry Andric 
6510b57cec5SDimitry Andric   const ScanfConversionSpecifier &getConversionSpecifier() const {
6520b57cec5SDimitry Andric     return cast<ScanfConversionSpecifier>(CS);
6530b57cec5SDimitry Andric   }
6540b57cec5SDimitry Andric 
6550b57cec5SDimitry Andric   bool consumesDataArgument() const {
6560b57cec5SDimitry Andric     return CS.consumesDataArgument() && !SuppressAssignment;
6570b57cec5SDimitry Andric   }
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric   ArgType getArgType(ASTContext &Ctx) const;
6600b57cec5SDimitry Andric 
6610b57cec5SDimitry Andric   bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
6620b57cec5SDimitry Andric                ASTContext &Ctx);
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric   void toString(raw_ostream &os) const;
6650b57cec5SDimitry Andric 
6660b57cec5SDimitry Andric   static ScanfSpecifier Parse(const char *beg, const char *end);
6670b57cec5SDimitry Andric };
6680b57cec5SDimitry Andric 
6690b57cec5SDimitry Andric } // end analyze_scanf namespace
6700b57cec5SDimitry Andric 
6710b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
6720b57cec5SDimitry Andric // Parsing and processing of format strings (both fprintf and fscanf).
6730b57cec5SDimitry Andric 
6740b57cec5SDimitry Andric namespace analyze_format_string {
6750b57cec5SDimitry Andric 
6760b57cec5SDimitry Andric enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
6770b57cec5SDimitry Andric 
6780b57cec5SDimitry Andric class FormatStringHandler {
6790b57cec5SDimitry Andric public:
6800b57cec5SDimitry Andric   FormatStringHandler() {}
6810b57cec5SDimitry Andric   virtual ~FormatStringHandler();
6820b57cec5SDimitry Andric 
6830b57cec5SDimitry Andric   virtual void HandleNullChar(const char *nullCharacter) {}
6840b57cec5SDimitry Andric 
6850b57cec5SDimitry Andric   virtual void HandlePosition(const char *startPos, unsigned posLen) {}
6860b57cec5SDimitry Andric 
6870b57cec5SDimitry Andric   virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
6880b57cec5SDimitry Andric                                      PositionContext p) {}
6890b57cec5SDimitry Andric 
6900b57cec5SDimitry Andric   virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric   virtual void HandleIncompleteSpecifier(const char *startSpecifier,
6930b57cec5SDimitry Andric                                          unsigned specifierLen) {}
6940b57cec5SDimitry Andric 
6950b57cec5SDimitry Andric   virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
6960b57cec5SDimitry Andric                                            unsigned flagsLen) {}
6970b57cec5SDimitry Andric 
6980b57cec5SDimitry Andric   virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
6990b57cec5SDimitry Andric                                              unsigned flagLen) {}
7000b57cec5SDimitry Andric 
7010b57cec5SDimitry Andric   virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
7020b57cec5SDimitry Andric                                             const char *flagsEnd,
7030b57cec5SDimitry Andric                                             const char *conversionPosition) {}
7040b57cec5SDimitry Andric   // Printf-specific handlers.
7050b57cec5SDimitry Andric 
7060b57cec5SDimitry Andric   virtual bool HandleInvalidPrintfConversionSpecifier(
7070b57cec5SDimitry Andric                                       const analyze_printf::PrintfSpecifier &FS,
7080b57cec5SDimitry Andric                                       const char *startSpecifier,
7090b57cec5SDimitry Andric                                       unsigned specifierLen) {
7100b57cec5SDimitry Andric     return true;
7110b57cec5SDimitry Andric   }
7120b57cec5SDimitry Andric 
7130b57cec5SDimitry Andric   virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
7140b57cec5SDimitry Andric                                      const char *startSpecifier,
7150b57cec5SDimitry Andric                                      unsigned specifierLen) {
7160b57cec5SDimitry Andric     return true;
7170b57cec5SDimitry Andric   }
7180b57cec5SDimitry Andric 
7190b57cec5SDimitry Andric   /// Handle mask types whose sizes are not between one and eight bytes.
7200b57cec5SDimitry Andric   virtual void handleInvalidMaskType(StringRef MaskType) {}
7210b57cec5SDimitry Andric 
7220b57cec5SDimitry Andric     // Scanf-specific handlers.
7230b57cec5SDimitry Andric 
7240b57cec5SDimitry Andric   virtual bool HandleInvalidScanfConversionSpecifier(
7250b57cec5SDimitry Andric                                         const analyze_scanf::ScanfSpecifier &FS,
7260b57cec5SDimitry Andric                                         const char *startSpecifier,
7270b57cec5SDimitry Andric                                         unsigned specifierLen) {
7280b57cec5SDimitry Andric     return true;
7290b57cec5SDimitry Andric   }
7300b57cec5SDimitry Andric 
7310b57cec5SDimitry Andric   virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
7320b57cec5SDimitry Andric                                     const char *startSpecifier,
7330b57cec5SDimitry Andric                                     unsigned specifierLen) {
7340b57cec5SDimitry Andric     return true;
7350b57cec5SDimitry Andric   }
7360b57cec5SDimitry Andric 
7370b57cec5SDimitry Andric   virtual void HandleIncompleteScanList(const char *start, const char *end) {}
7380b57cec5SDimitry Andric };
7390b57cec5SDimitry Andric 
7400b57cec5SDimitry Andric bool ParsePrintfString(FormatStringHandler &H,
7410b57cec5SDimitry Andric                        const char *beg, const char *end, const LangOptions &LO,
7420b57cec5SDimitry Andric                        const TargetInfo &Target, bool isFreeBSDKPrintf);
7430b57cec5SDimitry Andric 
7440b57cec5SDimitry Andric bool ParseFormatStringHasSArg(const char *beg, const char *end,
7450b57cec5SDimitry Andric                               const LangOptions &LO, const TargetInfo &Target);
7460b57cec5SDimitry Andric 
7470b57cec5SDimitry Andric bool ParseScanfString(FormatStringHandler &H,
7480b57cec5SDimitry Andric                       const char *beg, const char *end, const LangOptions &LO,
7490b57cec5SDimitry Andric                       const TargetInfo &Target);
7500b57cec5SDimitry Andric 
7510b57cec5SDimitry Andric } // end analyze_format_string namespace
7520b57cec5SDimitry Andric } // end clang namespace
7530b57cec5SDimitry Andric #endif
754