//= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
//
 
// This file defines APIs for analyzing the format strings of printf, fscanf,
 
// and friends.
 
//
 
// The structure of format strings for fprintf are described in C99 7.19.6.1.
 
//
 
// The structure of format strings for fscanf are described in C99 7.19.6.2.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_AST_FORMATSTRING_H
 
#define LLVM_CLANG_AST_FORMATSTRING_H
 
 
 
#include "clang/AST/CanonicalType.h"
 
#include <optional>
 
 
 
namespace clang {
 
 
 
class TargetInfo;
 
 
 
//===----------------------------------------------------------------------===//
 
/// Common components of both fprintf and fscanf format strings.
 
namespace analyze_format_string {
 
 
 
/// Class representing optional flags with location and representation
 
/// information.
 
class OptionalFlag {
 
public:
 
  OptionalFlag(const char *Representation)
 
      : representation(Representation), flag(false) {}
 
  bool isSet() const { return flag; }
 
  void set() { flag = true; }
 
  void clear() { flag = false; }
 
  void setPosition(const char *position) {
 
    assert(position);
 
    flag = true;
 
    this->position = position;
 
  }
 
  const char *getPosition() const {
 
    assert(position);
 
    return position;
 
  }
 
  const char *toString() const { return representation; }
 
 
 
  // Overloaded operators for bool like qualities
 
  explicit operator bool() const { return flag; }
 
  OptionalFlag& operator=(const bool &rhs) {
 
    flag = rhs;
 
    return *this;  // Return a reference to myself.
 
  }
 
private:
 
  const char *representation;
 
  const char *position;
 
  bool flag;
 
};
 
 
 
/// Represents the length modifier in a format string in scanf/printf.
 
class LengthModifier {
 
public:
 
  enum Kind {
 
    None,
 
    AsChar,       // 'hh'
 
    AsShort,      // 'h'
 
    AsShortLong,  // 'hl' (OpenCL float/int vector element)
 
    AsLong,       // 'l'
 
    AsLongLong,   // 'll'
 
    AsQuad,       // 'q' (BSD, deprecated, for 64-bit integer types)
 
    AsIntMax,     // 'j'
 
    AsSizeT,      // 'z'
 
    AsPtrDiff,    // 't'
 
    AsInt32,      // 'I32' (MSVCRT, like __int32)
 
    AsInt3264,    // 'I'   (MSVCRT, like __int3264 from MIDL)
 
    AsInt64,      // 'I64' (MSVCRT, like __int64)
 
    AsLongDouble, // 'L'
 
    AsAllocate,   // for '%as', GNU extension to C90 scanf
 
    AsMAllocate,  // for '%ms', GNU extension to scanf
 
    AsWide,       // 'w' (MSVCRT, like l but only for c, C, s, S, or Z
 
    AsWideChar = AsLong // for '%ls', only makes sense for printf
 
  };
 
 
 
  LengthModifier()
 
    : Position(nullptr), kind(None) {}
 
  LengthModifier(const char *pos, Kind k)
 
    : Position(pos), kind(k) {}
 
 
 
  const char *getStart() const {
 
    return Position;
 
  }
 
 
 
  unsigned getLength() const {
 
    switch (kind) {
 
      default:
 
        return 1;
 
      case AsLongLong:
 
      case AsChar:
 
        return 2;
 
      case AsInt32:
 
      case AsInt64:
 
        return 3;
 
      case None:
 
        return 0;
 
    }
 
  }
 
 
 
  Kind getKind() const { return kind; }
 
  void setKind(Kind k) { kind = k; }
 
 
 
  const char *toString() const;
 
 
 
private:
 
  const char *Position;
 
  Kind kind;
 
};
 
 
 
class ConversionSpecifier {
 
public:
 
  enum Kind {
 
    InvalidSpecifier = 0,
 
    // C99 conversion specifiers.
 
    cArg,
 
    dArg,
 
    DArg, // Apple extension
 
    iArg,
 
    // C23 conversion specifiers.
 
    bArg,
 
    BArg,
 
 
 
    IntArgBeg = dArg,
 
    IntArgEnd = BArg,
 
 
 
    oArg,
 
    OArg, // Apple extension
 
    uArg,
 
    UArg, // Apple extension
 
    xArg,
 
    XArg,
 
    UIntArgBeg = oArg,
 
    UIntArgEnd = XArg,
 
 
 
    fArg,
 
    FArg,
 
    eArg,
 
    EArg,
 
    gArg,
 
    GArg,
 
    aArg,
 
    AArg,
 
    DoubleArgBeg = fArg,
 
    DoubleArgEnd = AArg,
 
 
 
    sArg,
 
    pArg,
 
    nArg,
 
    PercentArg,
 
    CArg,
 
    SArg,
 
 
 
    // Apple extension: P specifies to os_log that the data being pointed to is
 
    // to be copied by os_log. The precision indicates the number of bytes to
 
    // copy.
 
    PArg,
 
 
 
    // ** Printf-specific **
 
 
 
    ZArg, // MS extension
 
 
 
    // Objective-C specific specifiers.
 
    ObjCObjArg, // '@'
 
    ObjCBeg = ObjCObjArg,
 
    ObjCEnd = ObjCObjArg,
 
 
 
    // FreeBSD kernel specific specifiers.
 
    FreeBSDbArg,
 
    FreeBSDDArg,
 
    FreeBSDrArg,
 
    FreeBSDyArg,
 
 
 
    // GlibC specific specifiers.
 
    PrintErrno, // 'm'
 
 
 
    PrintfConvBeg = ObjCObjArg,
 
    PrintfConvEnd = PrintErrno,
 
 
 
    // ** Scanf-specific **
 
    ScanListArg, // '['
 
    ScanfConvBeg = ScanListArg,
 
    ScanfConvEnd = ScanListArg
 
  };
 
 
 
  ConversionSpecifier(bool isPrintf = true)
 
    : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
 
      kind(InvalidSpecifier) {}
 
 
 
  ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
 
    : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
 
 
 
  const char *getStart() const {
 
    return Position;
 
  }
 
 
 
  StringRef getCharacters() const {
 
    return StringRef(getStart(), getLength());
 
  }
 
 
 
  bool consumesDataArgument() const {
 
    switch (kind) {
 
      case PrintErrno:
 
        assert(IsPrintf);
 
        return false;
 
      case PercentArg:
 
        return false;
 
      case InvalidSpecifier:
 
        return false;
 
      default:
 
        return true;
 
    }
 
  }
 
 
 
  Kind getKind() const { return kind; }
 
  void setKind(Kind k) { kind = k; }
 
  unsigned getLength() const {
 
    return EndScanList ? EndScanList - Position : 1;
 
  }
 
  void setEndScanList(const char *pos) { EndScanList = pos; }
 
 
 
  bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
 
    kind == FreeBSDrArg || kind == FreeBSDyArg; }
 
  bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
 
  bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
 
  bool isDoubleArg() const {
 
    return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
 
  }
 
 
 
  const char *toString() const;
 
 
 
  bool isPrintfKind() const { return IsPrintf; }
 
 
 
  std::optional<ConversionSpecifier> getStandardSpecifier() const;
 
 
 
protected:
 
  bool IsPrintf;
 
  const char *Position;
 
  const char *EndScanList;
 
  Kind kind;
 
};
 
 
 
class ArgType {
 
public:
 
  enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
 
              AnyCharTy, CStrTy, WCStrTy, WIntTy };
 
 
 
  /// How well a given conversion specifier matches its argument.
 
  enum MatchKind {
 
    /// The conversion specifier and the argument types are incompatible. For
 
    /// instance, "%d" and float.
 
    NoMatch = 0,
 
    /// The conversion specifier and the argument type are compatible. For
 
    /// instance, "%d" and int.
 
    Match = 1,
 
    /// The conversion specifier and the argument type are compatible because of
 
    /// default argument promotions. For instance, "%hhd" and int.
 
    MatchPromotion,
 
    /// The conversion specifier and the argument type are compatible but still
 
    /// seems likely to be an error. For instanace, "%hhd" and short.
 
    NoMatchPromotionTypeConfusion,
 
    /// The conversion specifier and the argument type are disallowed by the C
 
    /// standard, but are in practice harmless. For instance, "%p" and int*.
 
    NoMatchPedantic,
 
    /// The conversion specifier and the argument type are compatible, but still
 
    /// seems likely to be an error. For instance, "%hd" and _Bool.
 
    NoMatchTypeConfusion,
 
  };
 
 
 
private:
 
  const Kind K;
 
  QualType T;
 
  const char *Name = nullptr;
 
  bool Ptr = false;
 
 
 
  /// The TypeKind identifies certain well-known types like size_t and
 
  /// ptrdiff_t.
 
  enum class TypeKind { DontCare, SizeT, PtrdiffT };
 
  TypeKind TK = TypeKind::DontCare;
 
 
 
public:
 
  ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
 
  ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}
 
  ArgType(CanQualType T) : K(SpecificTy), T(T) {}
 
 
 
  static ArgType Invalid() { return ArgType(InvalidTy); }
 
  bool isValid() const { return K != InvalidTy; }
 
 
 
  bool isSizeT() const { return TK == TypeKind::SizeT; }
 
 
 
  bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }
 
 
 
  /// Create an ArgType which corresponds to the type pointer to A.
 
  static ArgType PtrTo(const ArgType& A) {
 
    assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
 
    ArgType Res = A;
 
    Res.Ptr = true;
 
    return Res;
 
  }
 
 
 
  /// Create an ArgType which corresponds to the size_t/ssize_t type.
 
  static ArgType makeSizeT(const ArgType &A) {
 
    ArgType Res = A;
 
    Res.TK = TypeKind::SizeT;
 
    return Res;
 
  }
 
 
 
  /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t
 
  /// type.
 
  static ArgType makePtrdiffT(const ArgType &A) {
 
    ArgType Res = A;
 
    Res.TK = TypeKind::PtrdiffT;
 
    return Res;
 
  }
 
 
 
  MatchKind matchesType(ASTContext &C, QualType argTy) const;
 
 
 
  QualType getRepresentativeType(ASTContext &C) const;
 
 
 
  ArgType makeVectorType(ASTContext &C, unsigned NumElts) const;
 
 
 
  std::string getRepresentativeTypeName(ASTContext &C) const;
 
};
 
 
 
class OptionalAmount {
 
public:
 
  enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
 
 
 
  OptionalAmount(HowSpecified howSpecified,
 
                 unsigned amount,
 
                 const char *amountStart,
 
                 unsigned amountLength,
 
                 bool usesPositionalArg)
 
  : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
 
  UsesPositionalArg(usesPositionalArg), UsesDotPrefix(false) {}
 
 
 
  OptionalAmount(bool valid = true)
 
  : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
 
  UsesPositionalArg(false), UsesDotPrefix(false) {}
 
 
 
  explicit OptionalAmount(unsigned Amount)
 
    : start(nullptr), length(0), hs(Constant), amt(Amount),
 
    UsesPositionalArg(false), UsesDotPrefix(false) {}
 
 
 
  bool isInvalid() const {
 
    return hs == Invalid;
 
  }
 
 
 
  HowSpecified getHowSpecified() const { return hs; }
 
  void setHowSpecified(HowSpecified h) { hs = h; }
 
 
 
  bool hasDataArgument() const { return hs == Arg; }
 
 
 
  unsigned getArgIndex() const {
 
    assert(hasDataArgument());
 
    return amt;
 
  }
 
 
 
  unsigned getConstantAmount() const {
 
    assert(hs == Constant);
 
    return amt;
 
  }
 
 
 
  const char *getStart() const {
 
      // We include the . character if it is given.
 
    return start - UsesDotPrefix;
 
  }
 
 
 
  unsigned getConstantLength() const {
 
    assert(hs == Constant);
 
    return length + UsesDotPrefix;
 
  }
 
 
 
  ArgType getArgType(ASTContext &Ctx) const;
 
 
 
  void toString(raw_ostream &os) const;
 
 
 
  bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
 
  unsigned getPositionalArgIndex() const {
 
    assert(hasDataArgument());
 
    return amt + 1;
 
  }
 
 
 
  bool usesDotPrefix() const { return UsesDotPrefix; }
 
  void setUsesDotPrefix() { UsesDotPrefix = true; }
 
 
 
private:
 
  const char *start;
 
  unsigned length;
 
  HowSpecified hs;
 
  unsigned amt;
 
  bool UsesPositionalArg : 1;
 
  bool UsesDotPrefix;
 
};
 
 
 
 
 
class FormatSpecifier {
 
protected:
 
  LengthModifier LM;
 
  OptionalAmount FieldWidth;
 
  ConversionSpecifier CS;
 
  OptionalAmount VectorNumElts;
 
 
 
  /// Positional arguments, an IEEE extension:
 
  ///  IEEE Std 1003.1, 2004 Edition
 
  ///  http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
 
  bool UsesPositionalArg;
 
  unsigned argIndex;
 
public:
 
  FormatSpecifier(bool isPrintf)
 
    : CS(isPrintf), VectorNumElts(false),
 
      UsesPositionalArg(false), argIndex(0) {}
 
 
 
  void setLengthModifier(LengthModifier lm) {
 
    LM = lm;
 
  }
 
 
 
  void setUsesPositionalArg() { UsesPositionalArg = true; }
 
 
 
  void setArgIndex(unsigned i) {
 
    argIndex = i;
 
  }
 
 
 
  unsigned getArgIndex() const {
 
    return argIndex;
 
  }
 
 
 
  unsigned getPositionalArgIndex() const {
 
    return argIndex + 1;
 
  }
 
 
 
  const LengthModifier &getLengthModifier() const {
 
    return LM;
 
  }
 
 
 
  const OptionalAmount &getFieldWidth() const {
 
    return FieldWidth;
 
  }
 
 
 
  void setVectorNumElts(const OptionalAmount &Amt) {
 
    VectorNumElts = Amt;
 
  }
 
 
 
  const OptionalAmount &getVectorNumElts() const {
 
    return VectorNumElts;
 
  }
 
 
 
  void setFieldWidth(const OptionalAmount &Amt) {
 
    FieldWidth = Amt;
 
  }
 
 
 
  bool usesPositionalArg() const { return UsesPositionalArg; }
 
 
 
  bool hasValidLengthModifier(const TargetInfo &Target,
 
                              const LangOptions &LO) const;
 
 
 
  bool hasStandardLengthModifier() const;
 
 
 
  std::optional<LengthModifier> getCorrectedLengthModifier() const;
 
 
 
  bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
 
 
 
  bool hasStandardLengthConversionCombination() const;
 
 
 
  /// For a TypedefType QT, if it is a named integer type such as size_t,
 
  /// assign the appropriate value to LM and return true.
 
  static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
 
};
 
 
 
} // end analyze_format_string namespace
 
 
 
//===----------------------------------------------------------------------===//
 
/// Pieces specific to fprintf format strings.
 
 
 
namespace analyze_printf {
 
 
 
class PrintfConversionSpecifier :
 
  public analyze_format_string::ConversionSpecifier  {
 
public:
 
  PrintfConversionSpecifier()
 
    : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
 
 
 
  PrintfConversionSpecifier(const char *pos, Kind k)
 
    : ConversionSpecifier(true, pos, k) {}
 
 
 
  bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
 
  bool isDoubleArg() const { return kind >= DoubleArgBeg &&
 
                                    kind <= DoubleArgEnd; }
 
 
 
  static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
 
    return CS->isPrintfKind();
 
  }
 
};
 
 
 
using analyze_format_string::ArgType;
 
using analyze_format_string::LengthModifier;
 
using analyze_format_string::OptionalAmount;
 
using analyze_format_string::OptionalFlag;
 
 
 
class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
 
  OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
 
  OptionalFlag IsLeftJustified; // '-'
 
  OptionalFlag HasPlusPrefix; // '+'
 
  OptionalFlag HasSpacePrefix; // ' '
 
  OptionalFlag HasAlternativeForm; // '#'
 
  OptionalFlag HasLeadingZeroes; // '0'
 
  OptionalFlag HasObjCTechnicalTerm; // '[tt]'
 
  OptionalFlag IsPrivate;            // '{private}'
 
  OptionalFlag IsPublic;             // '{public}'
 
  OptionalFlag IsSensitive;          // '{sensitive}'
 
  OptionalAmount Precision;
 
  StringRef MaskType;
 
 
 
  ArgType getScalarArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
 
 
 
public:
 
  PrintfSpecifier()
 
      : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
 
        IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
 
        HasAlternativeForm("#"), HasLeadingZeroes("0"),
 
        HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public"),
 
        IsSensitive("sensitive") {}
 
 
 
  static PrintfSpecifier Parse(const char *beg, const char *end);
 
 
 
    // Methods for incrementally constructing the PrintfSpecifier.
 
  void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
 
    CS = cs;
 
  }
 
  void setHasThousandsGrouping(const char *position) {
 
    HasThousandsGrouping.setPosition(position);
 
  }
 
  void setIsLeftJustified(const char *position) {
 
    IsLeftJustified.setPosition(position);
 
  }
 
  void setHasPlusPrefix(const char *position) {
 
    HasPlusPrefix.setPosition(position);
 
  }
 
  void setHasSpacePrefix(const char *position) {
 
    HasSpacePrefix.setPosition(position);
 
  }
 
  void setHasAlternativeForm(const char *position) {
 
    HasAlternativeForm.setPosition(position);
 
  }
 
  void setHasLeadingZeros(const char *position) {
 
    HasLeadingZeroes.setPosition(position);
 
  }
 
  void setHasObjCTechnicalTerm(const char *position) {
 
    HasObjCTechnicalTerm.setPosition(position);
 
  }
 
  void setIsPrivate(const char *position) { IsPrivate.setPosition(position); }
 
  void setIsPublic(const char *position) { IsPublic.setPosition(position); }
 
  void setIsSensitive(const char *position) {
 
    IsSensitive.setPosition(position);
 
  }
 
  void setUsesPositionalArg() { UsesPositionalArg = true; }
 
 
 
    // Methods for querying the format specifier.
 
 
 
  const PrintfConversionSpecifier &getConversionSpecifier() const {
 
    return cast<PrintfConversionSpecifier>(CS);
 
  }
 
 
 
  void setPrecision(const OptionalAmount &Amt) {
 
    Precision = Amt;
 
    Precision.setUsesDotPrefix();
 
  }
 
 
 
  const OptionalAmount &getPrecision() const {
 
    return Precision;
 
  }
 
 
 
  bool consumesDataArgument() const {
 
    return getConversionSpecifier().consumesDataArgument();
 
  }
 
 
 
  /// Returns the builtin type that a data argument
 
  /// paired with this format specifier should have.  This method
 
  /// will return null if the format specifier does not have
 
  /// a matching data argument or the matching argument matches
 
  /// more than one type.
 
  ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
 
 
 
  const OptionalFlag &hasThousandsGrouping() const {
 
      return HasThousandsGrouping;
 
  }
 
  const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
 
  const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
 
  const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
 
  const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
 
  const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
 
  const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }
 
  const OptionalFlag &isPrivate() const { return IsPrivate; }
 
  const OptionalFlag &isPublic() const { return IsPublic; }
 
  const OptionalFlag &isSensitive() const { return IsSensitive; }
 
  bool usesPositionalArg() const { return UsesPositionalArg; }
 
 
 
  StringRef getMaskType() const { return MaskType; }
 
  void setMaskType(StringRef S) { MaskType = S; }
 
 
 
  /// Changes the specifier and length according to a QualType, retaining any
 
  /// flags or options. Returns true on success, or false when a conversion
 
  /// was not successful.
 
  bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
 
               bool IsObjCLiteral);
 
 
 
  void toString(raw_ostream &os) const;
 
 
 
  // Validation methods - to check if any element results in undefined behavior
 
  bool hasValidPlusPrefix() const;
 
  bool hasValidAlternativeForm() const;
 
  bool hasValidLeadingZeros() const;
 
  bool hasValidSpacePrefix() const;
 
  bool hasValidLeftJustified() const;
 
  bool hasValidThousandsGroupingPrefix() const;
 
 
 
  bool hasValidPrecision() const;
 
  bool hasValidFieldWidth() const;
 
};
 
}  // end analyze_printf namespace
 
 
 
//===----------------------------------------------------------------------===//
 
/// Pieces specific to fscanf format strings.
 
 
 
namespace analyze_scanf {
 
 
 
class ScanfConversionSpecifier :
 
    public analyze_format_string::ConversionSpecifier  {
 
public:
 
  ScanfConversionSpecifier()
 
    : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
 
 
 
  ScanfConversionSpecifier(const char *pos, Kind k)
 
    : ConversionSpecifier(false, pos, k) {}
 
 
 
  static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
 
    return !CS->isPrintfKind();
 
  }
 
};
 
 
 
using analyze_format_string::ArgType;
 
using analyze_format_string::LengthModifier;
 
using analyze_format_string::OptionalAmount;
 
using analyze_format_string::OptionalFlag;
 
 
 
class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
 
  OptionalFlag SuppressAssignment; // '*'
 
public:
 
  ScanfSpecifier() :
 
    FormatSpecifier(/* isPrintf = */ false),
 
    SuppressAssignment("*") {}
 
 
 
  void setSuppressAssignment(const char *position) {
 
    SuppressAssignment.setPosition(position);
 
  }
 
 
 
  const OptionalFlag &getSuppressAssignment() const {
 
    return SuppressAssignment;
 
  }
 
 
 
  void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
 
    CS = cs;
 
  }
 
 
 
  const ScanfConversionSpecifier &getConversionSpecifier() const {
 
    return cast<ScanfConversionSpecifier>(CS);
 
  }
 
 
 
  bool consumesDataArgument() const {
 
    return CS.consumesDataArgument() && !SuppressAssignment;
 
  }
 
 
 
  ArgType getArgType(ASTContext &Ctx) const;
 
 
 
  bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
 
               ASTContext &Ctx);
 
 
 
  void toString(raw_ostream &os) const;
 
 
 
  static ScanfSpecifier Parse(const char *beg, const char *end);
 
};
 
 
 
} // end analyze_scanf namespace
 
 
 
//===----------------------------------------------------------------------===//
 
// Parsing and processing of format strings (both fprintf and fscanf).
 
 
 
namespace analyze_format_string {
 
 
 
enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
 
 
 
class FormatStringHandler {
 
public:
 
  FormatStringHandler() {}
 
  virtual ~FormatStringHandler();
 
 
 
  virtual void HandleNullChar(const char *nullCharacter) {}
 
 
 
  virtual void HandlePosition(const char *startPos, unsigned posLen) {}
 
 
 
  virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
 
                                     PositionContext p) {}
 
 
 
  virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
 
 
 
  virtual void HandleIncompleteSpecifier(const char *startSpecifier,
 
                                         unsigned specifierLen) {}
 
 
 
  virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
 
                                           unsigned flagsLen) {}
 
 
 
  virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
 
                                             unsigned flagLen) {}
 
 
 
  virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
 
                                            const char *flagsEnd,
 
                                            const char *conversionPosition) {}
 
  // Printf-specific handlers.
 
 
 
  virtual bool HandleInvalidPrintfConversionSpecifier(
 
                                      const analyze_printf::PrintfSpecifier &FS,
 
                                      const char *startSpecifier,
 
                                      unsigned specifierLen) {
 
    return true;
 
  }
 
 
 
  virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
 
                                     const char *startSpecifier,
 
                                     unsigned specifierLen,
 
                                     const TargetInfo &Target) {
 
    return true;
 
  }
 
 
 
  /// Handle mask types whose sizes are not between one and eight bytes.
 
  virtual void handleInvalidMaskType(StringRef MaskType) {}
 
 
 
    // Scanf-specific handlers.
 
 
 
  virtual bool HandleInvalidScanfConversionSpecifier(
 
                                        const analyze_scanf::ScanfSpecifier &FS,
 
                                        const char *startSpecifier,
 
                                        unsigned specifierLen) {
 
    return true;
 
  }
 
 
 
  virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
 
                                    const char *startSpecifier,
 
                                    unsigned specifierLen) {
 
    return true;
 
  }
 
 
 
  virtual void HandleIncompleteScanList(const char *start, const char *end) {}
 
};
 
 
 
bool ParsePrintfString(FormatStringHandler &H,
 
                       const char *beg, const char *end, const LangOptions &LO,
 
                       const TargetInfo &Target, bool isFreeBSDKPrintf);
 
 
 
bool ParseFormatStringHasSArg(const char *beg, const char *end,
 
                              const LangOptions &LO, const TargetInfo &Target);
 
 
 
bool ParseScanfString(FormatStringHandler &H,
 
                      const char *beg, const char *end, const LangOptions &LO,
 
                      const TargetInfo &Target);
 
 
 
/// Return true if the given string has at least one formatting specifier.
 
bool parseFormatStringHasFormattingSpecifiers(const char *Begin,
 
                                              const char *End,
 
                                              const LangOptions &LO,
 
                                              const TargetInfo &Target);
 
 
 
} // end analyze_format_string namespace
 
} // end clang namespace
 
#endif