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