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 
1804eeddc0SDimitry Andric #ifndef LLVM_CLANG_AST_FORMATSTRING_H
1904eeddc0SDimitry Andric #define LLVM_CLANG_AST_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 
254a7dea167SDimitry Andric   /// How well a given conversion specifier matches its argument.
255a7dea167SDimitry Andric   enum MatchKind {
256a7dea167SDimitry Andric     /// The conversion specifier and the argument types are incompatible. For
257a7dea167SDimitry Andric     /// instance, "%d" and float.
258a7dea167SDimitry Andric     NoMatch = 0,
259a7dea167SDimitry Andric     /// The conversion specifier and the argument type are compatible. For
260a7dea167SDimitry Andric     /// instance, "%d" and _Bool.
261a7dea167SDimitry Andric     Match = 1,
262a7dea167SDimitry Andric     /// The conversion specifier and the argument type are disallowed by the C
263a7dea167SDimitry Andric     /// standard, but are in practice harmless. For instance, "%p" and int*.
264a7dea167SDimitry Andric     NoMatchPedantic,
265a7dea167SDimitry Andric     /// The conversion specifier and the argument type are compatible, but still
266a7dea167SDimitry Andric     /// seems likely to be an error. For instance, "%hd" and _Bool.
267a7dea167SDimitry Andric     NoMatchTypeConfusion,
268a7dea167SDimitry Andric   };
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric private:
2710b57cec5SDimitry Andric   const Kind K;
2720b57cec5SDimitry Andric   QualType T;
2730b57cec5SDimitry Andric   const char *Name = nullptr;
2740b57cec5SDimitry Andric   bool Ptr = false;
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric   /// The TypeKind identifies certain well-known types like size_t and
2770b57cec5SDimitry Andric   /// ptrdiff_t.
2780b57cec5SDimitry Andric   enum class TypeKind { DontCare, SizeT, PtrdiffT };
2790b57cec5SDimitry Andric   TypeKind TK = TypeKind::DontCare;
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric public:
2820b57cec5SDimitry Andric   ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
2830b57cec5SDimitry Andric   ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}
2840b57cec5SDimitry Andric   ArgType(CanQualType T) : K(SpecificTy), T(T) {}
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric   static ArgType Invalid() { return ArgType(InvalidTy); }
2870b57cec5SDimitry Andric   bool isValid() const { return K != InvalidTy; }
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric   bool isSizeT() const { return TK == TypeKind::SizeT; }
2900b57cec5SDimitry Andric 
2910b57cec5SDimitry Andric   bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric   /// Create an ArgType which corresponds to the type pointer to A.
2940b57cec5SDimitry Andric   static ArgType PtrTo(const ArgType& A) {
2950b57cec5SDimitry Andric     assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
2960b57cec5SDimitry Andric     ArgType Res = A;
2970b57cec5SDimitry Andric     Res.Ptr = true;
2980b57cec5SDimitry Andric     return Res;
2990b57cec5SDimitry Andric   }
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric   /// Create an ArgType which corresponds to the size_t/ssize_t type.
3020b57cec5SDimitry Andric   static ArgType makeSizeT(const ArgType &A) {
3030b57cec5SDimitry Andric     ArgType Res = A;
3040b57cec5SDimitry Andric     Res.TK = TypeKind::SizeT;
3050b57cec5SDimitry Andric     return Res;
3060b57cec5SDimitry Andric   }
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric   /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t
3090b57cec5SDimitry Andric   /// type.
3100b57cec5SDimitry Andric   static ArgType makePtrdiffT(const ArgType &A) {
3110b57cec5SDimitry Andric     ArgType Res = A;
3120b57cec5SDimitry Andric     Res.TK = TypeKind::PtrdiffT;
3130b57cec5SDimitry Andric     return Res;
3140b57cec5SDimitry Andric   }
3150b57cec5SDimitry Andric 
3160b57cec5SDimitry Andric   MatchKind matchesType(ASTContext &C, QualType argTy) const;
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric   QualType getRepresentativeType(ASTContext &C) const;
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric   ArgType makeVectorType(ASTContext &C, unsigned NumElts) const;
3210b57cec5SDimitry Andric 
3220b57cec5SDimitry Andric   std::string getRepresentativeTypeName(ASTContext &C) const;
3230b57cec5SDimitry Andric };
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric class OptionalAmount {
3260b57cec5SDimitry Andric public:
3270b57cec5SDimitry Andric   enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
3280b57cec5SDimitry Andric 
3290b57cec5SDimitry Andric   OptionalAmount(HowSpecified howSpecified,
3300b57cec5SDimitry Andric                  unsigned amount,
3310b57cec5SDimitry Andric                  const char *amountStart,
3320b57cec5SDimitry Andric                  unsigned amountLength,
3330b57cec5SDimitry Andric                  bool usesPositionalArg)
3340b57cec5SDimitry Andric   : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
33504eeddc0SDimitry Andric   UsesPositionalArg(usesPositionalArg), UsesDotPrefix(false) {}
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric   OptionalAmount(bool valid = true)
3380b57cec5SDimitry Andric   : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
33904eeddc0SDimitry Andric   UsesPositionalArg(false), UsesDotPrefix(false) {}
3400b57cec5SDimitry Andric 
3410b57cec5SDimitry Andric   explicit OptionalAmount(unsigned Amount)
3420b57cec5SDimitry Andric     : start(nullptr), length(0), hs(Constant), amt(Amount),
3430b57cec5SDimitry Andric     UsesPositionalArg(false), UsesDotPrefix(false) {}
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric   bool isInvalid() const {
3460b57cec5SDimitry Andric     return hs == Invalid;
3470b57cec5SDimitry Andric   }
3480b57cec5SDimitry Andric 
3490b57cec5SDimitry Andric   HowSpecified getHowSpecified() const { return hs; }
3500b57cec5SDimitry Andric   void setHowSpecified(HowSpecified h) { hs = h; }
3510b57cec5SDimitry Andric 
3520b57cec5SDimitry Andric   bool hasDataArgument() const { return hs == Arg; }
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric   unsigned getArgIndex() const {
3550b57cec5SDimitry Andric     assert(hasDataArgument());
3560b57cec5SDimitry Andric     return amt;
3570b57cec5SDimitry Andric   }
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric   unsigned getConstantAmount() const {
3600b57cec5SDimitry Andric     assert(hs == Constant);
3610b57cec5SDimitry Andric     return amt;
3620b57cec5SDimitry Andric   }
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric   const char *getStart() const {
3650b57cec5SDimitry Andric       // We include the . character if it is given.
3660b57cec5SDimitry Andric     return start - UsesDotPrefix;
3670b57cec5SDimitry Andric   }
3680b57cec5SDimitry Andric 
3690b57cec5SDimitry Andric   unsigned getConstantLength() const {
3700b57cec5SDimitry Andric     assert(hs == Constant);
3710b57cec5SDimitry Andric     return length + UsesDotPrefix;
3720b57cec5SDimitry Andric   }
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric   ArgType getArgType(ASTContext &Ctx) const;
3750b57cec5SDimitry Andric 
3760b57cec5SDimitry Andric   void toString(raw_ostream &os) const;
3770b57cec5SDimitry Andric 
3780b57cec5SDimitry Andric   bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
3790b57cec5SDimitry Andric   unsigned getPositionalArgIndex() const {
3800b57cec5SDimitry Andric     assert(hasDataArgument());
3810b57cec5SDimitry Andric     return amt + 1;
3820b57cec5SDimitry Andric   }
3830b57cec5SDimitry Andric 
3840b57cec5SDimitry Andric   bool usesDotPrefix() const { return UsesDotPrefix; }
3850b57cec5SDimitry Andric   void setUsesDotPrefix() { UsesDotPrefix = true; }
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric private:
3880b57cec5SDimitry Andric   const char *start;
3890b57cec5SDimitry Andric   unsigned length;
3900b57cec5SDimitry Andric   HowSpecified hs;
3910b57cec5SDimitry Andric   unsigned amt;
3920b57cec5SDimitry Andric   bool UsesPositionalArg : 1;
3930b57cec5SDimitry Andric   bool UsesDotPrefix;
3940b57cec5SDimitry Andric };
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric 
3970b57cec5SDimitry Andric class FormatSpecifier {
3980b57cec5SDimitry Andric protected:
3990b57cec5SDimitry Andric   LengthModifier LM;
4000b57cec5SDimitry Andric   OptionalAmount FieldWidth;
4010b57cec5SDimitry Andric   ConversionSpecifier CS;
4020b57cec5SDimitry Andric   OptionalAmount VectorNumElts;
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric   /// Positional arguments, an IEEE extension:
4050b57cec5SDimitry Andric   ///  IEEE Std 1003.1, 2004 Edition
4060b57cec5SDimitry Andric   ///  http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
4070b57cec5SDimitry Andric   bool UsesPositionalArg;
4080b57cec5SDimitry Andric   unsigned argIndex;
4090b57cec5SDimitry Andric public:
4100b57cec5SDimitry Andric   FormatSpecifier(bool isPrintf)
4110b57cec5SDimitry Andric     : CS(isPrintf), VectorNumElts(false),
4120b57cec5SDimitry Andric       UsesPositionalArg(false), argIndex(0) {}
4130b57cec5SDimitry Andric 
4140b57cec5SDimitry Andric   void setLengthModifier(LengthModifier lm) {
4150b57cec5SDimitry Andric     LM = lm;
4160b57cec5SDimitry Andric   }
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric   void setUsesPositionalArg() { UsesPositionalArg = true; }
4190b57cec5SDimitry Andric 
4200b57cec5SDimitry Andric   void setArgIndex(unsigned i) {
4210b57cec5SDimitry Andric     argIndex = i;
4220b57cec5SDimitry Andric   }
4230b57cec5SDimitry Andric 
4240b57cec5SDimitry Andric   unsigned getArgIndex() const {
4250b57cec5SDimitry Andric     return argIndex;
4260b57cec5SDimitry Andric   }
4270b57cec5SDimitry Andric 
4280b57cec5SDimitry Andric   unsigned getPositionalArgIndex() const {
4290b57cec5SDimitry Andric     return argIndex + 1;
4300b57cec5SDimitry Andric   }
4310b57cec5SDimitry Andric 
4320b57cec5SDimitry Andric   const LengthModifier &getLengthModifier() const {
4330b57cec5SDimitry Andric     return LM;
4340b57cec5SDimitry Andric   }
4350b57cec5SDimitry Andric 
4360b57cec5SDimitry Andric   const OptionalAmount &getFieldWidth() const {
4370b57cec5SDimitry Andric     return FieldWidth;
4380b57cec5SDimitry Andric   }
4390b57cec5SDimitry Andric 
4400b57cec5SDimitry Andric   void setVectorNumElts(const OptionalAmount &Amt) {
4410b57cec5SDimitry Andric     VectorNumElts = Amt;
4420b57cec5SDimitry Andric   }
4430b57cec5SDimitry Andric 
4440b57cec5SDimitry Andric   const OptionalAmount &getVectorNumElts() const {
4450b57cec5SDimitry Andric     return VectorNumElts;
4460b57cec5SDimitry Andric   }
4470b57cec5SDimitry Andric 
4480b57cec5SDimitry Andric   void setFieldWidth(const OptionalAmount &Amt) {
4490b57cec5SDimitry Andric     FieldWidth = Amt;
4500b57cec5SDimitry Andric   }
4510b57cec5SDimitry Andric 
4520b57cec5SDimitry Andric   bool usesPositionalArg() const { return UsesPositionalArg; }
4530b57cec5SDimitry Andric 
4540b57cec5SDimitry Andric   bool hasValidLengthModifier(const TargetInfo &Target,
4550b57cec5SDimitry Andric                               const LangOptions &LO) const;
4560b57cec5SDimitry Andric 
4570b57cec5SDimitry Andric   bool hasStandardLengthModifier() const;
4580b57cec5SDimitry Andric 
4590b57cec5SDimitry Andric   Optional<LengthModifier> getCorrectedLengthModifier() const;
4600b57cec5SDimitry Andric 
4610b57cec5SDimitry Andric   bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
4620b57cec5SDimitry Andric 
4630b57cec5SDimitry Andric   bool hasStandardLengthConversionCombination() const;
4640b57cec5SDimitry Andric 
4650b57cec5SDimitry Andric   /// For a TypedefType QT, if it is a named integer type such as size_t,
4660b57cec5SDimitry Andric   /// assign the appropriate value to LM and return true.
4670b57cec5SDimitry Andric   static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
4680b57cec5SDimitry Andric };
4690b57cec5SDimitry Andric 
4700b57cec5SDimitry Andric } // end analyze_format_string namespace
4710b57cec5SDimitry Andric 
4720b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4730b57cec5SDimitry Andric /// Pieces specific to fprintf format strings.
4740b57cec5SDimitry Andric 
4750b57cec5SDimitry Andric namespace analyze_printf {
4760b57cec5SDimitry Andric 
4770b57cec5SDimitry Andric class PrintfConversionSpecifier :
4780b57cec5SDimitry Andric   public analyze_format_string::ConversionSpecifier  {
4790b57cec5SDimitry Andric public:
4800b57cec5SDimitry Andric   PrintfConversionSpecifier()
4810b57cec5SDimitry Andric     : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
4820b57cec5SDimitry Andric 
4830b57cec5SDimitry Andric   PrintfConversionSpecifier(const char *pos, Kind k)
4840b57cec5SDimitry Andric     : ConversionSpecifier(true, pos, k) {}
4850b57cec5SDimitry Andric 
4860b57cec5SDimitry Andric   bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
4870b57cec5SDimitry Andric   bool isDoubleArg() const { return kind >= DoubleArgBeg &&
4880b57cec5SDimitry Andric                                     kind <= DoubleArgEnd; }
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric   static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
4910b57cec5SDimitry Andric     return CS->isPrintfKind();
4920b57cec5SDimitry Andric   }
4930b57cec5SDimitry Andric };
4940b57cec5SDimitry Andric 
4950b57cec5SDimitry Andric using analyze_format_string::ArgType;
4960b57cec5SDimitry Andric using analyze_format_string::LengthModifier;
4970b57cec5SDimitry Andric using analyze_format_string::OptionalAmount;
4980b57cec5SDimitry Andric using analyze_format_string::OptionalFlag;
4990b57cec5SDimitry Andric 
5000b57cec5SDimitry Andric class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
5010b57cec5SDimitry Andric   OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
5020b57cec5SDimitry Andric   OptionalFlag IsLeftJustified; // '-'
5030b57cec5SDimitry Andric   OptionalFlag HasPlusPrefix; // '+'
5040b57cec5SDimitry Andric   OptionalFlag HasSpacePrefix; // ' '
5050b57cec5SDimitry Andric   OptionalFlag HasAlternativeForm; // '#'
5060b57cec5SDimitry Andric   OptionalFlag HasLeadingZeroes; // '0'
5070b57cec5SDimitry Andric   OptionalFlag HasObjCTechnicalTerm; // '[tt]'
5080b57cec5SDimitry Andric   OptionalFlag IsPrivate;            // '{private}'
5090b57cec5SDimitry Andric   OptionalFlag IsPublic;             // '{public}'
5100b57cec5SDimitry Andric   OptionalFlag IsSensitive;          // '{sensitive}'
5110b57cec5SDimitry Andric   OptionalAmount Precision;
5120b57cec5SDimitry Andric   StringRef MaskType;
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric   ArgType getScalarArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
5150b57cec5SDimitry Andric 
5160b57cec5SDimitry Andric public:
5170b57cec5SDimitry Andric   PrintfSpecifier()
5180b57cec5SDimitry Andric       : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
5190b57cec5SDimitry Andric         IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
5200b57cec5SDimitry Andric         HasAlternativeForm("#"), HasLeadingZeroes("0"),
5210b57cec5SDimitry Andric         HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public"),
5220b57cec5SDimitry Andric         IsSensitive("sensitive") {}
5230b57cec5SDimitry Andric 
5240b57cec5SDimitry Andric   static PrintfSpecifier Parse(const char *beg, const char *end);
5250b57cec5SDimitry Andric 
5260b57cec5SDimitry Andric     // Methods for incrementally constructing the PrintfSpecifier.
5270b57cec5SDimitry Andric   void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
5280b57cec5SDimitry Andric     CS = cs;
5290b57cec5SDimitry Andric   }
5300b57cec5SDimitry Andric   void setHasThousandsGrouping(const char *position) {
5310b57cec5SDimitry Andric     HasThousandsGrouping.setPosition(position);
5320b57cec5SDimitry Andric   }
5330b57cec5SDimitry Andric   void setIsLeftJustified(const char *position) {
5340b57cec5SDimitry Andric     IsLeftJustified.setPosition(position);
5350b57cec5SDimitry Andric   }
5360b57cec5SDimitry Andric   void setHasPlusPrefix(const char *position) {
5370b57cec5SDimitry Andric     HasPlusPrefix.setPosition(position);
5380b57cec5SDimitry Andric   }
5390b57cec5SDimitry Andric   void setHasSpacePrefix(const char *position) {
5400b57cec5SDimitry Andric     HasSpacePrefix.setPosition(position);
5410b57cec5SDimitry Andric   }
5420b57cec5SDimitry Andric   void setHasAlternativeForm(const char *position) {
5430b57cec5SDimitry Andric     HasAlternativeForm.setPosition(position);
5440b57cec5SDimitry Andric   }
5450b57cec5SDimitry Andric   void setHasLeadingZeros(const char *position) {
5460b57cec5SDimitry Andric     HasLeadingZeroes.setPosition(position);
5470b57cec5SDimitry Andric   }
5480b57cec5SDimitry Andric   void setHasObjCTechnicalTerm(const char *position) {
5490b57cec5SDimitry Andric     HasObjCTechnicalTerm.setPosition(position);
5500b57cec5SDimitry Andric   }
5510b57cec5SDimitry Andric   void setIsPrivate(const char *position) { IsPrivate.setPosition(position); }
5520b57cec5SDimitry Andric   void setIsPublic(const char *position) { IsPublic.setPosition(position); }
5530b57cec5SDimitry Andric   void setIsSensitive(const char *position) {
5540b57cec5SDimitry Andric     IsSensitive.setPosition(position);
5550b57cec5SDimitry Andric   }
5560b57cec5SDimitry Andric   void setUsesPositionalArg() { UsesPositionalArg = true; }
5570b57cec5SDimitry Andric 
5580b57cec5SDimitry Andric     // Methods for querying the format specifier.
5590b57cec5SDimitry Andric 
5600b57cec5SDimitry Andric   const PrintfConversionSpecifier &getConversionSpecifier() const {
5610b57cec5SDimitry Andric     return cast<PrintfConversionSpecifier>(CS);
5620b57cec5SDimitry Andric   }
5630b57cec5SDimitry Andric 
5640b57cec5SDimitry Andric   void setPrecision(const OptionalAmount &Amt) {
5650b57cec5SDimitry Andric     Precision = Amt;
5660b57cec5SDimitry Andric     Precision.setUsesDotPrefix();
5670b57cec5SDimitry Andric   }
5680b57cec5SDimitry Andric 
5690b57cec5SDimitry Andric   const OptionalAmount &getPrecision() const {
5700b57cec5SDimitry Andric     return Precision;
5710b57cec5SDimitry Andric   }
5720b57cec5SDimitry Andric 
5730b57cec5SDimitry Andric   bool consumesDataArgument() const {
5740b57cec5SDimitry Andric     return getConversionSpecifier().consumesDataArgument();
5750b57cec5SDimitry Andric   }
5760b57cec5SDimitry Andric 
5770b57cec5SDimitry Andric   /// Returns the builtin type that a data argument
5780b57cec5SDimitry Andric   /// paired with this format specifier should have.  This method
5790b57cec5SDimitry Andric   /// will return null if the format specifier does not have
5800b57cec5SDimitry Andric   /// a matching data argument or the matching argument matches
5810b57cec5SDimitry Andric   /// more than one type.
5820b57cec5SDimitry Andric   ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
5830b57cec5SDimitry Andric 
5840b57cec5SDimitry Andric   const OptionalFlag &hasThousandsGrouping() const {
5850b57cec5SDimitry Andric       return HasThousandsGrouping;
5860b57cec5SDimitry Andric   }
5870b57cec5SDimitry Andric   const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
5880b57cec5SDimitry Andric   const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
5890b57cec5SDimitry Andric   const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
5900b57cec5SDimitry Andric   const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
5910b57cec5SDimitry Andric   const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
5920b57cec5SDimitry Andric   const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }
5930b57cec5SDimitry Andric   const OptionalFlag &isPrivate() const { return IsPrivate; }
5940b57cec5SDimitry Andric   const OptionalFlag &isPublic() const { return IsPublic; }
5950b57cec5SDimitry Andric   const OptionalFlag &isSensitive() const { return IsSensitive; }
5960b57cec5SDimitry Andric   bool usesPositionalArg() const { return UsesPositionalArg; }
5970b57cec5SDimitry Andric 
5980b57cec5SDimitry Andric   StringRef getMaskType() const { return MaskType; }
5990b57cec5SDimitry Andric   void setMaskType(StringRef S) { MaskType = S; }
6000b57cec5SDimitry Andric 
6010b57cec5SDimitry Andric   /// Changes the specifier and length according to a QualType, retaining any
6020b57cec5SDimitry Andric   /// flags or options. Returns true on success, or false when a conversion
6030b57cec5SDimitry Andric   /// was not successful.
6040b57cec5SDimitry Andric   bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
6050b57cec5SDimitry Andric                bool IsObjCLiteral);
6060b57cec5SDimitry Andric 
6070b57cec5SDimitry Andric   void toString(raw_ostream &os) const;
6080b57cec5SDimitry Andric 
6090b57cec5SDimitry Andric   // Validation methods - to check if any element results in undefined behavior
6100b57cec5SDimitry Andric   bool hasValidPlusPrefix() const;
6110b57cec5SDimitry Andric   bool hasValidAlternativeForm() const;
6120b57cec5SDimitry Andric   bool hasValidLeadingZeros() const;
6130b57cec5SDimitry Andric   bool hasValidSpacePrefix() const;
6140b57cec5SDimitry Andric   bool hasValidLeftJustified() const;
6150b57cec5SDimitry Andric   bool hasValidThousandsGroupingPrefix() const;
6160b57cec5SDimitry Andric 
6170b57cec5SDimitry Andric   bool hasValidPrecision() const;
6180b57cec5SDimitry Andric   bool hasValidFieldWidth() const;
6190b57cec5SDimitry Andric };
6200b57cec5SDimitry Andric }  // end analyze_printf namespace
6210b57cec5SDimitry Andric 
6220b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
6230b57cec5SDimitry Andric /// Pieces specific to fscanf format strings.
6240b57cec5SDimitry Andric 
6250b57cec5SDimitry Andric namespace analyze_scanf {
6260b57cec5SDimitry Andric 
6270b57cec5SDimitry Andric class ScanfConversionSpecifier :
6280b57cec5SDimitry Andric     public analyze_format_string::ConversionSpecifier  {
6290b57cec5SDimitry Andric public:
6300b57cec5SDimitry Andric   ScanfConversionSpecifier()
6310b57cec5SDimitry Andric     : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
6320b57cec5SDimitry Andric 
6330b57cec5SDimitry Andric   ScanfConversionSpecifier(const char *pos, Kind k)
6340b57cec5SDimitry Andric     : ConversionSpecifier(false, pos, k) {}
6350b57cec5SDimitry Andric 
6360b57cec5SDimitry Andric   static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
6370b57cec5SDimitry Andric     return !CS->isPrintfKind();
6380b57cec5SDimitry Andric   }
6390b57cec5SDimitry Andric };
6400b57cec5SDimitry Andric 
6410b57cec5SDimitry Andric using analyze_format_string::ArgType;
6420b57cec5SDimitry Andric using analyze_format_string::LengthModifier;
6430b57cec5SDimitry Andric using analyze_format_string::OptionalAmount;
6440b57cec5SDimitry Andric using analyze_format_string::OptionalFlag;
6450b57cec5SDimitry Andric 
6460b57cec5SDimitry Andric class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
6470b57cec5SDimitry Andric   OptionalFlag SuppressAssignment; // '*'
6480b57cec5SDimitry Andric public:
6490b57cec5SDimitry Andric   ScanfSpecifier() :
6500b57cec5SDimitry Andric     FormatSpecifier(/* isPrintf = */ false),
6510b57cec5SDimitry Andric     SuppressAssignment("*") {}
6520b57cec5SDimitry Andric 
6530b57cec5SDimitry Andric   void setSuppressAssignment(const char *position) {
6540b57cec5SDimitry Andric     SuppressAssignment.setPosition(position);
6550b57cec5SDimitry Andric   }
6560b57cec5SDimitry Andric 
6570b57cec5SDimitry Andric   const OptionalFlag &getSuppressAssignment() const {
6580b57cec5SDimitry Andric     return SuppressAssignment;
6590b57cec5SDimitry Andric   }
6600b57cec5SDimitry Andric 
6610b57cec5SDimitry Andric   void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
6620b57cec5SDimitry Andric     CS = cs;
6630b57cec5SDimitry Andric   }
6640b57cec5SDimitry Andric 
6650b57cec5SDimitry Andric   const ScanfConversionSpecifier &getConversionSpecifier() const {
6660b57cec5SDimitry Andric     return cast<ScanfConversionSpecifier>(CS);
6670b57cec5SDimitry Andric   }
6680b57cec5SDimitry Andric 
6690b57cec5SDimitry Andric   bool consumesDataArgument() const {
6700b57cec5SDimitry Andric     return CS.consumesDataArgument() && !SuppressAssignment;
6710b57cec5SDimitry Andric   }
6720b57cec5SDimitry Andric 
6730b57cec5SDimitry Andric   ArgType getArgType(ASTContext &Ctx) const;
6740b57cec5SDimitry Andric 
6750b57cec5SDimitry Andric   bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
6760b57cec5SDimitry Andric                ASTContext &Ctx);
6770b57cec5SDimitry Andric 
6780b57cec5SDimitry Andric   void toString(raw_ostream &os) const;
6790b57cec5SDimitry Andric 
6800b57cec5SDimitry Andric   static ScanfSpecifier Parse(const char *beg, const char *end);
6810b57cec5SDimitry Andric };
6820b57cec5SDimitry Andric 
6830b57cec5SDimitry Andric } // end analyze_scanf namespace
6840b57cec5SDimitry Andric 
6850b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
6860b57cec5SDimitry Andric // Parsing and processing of format strings (both fprintf and fscanf).
6870b57cec5SDimitry Andric 
6880b57cec5SDimitry Andric namespace analyze_format_string {
6890b57cec5SDimitry Andric 
6900b57cec5SDimitry Andric enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric class FormatStringHandler {
6930b57cec5SDimitry Andric public:
6940b57cec5SDimitry Andric   FormatStringHandler() {}
6950b57cec5SDimitry Andric   virtual ~FormatStringHandler();
6960b57cec5SDimitry Andric 
6970b57cec5SDimitry Andric   virtual void HandleNullChar(const char *nullCharacter) {}
6980b57cec5SDimitry Andric 
6990b57cec5SDimitry Andric   virtual void HandlePosition(const char *startPos, unsigned posLen) {}
7000b57cec5SDimitry Andric 
7010b57cec5SDimitry Andric   virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
7020b57cec5SDimitry Andric                                      PositionContext p) {}
7030b57cec5SDimitry Andric 
7040b57cec5SDimitry Andric   virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
7050b57cec5SDimitry Andric 
7060b57cec5SDimitry Andric   virtual void HandleIncompleteSpecifier(const char *startSpecifier,
7070b57cec5SDimitry Andric                                          unsigned specifierLen) {}
7080b57cec5SDimitry Andric 
7090b57cec5SDimitry Andric   virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
7100b57cec5SDimitry Andric                                            unsigned flagsLen) {}
7110b57cec5SDimitry Andric 
7120b57cec5SDimitry Andric   virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
7130b57cec5SDimitry Andric                                              unsigned flagLen) {}
7140b57cec5SDimitry Andric 
7150b57cec5SDimitry Andric   virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
7160b57cec5SDimitry Andric                                             const char *flagsEnd,
7170b57cec5SDimitry Andric                                             const char *conversionPosition) {}
7180b57cec5SDimitry Andric   // Printf-specific handlers.
7190b57cec5SDimitry Andric 
7200b57cec5SDimitry Andric   virtual bool HandleInvalidPrintfConversionSpecifier(
7210b57cec5SDimitry Andric                                       const analyze_printf::PrintfSpecifier &FS,
7220b57cec5SDimitry Andric                                       const char *startSpecifier,
7230b57cec5SDimitry Andric                                       unsigned specifierLen) {
7240b57cec5SDimitry Andric     return true;
7250b57cec5SDimitry Andric   }
7260b57cec5SDimitry Andric 
7270b57cec5SDimitry Andric   virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
7280b57cec5SDimitry Andric                                      const char *startSpecifier,
72904eeddc0SDimitry Andric                                      unsigned specifierLen,
73004eeddc0SDimitry Andric                                      const TargetInfo &Target) {
7310b57cec5SDimitry Andric     return true;
7320b57cec5SDimitry Andric   }
7330b57cec5SDimitry Andric 
7340b57cec5SDimitry Andric   /// Handle mask types whose sizes are not between one and eight bytes.
7350b57cec5SDimitry Andric   virtual void handleInvalidMaskType(StringRef MaskType) {}
7360b57cec5SDimitry Andric 
7370b57cec5SDimitry Andric     // Scanf-specific handlers.
7380b57cec5SDimitry Andric 
7390b57cec5SDimitry Andric   virtual bool HandleInvalidScanfConversionSpecifier(
7400b57cec5SDimitry Andric                                         const analyze_scanf::ScanfSpecifier &FS,
7410b57cec5SDimitry Andric                                         const char *startSpecifier,
7420b57cec5SDimitry Andric                                         unsigned specifierLen) {
7430b57cec5SDimitry Andric     return true;
7440b57cec5SDimitry Andric   }
7450b57cec5SDimitry Andric 
7460b57cec5SDimitry Andric   virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
7470b57cec5SDimitry Andric                                     const char *startSpecifier,
7480b57cec5SDimitry Andric                                     unsigned specifierLen) {
7490b57cec5SDimitry Andric     return true;
7500b57cec5SDimitry Andric   }
7510b57cec5SDimitry Andric 
7520b57cec5SDimitry Andric   virtual void HandleIncompleteScanList(const char *start, const char *end) {}
7530b57cec5SDimitry Andric };
7540b57cec5SDimitry Andric 
7550b57cec5SDimitry Andric bool ParsePrintfString(FormatStringHandler &H,
7560b57cec5SDimitry Andric                        const char *beg, const char *end, const LangOptions &LO,
7570b57cec5SDimitry Andric                        const TargetInfo &Target, bool isFreeBSDKPrintf);
7580b57cec5SDimitry Andric 
7590b57cec5SDimitry Andric bool ParseFormatStringHasSArg(const char *beg, const char *end,
7600b57cec5SDimitry Andric                               const LangOptions &LO, const TargetInfo &Target);
7610b57cec5SDimitry Andric 
7620b57cec5SDimitry Andric bool ParseScanfString(FormatStringHandler &H,
7630b57cec5SDimitry Andric                       const char *beg, const char *end, const LangOptions &LO,
7640b57cec5SDimitry Andric                       const TargetInfo &Target);
7650b57cec5SDimitry Andric 
766a7dea167SDimitry Andric /// Return true if the given string has at least one formatting specifier.
767a7dea167SDimitry Andric bool parseFormatStringHasFormattingSpecifiers(const char *Begin,
768a7dea167SDimitry Andric                                               const char *End,
769a7dea167SDimitry Andric                                               const LangOptions &LO,
770a7dea167SDimitry Andric                                               const TargetInfo &Target);
771a7dea167SDimitry Andric 
7720b57cec5SDimitry Andric } // end analyze_format_string namespace
7730b57cec5SDimitry Andric } // end clang namespace
7740b57cec5SDimitry Andric #endif
775