r345971 - Reapply Logging: make os_log buffer size an integer constant expression.

Sam McCall via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 2 06:31:38 PDT 2018


The move of OSLog.h and FormatString.h to AST doesn't look obviously
correct.
Do these really belong in this layer? I think this patch needs review from
someone who knows AST/ better than myself... was there a review?

(If the do belong here: the namespaces and comments don't seem to have been
updated)

On Fri, Nov 2, 2018 at 2:16 PM Tim Northover via cfe-commits <
cfe-commits at lists.llvm.org> wrote:

> Author: tnorthover
> Date: Fri Nov  2 06:14:11 2018
> New Revision: 345971
>
> URL: http://llvm.org/viewvc/llvm-project?rev=345971&view=rev
> Log:
> Reapply Logging: make os_log buffer size an integer constant expression.
>
> The size of an os_log buffer is known at any stage of compilation, so
> making it
> a constant expression means that the common idiom of declaring a buffer
> for it
> won't result in a VLA. That allows the compiler to skip saving and
> restoring
> the stack pointer around such buffers.
>
> This also moves the OSLog and other FormatString helpers from
> libclangAnalysis to libclangAST to avoid a circular dependency.
>
> Added:
>     cfe/trunk/include/clang/AST/FormatString.h
>     cfe/trunk/include/clang/AST/OSLog.h
>     cfe/trunk/lib/AST/FormatString.cpp
>     cfe/trunk/lib/AST/FormatStringParsing.h
>     cfe/trunk/lib/AST/OSLog.cpp
>     cfe/trunk/lib/AST/PrintfFormatString.cpp
>     cfe/trunk/lib/AST/ScanfFormatString.cpp
> Removed:
>     cfe/trunk/include/clang/Analysis/Analyses/FormatString.h
>     cfe/trunk/include/clang/Analysis/Analyses/OSLog.h
>     cfe/trunk/lib/Analysis/FormatString.cpp
>     cfe/trunk/lib/Analysis/FormatStringParsing.h
>     cfe/trunk/lib/Analysis/OSLog.cpp
>     cfe/trunk/lib/Analysis/PrintfFormatString.cpp
>     cfe/trunk/lib/Analysis/ScanfFormatString.cpp
> Modified:
>     cfe/trunk/lib/AST/CMakeLists.txt
>     cfe/trunk/lib/AST/ExprConstant.cpp
>     cfe/trunk/lib/Analysis/CMakeLists.txt
>     cfe/trunk/lib/CodeGen/CGBuiltin.cpp
>     cfe/trunk/lib/Sema/SemaChecking.cpp
>     cfe/trunk/test/CodeGen/builtins.c
>
> Added: cfe/trunk/include/clang/AST/FormatString.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/FormatString.h?rev=345971&view=auto
>
> ==============================================================================
> --- cfe/trunk/include/clang/AST/FormatString.h (added)
> +++ cfe/trunk/include/clang/AST/FormatString.h Fri Nov  2 06:14:11 2018
> @@ -0,0 +1,719 @@
> +//= FormatString.h - Analysis of printf/fprintf format strings --*- C++
> -*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// 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_ANALYSIS_ANALYSES_FORMATSTRING_H
> +#define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
> +
> +#include "clang/AST/CanonicalType.h"
> +
> +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'
> +    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,
> +    IntArgBeg = dArg,
> +    IntArgEnd = iArg,
> +
> +    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; }
> +
> +  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 };
> +
> +  enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic };
> +
> +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;
> +
> +  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(0) {}
> +
> +  OptionalAmount(bool valid = true)
> +  : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
> +  UsesPositionalArg(0), UsesDotPrefix(0) {}
> +
> +  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;
> +  /// 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), 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 setFieldWidth(const OptionalAmount &Amt) {
> +    FieldWidth = Amt;
> +  }
> +
> +  bool usesPositionalArg() const { return UsesPositionalArg; }
> +
> +  bool hasValidLengthModifier(const TargetInfo &Target) const;
> +
> +  bool hasStandardLengthModifier() const;
> +
> +  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}'
> +  OptionalAmount Precision;
> +public:
> +  PrintfSpecifier()
> +      : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
> +        IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
> +        HasAlternativeForm("#"), HasLeadingZeroes("0"),
> +        HasObjCTechnicalTerm("tt"), IsPrivate("private"),
> IsPublic("public") {}
> +
> +  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 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; }
> +  bool usesPositionalArg() const { return UsesPositionalArg; }
> +
> +  /// 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) {
> +    return true;
> +  }
> +
> +    // 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);
> +
> +} // end analyze_format_string namespace
> +} // end clang namespace
> +#endif
>
> Added: cfe/trunk/include/clang/AST/OSLog.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/OSLog.h?rev=345971&view=auto
>
> ==============================================================================
> --- cfe/trunk/include/clang/AST/OSLog.h (added)
> +++ cfe/trunk/include/clang/AST/OSLog.h Fri Nov  2 06:14:11 2018
> @@ -0,0 +1,155 @@
> +//= OSLog.h - Analysis of calls to os_log builtins --*- C++
> -*-===============//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// This file defines APIs for determining the layout of the data buffer
> for
> +// os_log() and os_trace().
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H
> +#define LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H
> +
> +#include "clang/AST/ASTContext.h"
> +#include "clang/AST/Expr.h"
> +
> +namespace clang {
> +namespace analyze_os_log {
> +
> +/// An OSLogBufferItem represents a single item in the data written by a
> call
> +/// to os_log() or os_trace().
> +class OSLogBufferItem {
> +public:
> +  enum Kind {
> +    // The item is a scalar (int, float, raw pointer, etc.). No further
> copying
> +    // is required. This is the only kind allowed by os_trace().
> +    ScalarKind = 0,
> +
> +    // The item is a count, which describes the length of the following
> item to
> +    // be copied. A count may only be followed by an item of kind
> StringKind,
> +    // WideStringKind, or PointerKind.
> +    CountKind,
> +
> +    // The item is a pointer to a C string. If preceded by a count 'n',
> +    // os_log() will copy at most 'n' bytes from the pointer.
> +    StringKind,
> +
> +    // The item is a pointer to a block of raw data. This item must be
> preceded
> +    // by a count 'n'. os_log() will copy exactly 'n' bytes from the
> pointer.
> +    PointerKind,
> +
> +    // The item is a pointer to an Objective-C object. os_log() may
> retain the
> +    // object for later processing.
> +    ObjCObjKind,
> +
> +    // The item is a pointer to wide-char string.
> +    WideStringKind,
> +
> +    // The item is corresponding to the '%m' format specifier, no value is
> +    // populated in the buffer and the runtime is loading the errno value.
> +    ErrnoKind
> +  };
> +
> +  enum {
> +    // The item is marked "private" in the format string.
> +    IsPrivate = 0x1,
> +
> +    // The item is marked "public" in the format string.
> +    IsPublic = 0x2
> +  };
> +
> +private:
> +  Kind TheKind = ScalarKind;
> +  const Expr *TheExpr = nullptr;
> +  CharUnits ConstValue;
> +  CharUnits Size; // size of the data, not including the header bytes
> +  unsigned Flags = 0;
> +
> +public:
> +  OSLogBufferItem(Kind kind, const Expr *expr, CharUnits size, unsigned
> flags)
> +      : TheKind(kind), TheExpr(expr), Size(size), Flags(flags) {}
> +
> +  OSLogBufferItem(ASTContext &Ctx, CharUnits value, unsigned flags)
> +      : TheKind(CountKind), ConstValue(value),
> +        Size(Ctx.getTypeSizeInChars(Ctx.IntTy)), Flags(flags) {}
> +
> +  unsigned char getDescriptorByte() const {
> +    unsigned char result = 0;
> +    if (getIsPrivate())
> +      result |= IsPrivate;
> +    if (getIsPublic())
> +      result |= IsPublic;
> +    result |= ((unsigned)getKind()) << 4;
> +    return result;
> +  }
> +
> +  unsigned char getSizeByte() const { return size().getQuantity(); }
> +
> +  Kind getKind() const { return TheKind; }
> +  bool getIsPrivate() const { return (Flags & IsPrivate) != 0; }
> +  bool getIsPublic() const { return (Flags & IsPublic) != 0; }
> +
> +  const Expr *getExpr() const { return TheExpr; }
> +  CharUnits getConstValue() const { return ConstValue; }
> +  CharUnits size() const { return Size; }
> +};
> +
> +class OSLogBufferLayout {
> +public:
> +  SmallVector<OSLogBufferItem, 4> Items;
> +
> +  enum Flags { HasPrivateItems = 1, HasNonScalarItems = 1 << 1 };
> +
> +  CharUnits size() const {
> +    CharUnits result;
> +    result += CharUnits::fromQuantity(2); // summary byte, num-args byte
> +    for (auto &item : Items) {
> +      // descriptor byte, size byte
> +      result += item.size() + CharUnits::fromQuantity(2);
> +    }
> +    return result;
> +  }
> +
> +  bool hasPrivateItems() const {
> +    return llvm::any_of(
> +        Items, [](const OSLogBufferItem &Item) { return
> Item.getIsPrivate(); });
> +  }
> +
> +  bool hasPublicItems() const {
> +    return llvm::any_of(
> +        Items, [](const OSLogBufferItem &Item) { return
> Item.getIsPublic(); });
> +  }
> +
> +  bool hasNonScalar() const {
> +    return llvm::any_of(Items, [](const OSLogBufferItem &Item) {
> +      return Item.getKind() != OSLogBufferItem::ScalarKind;
> +    });
> +  }
> +
> +  unsigned char getSummaryByte() const {
> +    unsigned char result = 0;
> +    if (hasPrivateItems())
> +      result |= HasPrivateItems;
> +    if (hasNonScalar())
> +      result |= HasNonScalarItems;
> +    return result;
> +  }
> +
> +  unsigned char getNumArgsByte() const { return Items.size(); }
> +};
> +
> +// Given a call 'E' to one of the builtins __builtin_os_log_format() or
> +// __builtin_os_log_format_buffer_size(), compute the layout of the
> buffer that
> +// the call will write into and store it in 'layout'. Returns 'false' if
> there
> +// was some error encountered while computing the layout, and 'true'
> otherwise.
> +bool computeOSLogBufferLayout(clang::ASTContext &Ctx, const
> clang::CallExpr *E,
> +                              OSLogBufferLayout &layout);
> +
> +} // namespace analyze_os_log
> +} // namespace clang
> +#endif
>
> Removed: cfe/trunk/include/clang/Analysis/Analyses/FormatString.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/FormatString.h?rev=345970&view=auto
>
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/Analyses/FormatString.h (original)
> +++ cfe/trunk/include/clang/Analysis/Analyses/FormatString.h (removed)
> @@ -1,719 +0,0 @@
> -//= FormatString.h - Analysis of printf/fprintf format strings --*- C++
> -*-===//
> -//
> -//                     The LLVM Compiler Infrastructure
> -//
> -// This file is distributed under the University of Illinois Open Source
> -// License. See LICENSE.TXT for details.
> -//
>
> -//===----------------------------------------------------------------------===//
> -//
> -// 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_ANALYSIS_ANALYSES_FORMATSTRING_H
> -#define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
> -
> -#include "clang/AST/CanonicalType.h"
> -
> -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'
> -    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,
> -    IntArgBeg = dArg,
> -    IntArgEnd = iArg,
> -
> -    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; }
> -
> -  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 };
> -
> -  enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic };
> -
> -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;
> -
> -  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(0) {}
> -
> -  OptionalAmount(bool valid = true)
> -  : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
> -  UsesPositionalArg(0), UsesDotPrefix(0) {}
> -
> -  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;
> -  /// 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), 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 setFieldWidth(const OptionalAmount &Amt) {
> -    FieldWidth = Amt;
> -  }
> -
> -  bool usesPositionalArg() const { return UsesPositionalArg; }
> -
> -  bool hasValidLengthModifier(const TargetInfo &Target) const;
> -
> -  bool hasStandardLengthModifier() const;
> -
> -  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}'
> -  OptionalAmount Precision;
> -public:
> -  PrintfSpecifier()
> -      : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
> -        IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
> -        HasAlternativeForm("#"), HasLeadingZeroes("0"),
> -        HasObjCTechnicalTerm("tt"), IsPrivate("private"),
> IsPublic("public") {}
> -
> -  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 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; }
> -  bool usesPositionalArg() const { return UsesPositionalArg; }
> -
> -  /// 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) {
> -    return true;
> -  }
> -
> -    // 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);
> -
> -} // end analyze_format_string namespace
> -} // end clang namespace
> -#endif
>
> Removed: cfe/trunk/include/clang/Analysis/Analyses/OSLog.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/OSLog.h?rev=345970&view=auto
>
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/Analyses/OSLog.h (original)
> +++ cfe/trunk/include/clang/Analysis/Analyses/OSLog.h (removed)
> @@ -1,155 +0,0 @@
> -//= OSLog.h - Analysis of calls to os_log builtins --*- C++
> -*-===============//
> -//
> -//                     The LLVM Compiler Infrastructure
> -//
> -// This file is distributed under the University of Illinois Open Source
> -// License. See LICENSE.TXT for details.
> -//
>
> -//===----------------------------------------------------------------------===//
> -//
> -// This file defines APIs for determining the layout of the data buffer
> for
> -// os_log() and os_trace().
> -//
>
> -//===----------------------------------------------------------------------===//
> -
> -#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H
> -#define LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H
> -
> -#include "clang/AST/ASTContext.h"
> -#include "clang/AST/Expr.h"
> -
> -namespace clang {
> -namespace analyze_os_log {
> -
> -/// An OSLogBufferItem represents a single item in the data written by a
> call
> -/// to os_log() or os_trace().
> -class OSLogBufferItem {
> -public:
> -  enum Kind {
> -    // The item is a scalar (int, float, raw pointer, etc.). No further
> copying
> -    // is required. This is the only kind allowed by os_trace().
> -    ScalarKind = 0,
> -
> -    // The item is a count, which describes the length of the following
> item to
> -    // be copied. A count may only be followed by an item of kind
> StringKind,
> -    // WideStringKind, or PointerKind.
> -    CountKind,
> -
> -    // The item is a pointer to a C string. If preceded by a count 'n',
> -    // os_log() will copy at most 'n' bytes from the pointer.
> -    StringKind,
> -
> -    // The item is a pointer to a block of raw data. This item must be
> preceded
> -    // by a count 'n'. os_log() will copy exactly 'n' bytes from the
> pointer.
> -    PointerKind,
> -
> -    // The item is a pointer to an Objective-C object. os_log() may
> retain the
> -    // object for later processing.
> -    ObjCObjKind,
> -
> -    // The item is a pointer to wide-char string.
> -    WideStringKind,
> -
> -    // The item is corresponding to the '%m' format specifier, no value is
> -    // populated in the buffer and the runtime is loading the errno value.
> -    ErrnoKind
> -  };
> -
> -  enum {
> -    // The item is marked "private" in the format string.
> -    IsPrivate = 0x1,
> -
> -    // The item is marked "public" in the format string.
> -    IsPublic = 0x2
> -  };
> -
> -private:
> -  Kind TheKind = ScalarKind;
> -  const Expr *TheExpr = nullptr;
> -  CharUnits ConstValue;
> -  CharUnits Size; // size of the data, not including the header bytes
> -  unsigned Flags = 0;
> -
> -public:
> -  OSLogBufferItem(Kind kind, const Expr *expr, CharUnits size, unsigned
> flags)
> -      : TheKind(kind), TheExpr(expr), Size(size), Flags(flags) {}
> -
> -  OSLogBufferItem(ASTContext &Ctx, CharUnits value, unsigned flags)
> -      : TheKind(CountKind), ConstValue(value),
> -        Size(Ctx.getTypeSizeInChars(Ctx.IntTy)), Flags(flags) {}
> -
> -  unsigned char getDescriptorByte() const {
> -    unsigned char result = 0;
> -    if (getIsPrivate())
> -      result |= IsPrivate;
> -    if (getIsPublic())
> -      result |= IsPublic;
> -    result |= ((unsigned)getKind()) << 4;
> -    return result;
> -  }
> -
> -  unsigned char getSizeByte() const { return size().getQuantity(); }
> -
> -  Kind getKind() const { return TheKind; }
> -  bool getIsPrivate() const { return (Flags & IsPrivate) != 0; }
> -  bool getIsPublic() const { return (Flags & IsPublic) != 0; }
> -
> -  const Expr *getExpr() const { return TheExpr; }
> -  CharUnits getConstValue() const { return ConstValue; }
> -  CharUnits size() const { return Size; }
> -};
> -
> -class OSLogBufferLayout {
> -public:
> -  SmallVector<OSLogBufferItem, 4> Items;
> -
> -  enum Flags { HasPrivateItems = 1, HasNonScalarItems = 1 << 1 };
> -
> -  CharUnits size() const {
> -    CharUnits result;
> -    result += CharUnits::fromQuantity(2); // summary byte, num-args byte
> -    for (auto &item : Items) {
> -      // descriptor byte, size byte
> -      result += item.size() + CharUnits::fromQuantity(2);
> -    }
> -    return result;
> -  }
> -
> -  bool hasPrivateItems() const {
> -    return llvm::any_of(
> -        Items, [](const OSLogBufferItem &Item) { return
> Item.getIsPrivate(); });
> -  }
> -
> -  bool hasPublicItems() const {
> -    return llvm::any_of(
> -        Items, [](const OSLogBufferItem &Item) { return
> Item.getIsPublic(); });
> -  }
> -
> -  bool hasNonScalar() const {
> -    return llvm::any_of(Items, [](const OSLogBufferItem &Item) {
> -      return Item.getKind() != OSLogBufferItem::ScalarKind;
> -    });
> -  }
> -
> -  unsigned char getSummaryByte() const {
> -    unsigned char result = 0;
> -    if (hasPrivateItems())
> -      result |= HasPrivateItems;
> -    if (hasNonScalar())
> -      result |= HasNonScalarItems;
> -    return result;
> -  }
> -
> -  unsigned char getNumArgsByte() const { return Items.size(); }
> -};
> -
> -// Given a call 'E' to one of the builtins __builtin_os_log_format() or
> -// __builtin_os_log_format_buffer_size(), compute the layout of the
> buffer that
> -// the call will write into and store it in 'layout'. Returns 'false' if
> there
> -// was some error encountered while computing the layout, and 'true'
> otherwise.
> -bool computeOSLogBufferLayout(clang::ASTContext &Ctx, const
> clang::CallExpr *E,
> -                              OSLogBufferLayout &layout);
> -
> -} // namespace analyze_os_log
> -} // namespace clang
> -#endif
>
> Modified: cfe/trunk/lib/AST/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CMakeLists.txt?rev=345971&r1=345970&r2=345971&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/CMakeLists.txt (original)
> +++ cfe/trunk/lib/AST/CMakeLists.txt Fri Nov  2 06:14:11 2018
> @@ -39,6 +39,7 @@ add_clang_library(clangAST
>    ExprObjC.cpp
>    ExternalASTMerger.cpp
>    ExternalASTSource.cpp
> +  FormatString.cpp
>    InheritViz.cpp
>    ItaniumCXXABI.cpp
>    ItaniumMangle.cpp
> @@ -48,12 +49,15 @@ add_clang_library(clangAST
>    NestedNameSpecifier.cpp
>    NSAPI.cpp
>    ODRHash.cpp
> +  OSLog.cpp
>    OpenMPClause.cpp
>    ParentMap.cpp
> +  PrintfFormatString.cpp
>    QualTypeNames.cpp
>    RawCommentList.cpp
>    RecordLayout.cpp
>    RecordLayoutBuilder.cpp
> +  ScanfFormatString.cpp
>    SelectorLocationsKind.cpp
>    Stmt.cpp
>    StmtCXX.cpp
>
> Modified: cfe/trunk/lib/AST/ExprConstant.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=345971&r1=345970&r2=345971&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
> +++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Nov  2 06:14:11 2018
> @@ -39,6 +39,7 @@
>  #include "clang/AST/ASTLambda.h"
>  #include "clang/AST/CharUnits.h"
>  #include "clang/AST/Expr.h"
> +#include "clang/AST/OSLog.h"
>  #include "clang/AST/RecordLayout.h"
>  #include "clang/AST/StmtVisitor.h"
>  #include "clang/AST/TypeLoc.h"
> @@ -8126,6 +8127,12 @@ bool IntExprEvaluator::VisitBuiltinCallE
>      llvm_unreachable("unexpected EvalMode");
>    }
>
> +  case Builtin::BI__builtin_os_log_format_buffer_size: {
> +    analyze_os_log::OSLogBufferLayout Layout;
> +    analyze_os_log::computeOSLogBufferLayout(Info.Ctx, E, Layout);
> +    return Success(Layout.size().getQuantity(), E);
> +  }
> +
>    case Builtin::BI__builtin_bswap16:
>    case Builtin::BI__builtin_bswap32:
>    case Builtin::BI__builtin_bswap64: {
>
> Added: cfe/trunk/lib/AST/FormatString.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/FormatString.cpp?rev=345971&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/AST/FormatString.cpp (added)
> +++ cfe/trunk/lib/AST/FormatString.cpp Fri Nov  2 06:14:11 2018
> @@ -0,0 +1,955 @@
> +// FormatString.cpp - Common stuff for handling printf/scanf formats -*-
> C++ -*-
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// Shared details for processing format strings of printf and scanf
> +// (and friends).
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "FormatStringParsing.h"
> +#include "clang/Basic/LangOptions.h"
> +#include "clang/Basic/TargetInfo.h"
> +#include "llvm/Support/ConvertUTF.h"
> +
> +using clang::analyze_format_string::ArgType;
> +using clang::analyze_format_string::FormatStringHandler;
> +using clang::analyze_format_string::FormatSpecifier;
> +using clang::analyze_format_string::LengthModifier;
> +using clang::analyze_format_string::OptionalAmount;
> +using clang::analyze_format_string::PositionContext;
> +using clang::analyze_format_string::ConversionSpecifier;
> +using namespace clang;
> +
> +// Key function to FormatStringHandler.
> +FormatStringHandler::~FormatStringHandler() {}
> +
>
> +//===----------------------------------------------------------------------===//
> +// Functions for parsing format strings components in both printf and
> +// scanf format strings.
>
> +//===----------------------------------------------------------------------===//
> +
> +OptionalAmount
> +clang::analyze_format_string::ParseAmount(const char *&Beg, const char
> *E) {
> +  const char *I = Beg;
> +  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
> +
> +  unsigned accumulator = 0;
> +  bool hasDigits = false;
> +
> +  for ( ; I != E; ++I) {
> +    char c = *I;
> +    if (c >= '0' && c <= '9') {
> +      hasDigits = true;
> +      accumulator = (accumulator * 10) + (c - '0');
> +      continue;
> +    }
> +
> +    if (hasDigits)
> +      return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I
> - Beg,
> +          false);
> +
> +    break;
> +  }
> +
> +  return OptionalAmount();
> +}
> +
> +OptionalAmount
> +clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg,
> +                                                     const char *E,
> +                                                     unsigned &argIndex) {
> +  if (*Beg == '*') {
> +    ++Beg;
> +    return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
> +  }
> +
> +  return ParseAmount(Beg, E);
> +}
> +
> +OptionalAmount
> +clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H,
> +                                                  const char *Start,
> +                                                  const char *&Beg,
> +                                                  const char *E,
> +                                                  PositionContext p) {
> +  if (*Beg == '*') {
> +    const char *I = Beg + 1;
> +    const OptionalAmount &Amt = ParseAmount(I, E);
> +
> +    if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
> +      H.HandleInvalidPosition(Beg, I - Beg, p);
> +      return OptionalAmount(false);
> +    }
> +
> +    if (I == E) {
> +      // No more characters left?
> +      H.HandleIncompleteSpecifier(Start, E - Start);
> +      return OptionalAmount(false);
> +    }
> +
> +    assert(Amt.getHowSpecified() == OptionalAmount::Constant);
> +
> +    if (*I == '$') {
> +      // Handle positional arguments
> +
> +      // Special case: '*0$', since this is an easy mistake.
> +      if (Amt.getConstantAmount() == 0) {
> +        H.HandleZeroPosition(Beg, I - Beg + 1);
> +        return OptionalAmount(false);
> +      }
> +
> +      const char *Tmp = Beg;
> +      Beg = ++I;
> +
> +      return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount()
> - 1,
> +                            Tmp, 0, true);
> +    }
> +
> +    H.HandleInvalidPosition(Beg, I - Beg, p);
> +    return OptionalAmount(false);
> +  }
> +
> +  return ParseAmount(Beg, E);
> +}
> +
> +
> +bool
> +clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H,
> +                                              FormatSpecifier &CS,
> +                                              const char *Start,
> +                                              const char *&Beg, const
> char *E,
> +                                              unsigned *argIndex) {
> +  // FIXME: Support negative field widths.
> +  if (argIndex) {
> +    CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
> +  }
> +  else {
> +    const OptionalAmount Amt =
> +      ParsePositionAmount(H, Start, Beg, E,
> +                          analyze_format_string::FieldWidthPos);
> +
> +    if (Amt.isInvalid())
> +      return true;
> +    CS.setFieldWidth(Amt);
> +  }
> +  return false;
> +}
> +
> +bool
> +clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
> +                                               FormatSpecifier &FS,
> +                                               const char *Start,
> +                                               const char *&Beg,
> +                                               const char *E) {
> +  const char *I = Beg;
> +
> +  const OptionalAmount &Amt = ParseAmount(I, E);
> +
> +  if (I == E) {
> +    // No more characters left?
> +    H.HandleIncompleteSpecifier(Start, E - Start);
> +    return true;
> +  }
> +
> +  if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$')
> {
> +    // Warn that positional arguments are non-standard.
> +    H.HandlePosition(Start, I - Start);
> +
> +    // Special case: '%0$', since this is an easy mistake.
> +    if (Amt.getConstantAmount() == 0) {
> +      H.HandleZeroPosition(Start, I - Start);
> +      return true;
> +    }
> +
> +    FS.setArgIndex(Amt.getConstantAmount() - 1);
> +    FS.setUsesPositionalArg();
> +    // Update the caller's pointer if we decided to consume
> +    // these characters.
> +    Beg = I;
> +    return false;
> +  }
> +
> +  return false;
> +}
> +
> +bool
> +clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
> +                                                  const char *&I,
> +                                                  const char *E,
> +                                                  const LangOptions &LO,
> +                                                  bool IsScanf) {
> +  LengthModifier::Kind lmKind = LengthModifier::None;
> +  const char *lmPosition = I;
> +  switch (*I) {
> +    default:
> +      return false;
> +    case 'h':
> +      ++I;
> +      if (I != E && *I == 'h') {
> +        ++I;
> +        lmKind = LengthModifier::AsChar;
> +      } else {
> +        lmKind = LengthModifier::AsShort;
> +      }
> +      break;
> +    case 'l':
> +      ++I;
> +      if (I != E && *I == 'l') {
> +        ++I;
> +        lmKind = LengthModifier::AsLongLong;
> +      } else {
> +        lmKind = LengthModifier::AsLong;
> +      }
> +      break;
> +    case 'j': lmKind = LengthModifier::AsIntMax;     ++I; break;
> +    case 'z': lmKind = LengthModifier::AsSizeT;      ++I; break;
> +    case 't': lmKind = LengthModifier::AsPtrDiff;    ++I; break;
> +    case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
> +    case 'q': lmKind = LengthModifier::AsQuad;       ++I; break;
> +    case 'a':
> +      if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {
> +        // For scanf in C90, look at the next character to see if this
> should
> +        // be parsed as the GNU extension 'a' length modifier. If not,
> this
> +        // will be parsed as a conversion specifier.
> +        ++I;
> +        if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {
> +          lmKind = LengthModifier::AsAllocate;
> +          break;
> +        }
> +        --I;
> +      }
> +      return false;
> +    case 'm':
> +      if (IsScanf) {
> +        lmKind = LengthModifier::AsMAllocate;
> +        ++I;
> +        break;
> +      }
> +      return false;
> +    // printf: AsInt64, AsInt32, AsInt3264
> +    // scanf:  AsInt64
> +    case 'I':
> +      if (I + 1 != E && I + 2 != E) {
> +        if (I[1] == '6' && I[2] == '4') {
> +          I += 3;
> +          lmKind = LengthModifier::AsInt64;
> +          break;
> +        }
> +        if (IsScanf)
> +          return false;
> +
> +        if (I[1] == '3' && I[2] == '2') {
> +          I += 3;
> +          lmKind = LengthModifier::AsInt32;
> +          break;
> +        }
> +      }
> +      ++I;
> +      lmKind = LengthModifier::AsInt3264;
> +      break;
> +    case 'w':
> +      lmKind = LengthModifier::AsWide; ++I; break;
> +  }
> +  LengthModifier lm(lmPosition, lmKind);
> +  FS.setLengthModifier(lm);
> +  return true;
> +}
> +
> +bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(
> +    const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len) {
> +  if (SpecifierBegin + 1 >= FmtStrEnd)
> +    return false;
> +
> +  const llvm::UTF8 *SB =
> +      reinterpret_cast<const llvm::UTF8 *>(SpecifierBegin + 1);
> +  const llvm::UTF8 *SE = reinterpret_cast<const llvm::UTF8 *>(FmtStrEnd);
> +  const char FirstByte = *SB;
> +
> +  // If the invalid specifier is a multibyte UTF-8 string, return the
> +  // total length accordingly so that the conversion specifier can be
> +  // properly updated to reflect a complete UTF-8 specifier.
> +  unsigned NumBytes = llvm::getNumBytesForUTF8(FirstByte);
> +  if (NumBytes == 1)
> +    return false;
> +  if (SB + NumBytes > SE)
> +    return false;
> +
> +  Len = NumBytes + 1;
> +  return true;
> +}
> +
>
> +//===----------------------------------------------------------------------===//
> +// Methods on ArgType.
>
> +//===----------------------------------------------------------------------===//
> +
> +clang::analyze_format_string::ArgType::MatchKind
> +ArgType::matchesType(ASTContext &C, QualType argTy) const {
> +  if (Ptr) {
> +    // It has to be a pointer.
> +    const PointerType *PT = argTy->getAs<PointerType>();
> +    if (!PT)
> +      return NoMatch;
> +
> +    // We cannot write through a const qualified pointer.
> +    if (PT->getPointeeType().isConstQualified())
> +      return NoMatch;
> +
> +    argTy = PT->getPointeeType();
> +  }
> +
> +  switch (K) {
> +    case InvalidTy:
> +      llvm_unreachable("ArgType must be valid");
> +
> +    case UnknownTy:
> +      return Match;
> +
> +    case AnyCharTy: {
> +      if (const EnumType *ETy = argTy->getAs<EnumType>()) {
> +        // If the enum is incomplete we know nothing about the underlying
> type.
> +        // Assume that it's 'int'.
> +        if (!ETy->getDecl()->isComplete())
> +          return NoMatch;
> +        argTy = ETy->getDecl()->getIntegerType();
> +      }
> +
> +      if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
> +        switch (BT->getKind()) {
> +          default:
> +            break;
> +          case BuiltinType::Char_S:
> +          case BuiltinType::SChar:
> +          case BuiltinType::UChar:
> +          case BuiltinType::Char_U:
> +            return Match;
> +        }
> +      return NoMatch;
> +    }
> +
> +    case SpecificTy: {
> +      if (const EnumType *ETy = argTy->getAs<EnumType>()) {
> +        // If the enum is incomplete we know nothing about the underlying
> type.
> +        // Assume that it's 'int'.
> +        if (!ETy->getDecl()->isComplete())
> +          argTy = C.IntTy;
> +        else
> +          argTy = ETy->getDecl()->getIntegerType();
> +      }
> +      argTy = C.getCanonicalType(argTy).getUnqualifiedType();
> +
> +      if (T == argTy)
> +        return Match;
> +      // Check for "compatible types".
> +      if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
> +        switch (BT->getKind()) {
> +          default:
> +            break;
> +          case BuiltinType::Char_S:
> +          case BuiltinType::SChar:
> +          case BuiltinType::Char_U:
> +          case BuiltinType::UChar:
> +            return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match
> +                                                                : NoMatch;
> +          case BuiltinType::Short:
> +            return T == C.UnsignedShortTy ? Match : NoMatch;
> +          case BuiltinType::UShort:
> +            return T == C.ShortTy ? Match : NoMatch;
> +          case BuiltinType::Int:
> +            return T == C.UnsignedIntTy ? Match : NoMatch;
> +          case BuiltinType::UInt:
> +            return T == C.IntTy ? Match : NoMatch;
> +          case BuiltinType::Long:
> +            return T == C.UnsignedLongTy ? Match : NoMatch;
> +          case BuiltinType::ULong:
> +            return T == C.LongTy ? Match : NoMatch;
> +          case BuiltinType::LongLong:
> +            return T == C.UnsignedLongLongTy ? Match : NoMatch;
> +          case BuiltinType::ULongLong:
> +            return T == C.LongLongTy ? Match : NoMatch;
> +        }
> +      return NoMatch;
> +    }
> +
> +    case CStrTy: {
> +      const PointerType *PT = argTy->getAs<PointerType>();
> +      if (!PT)
> +        return NoMatch;
> +      QualType pointeeTy = PT->getPointeeType();
> +      if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
> +        switch (BT->getKind()) {
> +          case BuiltinType::Void:
> +          case BuiltinType::Char_U:
> +          case BuiltinType::UChar:
> +          case BuiltinType::Char_S:
> +          case BuiltinType::SChar:
> +            return Match;
> +          default:
> +            break;
> +        }
> +
> +      return NoMatch;
> +    }
> +
> +    case WCStrTy: {
> +      const PointerType *PT = argTy->getAs<PointerType>();
> +      if (!PT)
> +        return NoMatch;
> +      QualType pointeeTy =
> +        C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
> +      return pointeeTy == C.getWideCharType() ? Match : NoMatch;
> +    }
> +
> +    case WIntTy: {
> +      QualType WInt =
> C.getCanonicalType(C.getWIntType()).getUnqualifiedType();
> +
> +      if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)
> +        return Match;
> +
> +      QualType PromoArg = argTy->isPromotableIntegerType()
> +                              ? C.getPromotedIntegerType(argTy)
> +                              : argTy;
> +      PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();
> +
> +      // If the promoted argument is the corresponding signed type of the
> +      // wint_t type, then it should match.
> +      if (PromoArg->hasSignedIntegerRepresentation() &&
> +          C.getCorrespondingUnsignedType(PromoArg) == WInt)
> +        return Match;
> +
> +      return WInt == PromoArg ? Match : NoMatch;
> +    }
> +
> +    case CPointerTy:
> +      if (argTy->isVoidPointerType()) {
> +        return Match;
> +      } if (argTy->isPointerType() || argTy->isObjCObjectPointerType() ||
> +            argTy->isBlockPointerType() || argTy->isNullPtrType()) {
> +        return NoMatchPedantic;
> +      } else {
> +        return NoMatch;
> +      }
> +
> +    case ObjCPointerTy: {
> +      if (argTy->getAs<ObjCObjectPointerType>() ||
> +          argTy->getAs<BlockPointerType>())
> +        return Match;
> +
> +      // Handle implicit toll-free bridging.
> +      if (const PointerType *PT = argTy->getAs<PointerType>()) {
> +        // Things such as CFTypeRef are really just opaque pointers
> +        // to C structs representing CF types that can often be bridged
> +        // to Objective-C objects.  Since the compiler doesn't know which
> +        // structs can be toll-free bridged, we just accept them all.
> +        QualType pointee = PT->getPointeeType();
> +        if (pointee->getAsStructureType() || pointee->isVoidType())
> +          return Match;
> +      }
> +      return NoMatch;
> +    }
> +  }
> +
> +  llvm_unreachable("Invalid ArgType Kind!");
> +}
> +
> +QualType ArgType::getRepresentativeType(ASTContext &C) const {
> +  QualType Res;
> +  switch (K) {
> +    case InvalidTy:
> +      llvm_unreachable("No representative type for Invalid ArgType");
> +    case UnknownTy:
> +      llvm_unreachable("No representative type for Unknown ArgType");
> +    case AnyCharTy:
> +      Res = C.CharTy;
> +      break;
> +    case SpecificTy:
> +      Res = T;
> +      break;
> +    case CStrTy:
> +      Res = C.getPointerType(C.CharTy);
> +      break;
> +    case WCStrTy:
> +      Res = C.getPointerType(C.getWideCharType());
> +      break;
> +    case ObjCPointerTy:
> +      Res = C.ObjCBuiltinIdTy;
> +      break;
> +    case CPointerTy:
> +      Res = C.VoidPtrTy;
> +      break;
> +    case WIntTy: {
> +      Res = C.getWIntType();
> +      break;
> +    }
> +  }
> +
> +  if (Ptr)
> +    Res = C.getPointerType(Res);
> +  return Res;
> +}
> +
> +std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {
> +  std::string S = getRepresentativeType(C).getAsString();
> +
> +  std::string Alias;
> +  if (Name) {
> +    // Use a specific name for this type, e.g. "size_t".
> +    Alias = Name;
> +    if (Ptr) {
> +      // If ArgType is actually a pointer to T, append an asterisk.
> +      Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *";
> +    }
> +    // If Alias is the same as the underlying type, e.g. wchar_t, then
> drop it.
> +    if (S == Alias)
> +      Alias.clear();
> +  }
> +
> +  if (!Alias.empty())
> +    return std::string("'") + Alias + "' (aka '" + S + "')";
> +  return std::string("'") + S + "'";
> +}
> +
> +
>
> +//===----------------------------------------------------------------------===//
> +// Methods on OptionalAmount.
>
> +//===----------------------------------------------------------------------===//
> +
> +ArgType
> +analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {
> +  return Ctx.IntTy;
> +}
> +
>
> +//===----------------------------------------------------------------------===//
> +// Methods on LengthModifier.
>
> +//===----------------------------------------------------------------------===//
> +
> +const char *
> +analyze_format_string::LengthModifier::toString() const {
> +  switch (kind) {
> +  case AsChar:
> +    return "hh";
> +  case AsShort:
> +    return "h";
> +  case AsLong: // or AsWideChar
> +    return "l";
> +  case AsLongLong:
> +    return "ll";
> +  case AsQuad:
> +    return "q";
> +  case AsIntMax:
> +    return "j";
> +  case AsSizeT:
> +    return "z";
> +  case AsPtrDiff:
> +    return "t";
> +  case AsInt32:
> +    return "I32";
> +  case AsInt3264:
> +    return "I";
> +  case AsInt64:
> +    return "I64";
> +  case AsLongDouble:
> +    return "L";
> +  case AsAllocate:
> +    return "a";
> +  case AsMAllocate:
> +    return "m";
> +  case AsWide:
> +    return "w";
> +  case None:
> +    return "";
> +  }
> +  return nullptr;
> +}
> +
>
> +//===----------------------------------------------------------------------===//
> +// Methods on ConversionSpecifier.
>
> +//===----------------------------------------------------------------------===//
> +
> +const char *ConversionSpecifier::toString() const {
> +  switch (kind) {
> +  case dArg: return "d";
> +  case DArg: return "D";
> +  case iArg: return "i";
> +  case oArg: return "o";
> +  case OArg: return "O";
> +  case uArg: return "u";
> +  case UArg: return "U";
> +  case xArg: return "x";
> +  case XArg: return "X";
> +  case fArg: return "f";
> +  case FArg: return "F";
> +  case eArg: return "e";
> +  case EArg: return "E";
> +  case gArg: return "g";
> +  case GArg: return "G";
> +  case aArg: return "a";
> +  case AArg: return "A";
> +  case cArg: return "c";
> +  case sArg: return "s";
> +  case pArg: return "p";
> +  case PArg:
> +    return "P";
> +  case nArg: return "n";
> +  case PercentArg:  return "%";
> +  case ScanListArg: return "[";
> +  case InvalidSpecifier: return nullptr;
> +
> +  // POSIX unicode extensions.
> +  case CArg: return "C";
> +  case SArg: return "S";
> +
> +  // Objective-C specific specifiers.
> +  case ObjCObjArg: return "@";
> +
> +  // FreeBSD kernel specific specifiers.
> +  case FreeBSDbArg: return "b";
> +  case FreeBSDDArg: return "D";
> +  case FreeBSDrArg: return "r";
> +  case FreeBSDyArg: return "y";
> +
> +  // GlibC specific specifiers.
> +  case PrintErrno: return "m";
> +
> +  // MS specific specifiers.
> +  case ZArg: return "Z";
> +  }
> +  return nullptr;
> +}
> +
> +Optional<ConversionSpecifier>
> +ConversionSpecifier::getStandardSpecifier() const {
> +  ConversionSpecifier::Kind NewKind;
> +
> +  switch (getKind()) {
> +  default:
> +    return None;
> +  case DArg:
> +    NewKind = dArg;
> +    break;
> +  case UArg:
> +    NewKind = uArg;
> +    break;
> +  case OArg:
> +    NewKind = oArg;
> +    break;
> +  }
> +
> +  ConversionSpecifier FixedCS(*this);
> +  FixedCS.setKind(NewKind);
> +  return FixedCS;
> +}
> +
>
> +//===----------------------------------------------------------------------===//
> +// Methods on OptionalAmount.
>
> +//===----------------------------------------------------------------------===//
> +
> +void OptionalAmount::toString(raw_ostream &os) const {
> +  switch (hs) {
> +  case Invalid:
> +  case NotSpecified:
> +    return;
> +  case Arg:
> +    if (UsesDotPrefix)
> +        os << ".";
> +    if (usesPositionalArg())
> +      os << "*" << getPositionalArgIndex() << "$";
> +    else
> +      os << "*";
> +    break;
> +  case Constant:
> +    if (UsesDotPrefix)
> +        os << ".";
> +    os << amt;
> +    break;
> +  }
> +}
> +
> +bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target)
> const {
> +  switch (LM.getKind()) {
> +    case LengthModifier::None:
> +      return true;
> +
> +    // Handle most integer flags
> +    case LengthModifier::AsShort:
> +      if (Target.getTriple().isOSMSVCRT()) {
> +        switch (CS.getKind()) {
> +          case ConversionSpecifier::cArg:
> +          case ConversionSpecifier::CArg:
> +          case ConversionSpecifier::sArg:
> +          case ConversionSpecifier::SArg:
> +          case ConversionSpecifier::ZArg:
> +            return true;
> +          default:
> +            break;
> +        }
> +      }
> +      LLVM_FALLTHROUGH;
> +    case LengthModifier::AsChar:
> +    case LengthModifier::AsLongLong:
> +    case LengthModifier::AsQuad:
> +    case LengthModifier::AsIntMax:
> +    case LengthModifier::AsSizeT:
> +    case LengthModifier::AsPtrDiff:
> +      switch (CS.getKind()) {
> +        case ConversionSpecifier::dArg:
> +        case ConversionSpecifier::DArg:
> +        case ConversionSpecifier::iArg:
> +        case ConversionSpecifier::oArg:
> +        case ConversionSpecifier::OArg:
> +        case ConversionSpecifier::uArg:
> +        case ConversionSpecifier::UArg:
> +        case ConversionSpecifier::xArg:
> +        case ConversionSpecifier::XArg:
> +        case ConversionSpecifier::nArg:
> +          return true;
> +        case ConversionSpecifier::FreeBSDrArg:
> +        case ConversionSpecifier::FreeBSDyArg:
> +          return Target.getTriple().isOSFreeBSD() ||
> Target.getTriple().isPS4();
> +        default:
> +          return false;
> +      }
> +
> +    // Handle 'l' flag
> +    case LengthModifier::AsLong: // or AsWideChar
> +      switch (CS.getKind()) {
> +        case ConversionSpecifier::dArg:
> +        case ConversionSpecifier::DArg:
> +        case ConversionSpecifier::iArg:
> +        case ConversionSpecifier::oArg:
> +        case ConversionSpecifier::OArg:
> +        case ConversionSpecifier::uArg:
> +        case ConversionSpecifier::UArg:
> +        case ConversionSpecifier::xArg:
> +        case ConversionSpecifier::XArg:
> +        case ConversionSpecifier::aArg:
> +        case ConversionSpecifier::AArg:
> +        case ConversionSpecifier::fArg:
> +        case ConversionSpecifier::FArg:
> +        case ConversionSpecifier::eArg:
> +        case ConversionSpecifier::EArg:
> +        case ConversionSpecifier::gArg:
> +        case ConversionSpecifier::GArg:
> +        case ConversionSpecifier::nArg:
> +        case ConversionSpecifier::cArg:
> +        case ConversionSpecifier::sArg:
> +        case ConversionSpecifier::ScanListArg:
> +        case ConversionSpecifier::ZArg:
> +          return true;
> +        case ConversionSpecifier::FreeBSDrArg:
> +        case ConversionSpecifier::FreeBSDyArg:
> +          return Target.getTriple().isOSFreeBSD() ||
> Target.getTriple().isPS4();
> +        default:
> +          return false;
> +      }
> +
> +    case LengthModifier::AsLongDouble:
> +      switch (CS.getKind()) {
> +        case ConversionSpecifier::aArg:
> +        case ConversionSpecifier::AArg:
> +        case ConversionSpecifier::fArg:
> +        case ConversionSpecifier::FArg:
> +        case ConversionSpecifier::eArg:
> +        case ConversionSpecifier::EArg:
> +        case ConversionSpecifier::gArg:
> +        case ConversionSpecifier::GArg:
> +          return true;
> +        // GNU libc extension.
> +        case ConversionSpecifier::dArg:
> +        case ConversionSpecifier::iArg:
> +        case ConversionSpecifier::oArg:
> +        case ConversionSpecifier::uArg:
> +        case ConversionSpecifier::xArg:
> +        case ConversionSpecifier::XArg:
> +          return !Target.getTriple().isOSDarwin() &&
> +                 !Target.getTriple().isOSWindows();
> +        default:
> +          return false;
> +      }
> +
> +    case LengthModifier::AsAllocate:
> +      switch (CS.getKind()) {
> +        case ConversionSpecifier::sArg:
> +        case ConversionSpecifier::SArg:
> +        case ConversionSpecifier::ScanListArg:
> +          return true;
> +        default:
> +          return false;
> +      }
> +
> +    case LengthModifier::AsMAllocate:
> +      switch (CS.getKind()) {
> +        case ConversionSpecifier::cArg:
> +        case ConversionSpecifier::CArg:
> +        case ConversionSpecifier::sArg:
> +        case ConversionSpecifier::SArg:
> +        case ConversionSpecifier::ScanListArg:
> +          return true;
> +        default:
> +          return false;
> +      }
> +    case LengthModifier::AsInt32:
> +    case LengthModifier::AsInt3264:
> +    case LengthModifier::AsInt64:
> +      switch (CS.getKind()) {
> +        case ConversionSpecifier::dArg:
> +        case ConversionSpecifier::iArg:
> +        case ConversionSpecifier::oArg:
> +        case ConversionSpecifier::uArg:
> +        case ConversionSpecifier::xArg:
> +        case ConversionSpecifier::XArg:
> +          return Target.getTriple().isOSMSVCRT();
> +        default:
> +          return false;
> +      }
> +    case LengthModifier::AsWide:
> +      switch (CS.getKind()) {
> +        case ConversionSpecifier::cArg:
> +        case ConversionSpecifier::CArg:
> +        case ConversionSpecifier::sArg:
> +        case ConversionSpecifier::SArg:
> +        case ConversionSpecifier::ZArg:
> +          return Target.getTriple().isOSMSVCRT();
> +        default:
> +          return false;
> +      }
> +  }
> +  llvm_unreachable("Invalid LengthModifier Kind!");
> +}
> +
> +bool FormatSpecifier::hasStandardLengthModifier() const {
> +  switch (LM.getKind()) {
> +    case LengthModifier::None:
> +    case LengthModifier::AsChar:
> +    case LengthModifier::AsShort:
> +    case LengthModifier::AsLong:
> +    case LengthModifier::AsLongLong:
> +    case LengthModifier::AsIntMax:
> +    case LengthModifier::AsSizeT:
> +    case LengthModifier::AsPtrDiff:
> +    case LengthModifier::AsLongDouble:
> +      return true;
> +    case LengthModifier::AsAllocate:
> +    case LengthModifier::AsMAllocate:
> +    case LengthModifier::AsQuad:
> +    case LengthModifier::AsInt32:
> +    case LengthModifier::AsInt3264:
> +    case LengthModifier::AsInt64:
> +    case LengthModifier::AsWide:
> +      return false;
> +  }
> +  llvm_unreachable("Invalid LengthModifier Kind!");
> +}
> +
> +bool FormatSpecifier::hasStandardConversionSpecifier(
> +    const LangOptions &LangOpt) const {
> +  switch (CS.getKind()) {
> +    case ConversionSpecifier::cArg:
> +    case ConversionSpecifier::dArg:
> +    case ConversionSpecifier::iArg:
> +    case ConversionSpecifier::oArg:
> +    case ConversionSpecifier::uArg:
> +    case ConversionSpecifier::xArg:
> +    case ConversionSpecifier::XArg:
> +    case ConversionSpecifier::fArg:
> +    case ConversionSpecifier::FArg:
> +    case ConversionSpecifier::eArg:
> +    case ConversionSpecifier::EArg:
> +    case ConversionSpecifier::gArg:
> +    case ConversionSpecifier::GArg:
> +    case ConversionSpecifier::aArg:
> +    case ConversionSpecifier::AArg:
> +    case ConversionSpecifier::sArg:
> +    case ConversionSpecifier::pArg:
> +    case ConversionSpecifier::nArg:
> +    case ConversionSpecifier::ObjCObjArg:
> +    case ConversionSpecifier::ScanListArg:
> +    case ConversionSpecifier::PercentArg:
> +    case ConversionSpecifier::PArg:
> +      return true;
> +    case ConversionSpecifier::CArg:
> +    case ConversionSpecifier::SArg:
> +      return LangOpt.ObjC;
> +    case ConversionSpecifier::InvalidSpecifier:
> +    case ConversionSpecifier::FreeBSDbArg:
> +    case ConversionSpecifier::FreeBSDDArg:
> +    case ConversionSpecifier::FreeBSDrArg:
> +    case ConversionSpecifier::FreeBSDyArg:
> +    case ConversionSpecifier::PrintErrno:
> +    case ConversionSpecifier::DArg:
> +    case ConversionSpecifier::OArg:
> +    case ConversionSpecifier::UArg:
> +    case ConversionSpecifier::ZArg:
> +      return false;
> +  }
> +  llvm_unreachable("Invalid ConversionSpecifier Kind!");
> +}
> +
> +bool FormatSpecifier::hasStandardLengthConversionCombination() const {
> +  if (LM.getKind() == LengthModifier::AsLongDouble) {
> +    switch(CS.getKind()) {
> +        case ConversionSpecifier::dArg:
> +        case ConversionSpecifier::iArg:
> +        case ConversionSpecifier::oArg:
> +        case ConversionSpecifier::uArg:
> +        case ConversionSpecifier::xArg:
> +        case ConversionSpecifier::XArg:
> +          return false;
> +        default:
> +          return true;
> +    }
> +  }
> +  return true;
> +}
> +
> +Optional<LengthModifier> FormatSpecifier::getCorrectedLengthModifier()
> const {
> +  if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
> +    if (LM.getKind() == LengthModifier::AsLongDouble ||
> +        LM.getKind() == LengthModifier::AsQuad) {
> +      LengthModifier FixedLM(LM);
> +      FixedLM.setKind(LengthModifier::AsLongLong);
> +      return FixedLM;
> +    }
> +  }
> +
> +  return None;
> +}
> +
> +bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
> +                                                LengthModifier &LM) {
> +  assert(isa<TypedefType>(QT) && "Expected a TypedefType");
> +  const TypedefNameDecl *Typedef = cast<TypedefType>(QT)->getDecl();
> +
> +  for (;;) {
> +    const IdentifierInfo *Identifier = Typedef->getIdentifier();
> +    if (Identifier->getName() == "size_t") {
> +      LM.setKind(LengthModifier::AsSizeT);
> +      return true;
> +    } else if (Identifier->getName() == "ssize_t") {
> +      // Not C99, but common in Unix.
> +      LM.setKind(LengthModifier::AsSizeT);
> +      return true;
> +    } else if (Identifier->getName() == "intmax_t") {
> +      LM.setKind(LengthModifier::AsIntMax);
> +      return true;
> +    } else if (Identifier->getName() == "uintmax_t") {
> +      LM.setKind(LengthModifier::AsIntMax);
> +      return true;
> +    } else if (Identifier->getName() == "ptrdiff_t") {
> +      LM.setKind(LengthModifier::AsPtrDiff);
> +      return true;
> +    }
> +
> +    QualType T = Typedef->getUnderlyingType();
> +    if (!isa<TypedefType>(T))
> +      break;
> +
> +    Typedef = cast<TypedefType>(T)->getDecl();
> +  }
> +  return false;
> +}
>
> Added: cfe/trunk/lib/AST/FormatStringParsing.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/FormatStringParsing.h?rev=345971&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/AST/FormatStringParsing.h (added)
> +++ cfe/trunk/lib/AST/FormatStringParsing.h Fri Nov  2 06:14:11 2018
> @@ -0,0 +1,79 @@
> +#ifndef LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
> +#define LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
> +
> +#include "clang/AST/ASTContext.h"
> +#include "clang/AST/Type.h"
> +#include "clang/AST/FormatString.h"
> +
> +namespace clang {
> +
> +class LangOptions;
> +
> +template <typename T>
> +class UpdateOnReturn {
> +  T &ValueToUpdate;
> +  const T &ValueToCopy;
> +public:
> +  UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
> +    : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
> +
> +  ~UpdateOnReturn() {
> +    ValueToUpdate = ValueToCopy;
> +  }
> +};
> +
> +namespace analyze_format_string {
> +
> +OptionalAmount ParseAmount(const char *&Beg, const char *E);
> +OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
> +                                      unsigned &argIndex);
> +
> +OptionalAmount ParsePositionAmount(FormatStringHandler &H,
> +                                   const char *Start, const char *&Beg,
> +                                   const char *E, PositionContext p);
> +
> +bool ParseFieldWidth(FormatStringHandler &H,
> +                     FormatSpecifier &CS,
> +                     const char *Start, const char *&Beg, const char *E,
> +                     unsigned *argIndex);
> +
> +bool ParseArgPosition(FormatStringHandler &H,
> +                      FormatSpecifier &CS, const char *Start,
> +                      const char *&Beg, const char *E);
> +
> +/// Returns true if a LengthModifier was parsed and installed in the
> +/// FormatSpecifier& argument, and false otherwise.
> +bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const
> char *E,
> +                         const LangOptions &LO, bool IsScanf = false);
> +
> +/// Returns true if the invalid specifier in \p SpecifierBegin is a UTF-8
> +/// string; check that it won't go further than \p FmtStrEnd and write
> +/// up the total size in \p Len.
> +bool ParseUTF8InvalidSpecifier(const char *SpecifierBegin,
> +                               const char *FmtStrEnd, unsigned &Len);
> +
> +template <typename T> class SpecifierResult {
> +  T FS;
> +  const char *Start;
> +  bool Stop;
> +public:
> +  SpecifierResult(bool stop = false)
> +  : Start(nullptr), Stop(stop) {}
> +  SpecifierResult(const char *start,
> +                  const T &fs)
> +  : FS(fs), Start(start), Stop(false) {}
> +
> +  const char *getStart() const { return Start; }
> +  bool shouldStop() const { return Stop; }
> +  bool hasValue() const { return Start != nullptr; }
> +  const T &getValue() const {
> +    assert(hasValue());
> +    return FS;
> +  }
> +  const T &getValue() { return FS; }
> +};
> +
> +} // end analyze_format_string namespace
> +} // end clang namespace
> +
> +#endif
>
> Added: cfe/trunk/lib/AST/OSLog.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/OSLog.cpp?rev=345971&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/AST/OSLog.cpp (added)
> +++ cfe/trunk/lib/AST/OSLog.cpp Fri Nov  2 06:14:11 2018
> @@ -0,0 +1,203 @@
> +// TODO: header template
> +
> +#include "clang/AST/OSLog.h"
> +#include "clang/AST/Attr.h"
> +#include "clang/AST/Decl.h"
> +#include "clang/AST/DeclCXX.h"
> +#include "clang/AST/ExprObjC.h"
> +#include "clang/AST/FormatString.h"
> +#include "clang/Basic/Builtins.h"
> +#include "llvm/ADT/SmallBitVector.h"
> +
> +using namespace clang;
> +
> +using clang::analyze_os_log::OSLogBufferItem;
> +using clang::analyze_os_log::OSLogBufferLayout;
> +
> +namespace {
> +class OSLogFormatStringHandler
> +    : public analyze_format_string::FormatStringHandler {
> +private:
> +  struct ArgData {
> +    const Expr *E = nullptr;
> +    Optional<OSLogBufferItem::Kind> Kind;
> +    Optional<unsigned> Size;
> +    Optional<const Expr *> Count;
> +    Optional<const Expr *> Precision;
> +    Optional<const Expr *> FieldWidth;
> +    unsigned char Flags = 0;
> +  };
> +  SmallVector<ArgData, 4> ArgsData;
> +  ArrayRef<const Expr *> Args;
> +
> +  OSLogBufferItem::Kind
> +  getKind(analyze_format_string::ConversionSpecifier::Kind K) {
> +    switch (K) {
> +    case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"
> +      return OSLogBufferItem::StringKind;
> +    case clang::analyze_format_string::ConversionSpecifier::SArg: // "%S"
> +      return OSLogBufferItem::WideStringKind;
> +    case clang::analyze_format_string::ConversionSpecifier::PArg: { //
> "%P"
> +      return OSLogBufferItem::PointerKind;
> +    case clang::analyze_format_string::ConversionSpecifier::ObjCObjArg:
> // "%@"
> +      return OSLogBufferItem::ObjCObjKind;
> +    case clang::analyze_format_string::ConversionSpecifier::PrintErrno:
> // "%m"
> +      return OSLogBufferItem::ErrnoKind;
> +    default:
> +      return OSLogBufferItem::ScalarKind;
> +    }
> +    }
> +  }
> +
> +public:
> +  OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {
> +    ArgsData.reserve(Args.size());
> +  }
> +
> +  virtual bool HandlePrintfSpecifier(const
> analyze_printf::PrintfSpecifier &FS,
> +                                     const char *StartSpecifier,
> +                                     unsigned SpecifierLen) {
> +    if (!FS.consumesDataArgument() &&
> +        FS.getConversionSpecifier().getKind() !=
> +            clang::analyze_format_string::ConversionSpecifier::PrintErrno)
> +      return true;
> +
> +    ArgsData.emplace_back();
> +    unsigned ArgIndex = FS.getArgIndex();
> +    if (ArgIndex < Args.size())
> +      ArgsData.back().E = Args[ArgIndex];
> +
> +    // First get the Kind
> +    ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());
> +    if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&
> +        !ArgsData.back().E) {
> +      // missing argument
> +      ArgsData.pop_back();
> +      return false;
> +    }
> +
> +    switch (FS.getConversionSpecifier().getKind()) {
> +    case clang::analyze_format_string::ConversionSpecifier::sArg:   //
> "%s"
> +    case clang::analyze_format_string::ConversionSpecifier::SArg: { //
> "%S"
> +      auto &precision = FS.getPrecision();
> +      switch (precision.getHowSpecified()) {
> +      case clang::analyze_format_string::OptionalAmount::NotSpecified: //
> "%s"
> +        break;
> +      case clang::analyze_format_string::OptionalAmount::Constant: //
> "%.16s"
> +        ArgsData.back().Size = precision.getConstantAmount();
> +        break;
> +      case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s"
> +        ArgsData.back().Count = Args[precision.getArgIndex()];
> +        break;
> +      case clang::analyze_format_string::OptionalAmount::Invalid:
> +        return false;
> +      }
> +      break;
> +    }
> +    case clang::analyze_format_string::ConversionSpecifier::PArg: { //
> "%P"
> +      auto &precision = FS.getPrecision();
> +      switch (precision.getHowSpecified()) {
> +      case clang::analyze_format_string::OptionalAmount::NotSpecified: //
> "%P"
> +        return false; // length must be supplied with pointer format
> specifier
> +      case clang::analyze_format_string::OptionalAmount::Constant: //
> "%.16P"
> +        ArgsData.back().Size = precision.getConstantAmount();
> +        break;
> +      case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P"
> +        ArgsData.back().Count = Args[precision.getArgIndex()];
> +        break;
> +      case clang::analyze_format_string::OptionalAmount::Invalid:
> +        return false;
> +      }
> +      break;
> +    }
> +    default:
> +      if (FS.getPrecision().hasDataArgument()) {
> +        ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];
> +      }
> +      break;
> +    }
> +    if (FS.getFieldWidth().hasDataArgument()) {
> +      ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];
> +    }
> +
> +    if (FS.isPrivate()) {
> +      ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;
> +    }
> +    if (FS.isPublic()) {
> +      ArgsData.back().Flags |= OSLogBufferItem::IsPublic;
> +    }
> +    return true;
> +  }
> +
> +  void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {
> +    Layout.Items.clear();
> +    for (auto &Data : ArgsData) {
> +      if (Data.FieldWidth) {
> +        CharUnits Size =
> Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());
> +        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind,
> *Data.FieldWidth,
> +                                  Size, 0);
> +      }
> +      if (Data.Precision) {
> +        CharUnits Size =
> Ctx.getTypeSizeInChars((*Data.Precision)->getType());
> +        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind,
> *Data.Precision,
> +                                  Size, 0);
> +      }
> +      if (Data.Count) {
> +        // "%.*P" has an extra "count" that we insert before the argument.
> +        CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());
> +        Layout.Items.emplace_back(OSLogBufferItem::CountKind,
> *Data.Count, Size,
> +                                  0);
> +      }
> +      if (Data.Size)
> +        Layout.Items.emplace_back(Ctx,
> CharUnits::fromQuantity(*Data.Size),
> +                                  Data.Flags);
> +      if (Data.Kind) {
> +        CharUnits Size;
> +        if (*Data.Kind == OSLogBufferItem::ErrnoKind)
> +          Size = CharUnits::Zero();
> +        else
> +          Size = Ctx.getTypeSizeInChars(Data.E->getType());
> +        Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);
> +      } else {
> +        auto Size = Ctx.getTypeSizeInChars(Data.E->getType());
> +        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E,
> Size,
> +                                  Data.Flags);
> +      }
> +    }
> +  }
> +};
> +} // end anonymous namespace
> +
> +bool clang::analyze_os_log::computeOSLogBufferLayout(
> +    ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {
> +  ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() +
> E->getNumArgs());
> +
> +  const Expr *StringArg;
> +  ArrayRef<const Expr *> VarArgs;
> +  switch (E->getBuiltinCallee()) {
> +  case Builtin::BI__builtin_os_log_format_buffer_size:
> +    assert(E->getNumArgs() >= 1 &&
> +           "__builtin_os_log_format_buffer_size takes at least 1
> argument");
> +    StringArg = E->getArg(0);
> +    VarArgs = Args.slice(1);
> +    break;
> +  case Builtin::BI__builtin_os_log_format:
> +    assert(E->getNumArgs() >= 2 &&
> +           "__builtin_os_log_format takes at least 2 arguments");
> +    StringArg = E->getArg(1);
> +    VarArgs = Args.slice(2);
> +    break;
> +  default:
> +    llvm_unreachable("non-os_log builtin passed to
> computeOSLogBufferLayout");
> +  }
> +
> +  const StringLiteral *Lit =
> cast<StringLiteral>(StringArg->IgnoreParenCasts());
> +  assert(Lit && (Lit->isAscii() || Lit->isUTF8()));
> +  StringRef Data = Lit->getString();
> +  OSLogFormatStringHandler H(VarArgs);
> +  ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),
> +                    Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);
> +
> +  H.computeLayout(Ctx, Layout);
> +  return true;
> +}
>
> Added: cfe/trunk/lib/AST/PrintfFormatString.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/PrintfFormatString.cpp?rev=345971&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/AST/PrintfFormatString.cpp (added)
> +++ cfe/trunk/lib/AST/PrintfFormatString.cpp Fri Nov  2 06:14:11 2018
> @@ -0,0 +1,1029 @@
> +//== PrintfFormatString.cpp - Analysis of printf format strings --*- C++
> -*-==//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// Handling of format string in printf and friends.  The structure of
> format
> +// strings for fprintf() are described in C99 7.19.6.1.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "clang/AST/FormatString.h"
> +#include "clang/AST/OSLog.h"
> +#include "FormatStringParsing.h"
> +#include "clang/Basic/TargetInfo.h"
> +
> +using clang::analyze_format_string::ArgType;
> +using clang::analyze_format_string::FormatStringHandler;
> +using clang::analyze_format_string::LengthModifier;
> +using clang::analyze_format_string::OptionalAmount;
> +using clang::analyze_format_string::ConversionSpecifier;
> +using clang::analyze_printf::PrintfSpecifier;
> +
> +using namespace clang;
> +
> +typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
> +        PrintfSpecifierResult;
> +
>
> +//===----------------------------------------------------------------------===//
> +// Methods for parsing format strings.
>
> +//===----------------------------------------------------------------------===//
> +
> +using analyze_format_string::ParseNonPositionAmount;
> +
> +static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
> +                           const char *Start, const char *&Beg, const
> char *E,
> +                           unsigned *argIndex) {
> +  if (argIndex) {
> +    FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
> +  } else {
> +    const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
> +
>  analyze_format_string::PrecisionPos);
> +    if (Amt.isInvalid())
> +      return true;
> +    FS.setPrecision(Amt);
> +  }
> +  return false;
> +}
> +
> +static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,
> +                           const char *FlagBeg, const char *E, bool Warn)
> {
> +   StringRef Flag(FlagBeg, E - FlagBeg);
> +   // Currently there is only one flag.
> +   if (Flag == "tt") {
> +     FS.setHasObjCTechnicalTerm(FlagBeg);
> +     return false;
> +   }
> +   // Handle either the case of no flag or an invalid flag.
> +   if (Warn) {
> +     if (Flag == "")
> +       H.HandleEmptyObjCModifierFlag(FlagBeg, E  - FlagBeg);
> +     else
> +       H.HandleInvalidObjCModifierFlag(FlagBeg, E  - FlagBeg);
> +   }
> +   return true;
> +}
> +
> +static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
> +                                                  const char *&Beg,
> +                                                  const char *E,
> +                                                  unsigned &argIndex,
> +                                                  const LangOptions &LO,
> +                                                  const TargetInfo
> &Target,
> +                                                  bool Warn,
> +                                                  bool isFreeBSDKPrintf) {
> +
> +  using namespace clang::analyze_format_string;
> +  using namespace clang::analyze_printf;
> +
> +  const char *I = Beg;
> +  const char *Start = nullptr;
> +  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
> +
> +  // Look for a '%' character that indicates the start of a format
> specifier.
> +  for ( ; I != E ; ++I) {
> +    char c = *I;
> +    if (c == '\0') {
> +      // Detect spurious null characters, which are likely errors.
> +      H.HandleNullChar(I);
> +      return true;
> +    }
> +    if (c == '%') {
> +      Start = I++;  // Record the start of the format specifier.
> +      break;
> +    }
> +  }
> +
> +  // No format specifier found?
> +  if (!Start)
> +    return false;
> +
> +  if (I == E) {
> +    // No more characters left?
> +    if (Warn)
> +      H.HandleIncompleteSpecifier(Start, E - Start);
> +    return true;
> +  }
> +
> +  PrintfSpecifier FS;
> +  if (ParseArgPosition(H, FS, Start, I, E))
> +    return true;
> +
> +  if (I == E) {
> +    // No more characters left?
> +    if (Warn)
> +      H.HandleIncompleteSpecifier(Start, E - Start);
> +    return true;
> +  }
> +
> +  if (*I == '{') {
> +    ++I;
> +    unsigned char PrivacyFlags = 0;
> +    StringRef MatchedStr;
> +
> +    do {
> +      StringRef Str(I, E - I);
> +      std::string Match = "^[\t\n\v\f\r ]*(private|public)[\t\n\v\f\r
> ]*(,|})";
> +      llvm::Regex R(Match);
> +      SmallVector<StringRef, 2> Matches;
> +
> +      if (R.match(Str, &Matches)) {
> +        MatchedStr = Matches[1];
> +        I += Matches[0].size();
> +
> +        // Set the privacy flag if the privacy annotation in the
> +        // comma-delimited segment is at least as strict as the privacy
> +        // annotations in previous comma-delimited segments.
> +        if (MatchedStr.equals("private"))
> +          PrivacyFlags =
> clang::analyze_os_log::OSLogBufferItem::IsPrivate;
> +        else if (PrivacyFlags == 0 && MatchedStr.equals("public"))
> +          PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic;
> +      } else {
> +        size_t CommaOrBracePos =
> +            Str.find_if([](char c) { return c == ',' || c == '}'; });
> +
> +        if (CommaOrBracePos == StringRef::npos) {
> +          // Neither a comma nor the closing brace was found.
> +          if (Warn)
> +            H.HandleIncompleteSpecifier(Start, E - Start);
> +          return true;
> +        }
> +
> +        I += CommaOrBracePos + 1;
> +      }
> +      // Continue until the closing brace is found.
> +    } while (*(I - 1) == ',');
> +
> +    // Set the privacy flag.
> +    switch (PrivacyFlags) {
> +    case 0:
> +      break;
> +    case clang::analyze_os_log::OSLogBufferItem::IsPrivate:
> +      FS.setIsPrivate(MatchedStr.data());
> +      break;
> +    case clang::analyze_os_log::OSLogBufferItem::IsPublic:
> +      FS.setIsPublic(MatchedStr.data());
> +      break;
> +    default:
> +      llvm_unreachable("Unexpected privacy flag value");
> +    }
> +  }
> +
> +  // Look for flags (if any).
> +  bool hasMore = true;
> +  for ( ; I != E; ++I) {
> +    switch (*I) {
> +      default: hasMore = false; break;
> +      case '\'':
> +        // FIXME: POSIX specific.  Always accept?
> +        FS.setHasThousandsGrouping(I);
> +        break;
> +      case '-': FS.setIsLeftJustified(I); break;
> +      case '+': FS.setHasPlusPrefix(I); break;
> +      case ' ': FS.setHasSpacePrefix(I); break;
> +      case '#': FS.setHasAlternativeForm(I); break;
> +      case '0': FS.setHasLeadingZeros(I); break;
> +    }
> +    if (!hasMore)
> +      break;
> +  }
> +
> +  if (I == E) {
> +    // No more characters left?
> +    if (Warn)
> +      H.HandleIncompleteSpecifier(Start, E - Start);
> +    return true;
> +  }
> +
> +  // Look for the field width (if any).
> +  if (ParseFieldWidth(H, FS, Start, I, E,
> +                      FS.usesPositionalArg() ? nullptr : &argIndex))
> +    return true;
> +
> +  if (I == E) {
> +    // No more characters left?
> +    if (Warn)
> +      H.HandleIncompleteSpecifier(Start, E - Start);
> +    return true;
> +  }
> +
> +  // Look for the precision (if any).
> +  if (*I == '.') {
> +    ++I;
> +    if (I == E) {
> +      if (Warn)
> +        H.HandleIncompleteSpecifier(Start, E - Start);
> +      return true;
> +    }
> +
> +    if (ParsePrecision(H, FS, Start, I, E,
> +                       FS.usesPositionalArg() ? nullptr : &argIndex))
> +      return true;
> +
> +    if (I == E) {
> +      // No more characters left?
> +      if (Warn)
> +        H.HandleIncompleteSpecifier(Start, E - Start);
> +      return true;
> +    }
> +  }
> +
> +  // Look for the length modifier.
> +  if (ParseLengthModifier(FS, I, E, LO) && I == E) {
> +    // No more characters left?
> +    if (Warn)
> +      H.HandleIncompleteSpecifier(Start, E - Start);
> +    return true;
> +  }
> +
> +  // Look for the Objective-C modifier flags, if any.
> +  // We parse these here, even if they don't apply to
> +  // the conversion specifier, and then emit an error
> +  // later if the conversion specifier isn't '@'.  This
> +  // enables better recovery, and we don't know if
> +  // these flags are applicable until later.
> +  const char *ObjCModifierFlagsStart = nullptr,
> +             *ObjCModifierFlagsEnd = nullptr;
> +  if (*I == '[') {
> +    ObjCModifierFlagsStart = I;
> +    ++I;
> +    auto flagStart = I;
> +    for (;; ++I) {
> +      ObjCModifierFlagsEnd = I;
> +      if (I == E) {
> +        if (Warn)
> +          H.HandleIncompleteSpecifier(Start, E - Start);
> +        return true;
> +      }
> +      // Did we find the closing ']'?
> +      if (*I == ']') {
> +        if (ParseObjCFlags(H, FS, flagStart, I, Warn))
> +          return true;
> +        ++I;
> +        break;
> +      }
> +      // There are no separators defined yet for multiple
> +      // Objective-C modifier flags.  When those are
> +      // defined, this is the place to check.
> +    }
> +  }
> +
> +  if (*I == '\0') {
> +    // Detect spurious null characters, which are likely errors.
> +    H.HandleNullChar(I);
> +    return true;
> +  }
> +
> +  // Finally, look for the conversion specifier.
> +  const char *conversionPosition = I++;
> +  ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
> +  switch (*conversionPosition) {
> +    default:
> +      break;
> +    // C99: 7.19.6.1 (section 8).
> +    case '%': k = ConversionSpecifier::PercentArg;   break;
> +    case 'A': k = ConversionSpecifier::AArg; break;
> +    case 'E': k = ConversionSpecifier::EArg; break;
> +    case 'F': k = ConversionSpecifier::FArg; break;
> +    case 'G': k = ConversionSpecifier::GArg; break;
> +    case 'X': k = ConversionSpecifier::XArg; break;
> +    case 'a': k = ConversionSpecifier::aArg; break;
> +    case 'c': k = ConversionSpecifier::cArg; break;
> +    case 'd': k = ConversionSpecifier::dArg; break;
> +    case 'e': k = ConversionSpecifier::eArg; break;
> +    case 'f': k = ConversionSpecifier::fArg; break;
> +    case 'g': k = ConversionSpecifier::gArg; break;
> +    case 'i': k = ConversionSpecifier::iArg; break;
> +    case 'n': k = ConversionSpecifier::nArg; break;
> +    case 'o': k = ConversionSpecifier::oArg; break;
> +    case 'p': k = ConversionSpecifier::pArg; break;
> +    case 's': k = ConversionSpecifier::sArg; break;
> +    case 'u': k = ConversionSpecifier::uArg; break;
> +    case 'x': k = ConversionSpecifier::xArg; break;
> +    // POSIX specific.
> +    case 'C': k = ConversionSpecifier::CArg; break;
> +    case 'S': k = ConversionSpecifier::SArg; break;
> +    // Apple extension for os_log
> +    case 'P':
> +      k = ConversionSpecifier::PArg;
> +      break;
> +    // Objective-C.
> +    case '@': k = ConversionSpecifier::ObjCObjArg; break;
> +    // Glibc specific.
> +    case 'm': k = ConversionSpecifier::PrintErrno; break;
> +    // FreeBSD kernel specific.
> +    case 'b':
> +      if (isFreeBSDKPrintf)
> +        k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
> +      break;
> +    case 'r':
> +      if (isFreeBSDKPrintf)
> +        k = ConversionSpecifier::FreeBSDrArg; // int
> +      break;
> +    case 'y':
> +      if (isFreeBSDKPrintf)
> +        k = ConversionSpecifier::FreeBSDyArg; // int
> +      break;
> +    // Apple-specific.
> +    case 'D':
> +      if (isFreeBSDKPrintf)
> +        k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *
> +      else if (Target.getTriple().isOSDarwin())
> +        k = ConversionSpecifier::DArg;
> +      break;
> +    case 'O':
> +      if (Target.getTriple().isOSDarwin())
> +        k = ConversionSpecifier::OArg;
> +      break;
> +    case 'U':
> +      if (Target.getTriple().isOSDarwin())
> +        k = ConversionSpecifier::UArg;
> +      break;
> +    // MS specific.
> +    case 'Z':
> +      if (Target.getTriple().isOSMSVCRT())
> +        k = ConversionSpecifier::ZArg;
> +  }
> +
> +  // Check to see if we used the Objective-C modifier flags with
> +  // a conversion specifier other than '@'.
> +  if (k != ConversionSpecifier::ObjCObjArg &&
> +      k != ConversionSpecifier::InvalidSpecifier &&
> +      ObjCModifierFlagsStart) {
> +    H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart,
> +                                           ObjCModifierFlagsEnd + 1,
> +                                           conversionPosition);
> +    return true;
> +  }
> +
> +  PrintfConversionSpecifier CS(conversionPosition, k);
> +  FS.setConversionSpecifier(CS);
> +  if (CS.consumesDataArgument() && !FS.usesPositionalArg())
> +    FS.setArgIndex(argIndex++);
> +  // FreeBSD kernel specific.
> +  if (k == ConversionSpecifier::FreeBSDbArg ||
> +      k == ConversionSpecifier::FreeBSDDArg)
> +    argIndex++;
> +
> +  if (k == ConversionSpecifier::InvalidSpecifier) {
> +    unsigned Len = I - Start;
> +    if (ParseUTF8InvalidSpecifier(Start, E, Len)) {
> +      CS.setEndScanList(Start + Len);
> +      FS.setConversionSpecifier(CS);
> +    }
> +    // Assume the conversion takes one argument.
> +    return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len);
> +  }
> +  return PrintfSpecifierResult(Start, FS);
> +}
> +
> +bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler
> &H,
> +                                                     const char *I,
> +                                                     const char *E,
> +                                                     const LangOptions
> &LO,
> +                                                     const TargetInfo
> &Target,
> +                                                     bool
> isFreeBSDKPrintf) {
> +
> +  unsigned argIndex = 0;
> +
> +  // Keep looking for a format specifier until we have exhausted the
> string.
> +  while (I != E) {
> +    const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E,
> argIndex,
> +                                                            LO, Target,
> true,
> +
> isFreeBSDKPrintf);
> +    // Did a fail-stop error of any kind occur when parsing the specifier?
> +    // If so, don't do any more processing.
> +    if (FSR.shouldStop())
> +      return true;
> +    // Did we exhaust the string or encounter an error that
> +    // we can recover from?
> +    if (!FSR.hasValue())
> +      continue;
> +    // We have a format specifier.  Pass it to the callback.
> +    if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
> +                                 I - FSR.getStart()))
> +      return true;
> +  }
> +  assert(I == E && "Format string not exhausted");
> +  return false;
> +}
> +
> +bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
> +                                                            const char *E,
> +                                                            const
> LangOptions &LO,
> +                                                            const
> TargetInfo &Target) {
> +
> +  unsigned argIndex = 0;
> +
> +  // Keep looking for a %s format specifier until we have exhausted the
> string.
> +  FormatStringHandler H;
> +  while (I != E) {
> +    const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E,
> argIndex,
> +                                                            LO, Target,
> false,
> +                                                            false);
> +    // Did a fail-stop error of any kind occur when parsing the specifier?
> +    // If so, don't do any more processing.
> +    if (FSR.shouldStop())
> +      return false;
> +    // Did we exhaust the string or encounter an error that
> +    // we can recover from?
> +    if (!FSR.hasValue())
> +      continue;
> +    const analyze_printf::PrintfSpecifier &FS = FSR.getValue();
> +    // Return true if this a %s format specifier.
> +    if (FS.getConversionSpecifier().getKind() ==
> ConversionSpecifier::Kind::sArg)
> +      return true;
> +  }
> +  return false;
> +}
> +
>
> +//===----------------------------------------------------------------------===//
> +// Methods on PrintfSpecifier.
>
> +//===----------------------------------------------------------------------===//
> +
> +ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
> +                                    bool IsObjCLiteral) const {
> +  const PrintfConversionSpecifier &CS = getConversionSpecifier();
> +
> +  if (!CS.consumesDataArgument())
> +    return ArgType::Invalid();
> +
> +  if (CS.getKind() == ConversionSpecifier::cArg)
> +    switch (LM.getKind()) {
> +      case LengthModifier::None:
> +        return Ctx.IntTy;
> +      case LengthModifier::AsLong:
> +      case LengthModifier::AsWide:
> +        return ArgType(ArgType::WIntTy, "wint_t");
> +      case LengthModifier::AsShort:
> +        if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
> +          return Ctx.IntTy;
> +        LLVM_FALLTHROUGH;
> +      default:
> +        return ArgType::Invalid();
> +    }
> +
> +  if (CS.isIntArg())
> +    switch (LM.getKind()) {
> +      case LengthModifier::AsLongDouble:
> +        // GNU extension.
> +        return Ctx.LongLongTy;
> +      case LengthModifier::None:
> +        return Ctx.IntTy;
> +      case LengthModifier::AsInt32:
> +        return ArgType(Ctx.IntTy, "__int32");
> +      case LengthModifier::AsChar: return ArgType::AnyCharTy;
> +      case LengthModifier::AsShort: return Ctx.ShortTy;
> +      case LengthModifier::AsLong: return Ctx.LongTy;
> +      case LengthModifier::AsLongLong:
> +      case LengthModifier::AsQuad:
> +        return Ctx.LongLongTy;
> +      case LengthModifier::AsInt64:
> +        return ArgType(Ctx.LongLongTy, "__int64");
> +      case LengthModifier::AsIntMax:
> +        return ArgType(Ctx.getIntMaxType(), "intmax_t");
> +      case LengthModifier::AsSizeT:
> +        return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(),
> "ssize_t"));
> +      case LengthModifier::AsInt3264:
> +        return Ctx.getTargetInfo().getTriple().isArch64Bit()
> +                   ? ArgType(Ctx.LongLongTy, "__int64")
> +                   : ArgType(Ctx.IntTy, "__int32");
> +      case LengthModifier::AsPtrDiff:
> +        return ArgType::makePtrdiffT(
> +            ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
> +      case LengthModifier::AsAllocate:
> +      case LengthModifier::AsMAllocate:
> +      case LengthModifier::AsWide:
> +        return ArgType::Invalid();
> +    }
> +
> +  if (CS.isUIntArg())
> +    switch (LM.getKind()) {
> +      case LengthModifier::AsLongDouble:
> +        // GNU extension.
> +        return Ctx.UnsignedLongLongTy;
> +      case LengthModifier::None:
> +        return Ctx.UnsignedIntTy;
> +      case LengthModifier::AsInt32:
> +        return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
> +      case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
> +      case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
> +      case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
> +      case LengthModifier::AsLongLong:
> +      case LengthModifier::AsQuad:
> +        return Ctx.UnsignedLongLongTy;
> +      case LengthModifier::AsInt64:
> +        return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
> +      case LengthModifier::AsIntMax:
> +        return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
> +      case LengthModifier::AsSizeT:
> +        return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));
> +      case LengthModifier::AsInt3264:
> +        return Ctx.getTargetInfo().getTriple().isArch64Bit()
> +                   ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
> +                   : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
> +      case LengthModifier::AsPtrDiff:
> +        return ArgType::makePtrdiffT(
> +            ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned
> ptrdiff_t"));
> +      case LengthModifier::AsAllocate:
> +      case LengthModifier::AsMAllocate:
> +      case LengthModifier::AsWide:
> +        return ArgType::Invalid();
> +    }
> +
> +  if (CS.isDoubleArg()) {
> +    if (LM.getKind() == LengthModifier::AsLongDouble)
> +      return Ctx.LongDoubleTy;
> +    return Ctx.DoubleTy;
> +  }
> +
> +  if (CS.getKind() == ConversionSpecifier::nArg) {
> +    switch (LM.getKind()) {
> +      case LengthModifier::None:
> +        return ArgType::PtrTo(Ctx.IntTy);
> +      case LengthModifier::AsChar:
> +        return ArgType::PtrTo(Ctx.SignedCharTy);
> +      case LengthModifier::AsShort:
> +        return ArgType::PtrTo(Ctx.ShortTy);
> +      case LengthModifier::AsLong:
> +        return ArgType::PtrTo(Ctx.LongTy);
> +      case LengthModifier::AsLongLong:
> +      case LengthModifier::AsQuad:
> +        return ArgType::PtrTo(Ctx.LongLongTy);
> +      case LengthModifier::AsIntMax:
> +        return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
> +      case LengthModifier::AsSizeT:
> +        return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(),
> "ssize_t"));
> +      case LengthModifier::AsPtrDiff:
> +        return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(),
> "ptrdiff_t"));
> +      case LengthModifier::AsLongDouble:
> +        return ArgType(); // FIXME: Is this a known extension?
> +      case LengthModifier::AsAllocate:
> +      case LengthModifier::AsMAllocate:
> +      case LengthModifier::AsInt32:
> +      case LengthModifier::AsInt3264:
> +      case LengthModifier::AsInt64:
> +      case LengthModifier::AsWide:
> +        return ArgType::Invalid();
> +    }
> +  }
> +
> +  switch (CS.getKind()) {
> +    case ConversionSpecifier::sArg:
> +      if (LM.getKind() == LengthModifier::AsWideChar) {
> +        if (IsObjCLiteral)
> +          return
> ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
> +                         "const unichar *");
> +        return ArgType(ArgType::WCStrTy, "wchar_t *");
> +      }
> +      if (LM.getKind() == LengthModifier::AsWide)
> +        return ArgType(ArgType::WCStrTy, "wchar_t *");
> +      return ArgType::CStrTy;
> +    case ConversionSpecifier::SArg:
> +      if (IsObjCLiteral)
> +        return
> ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
> +                       "const unichar *");
> +      if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
> +          LM.getKind() == LengthModifier::AsShort)
> +        return ArgType::CStrTy;
> +      return ArgType(ArgType::WCStrTy, "wchar_t *");
> +    case ConversionSpecifier::CArg:
> +      if (IsObjCLiteral)
> +        return ArgType(Ctx.UnsignedShortTy, "unichar");
> +      if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
> +          LM.getKind() == LengthModifier::AsShort)
> +        return Ctx.IntTy;
> +      return ArgType(Ctx.WideCharTy, "wchar_t");
> +    case ConversionSpecifier::pArg:
> +    case ConversionSpecifier::PArg:
> +      return ArgType::CPointerTy;
> +    case ConversionSpecifier::ObjCObjArg:
> +      return ArgType::ObjCPointerTy;
> +    default:
> +      break;
> +  }
> +
> +  // FIXME: Handle other cases.
> +  return ArgType();
> +}
> +
> +bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
> +                              ASTContext &Ctx, bool IsObjCLiteral) {
> +  // %n is different from other conversion specifiers; don't try to fix
> it.
> +  if (CS.getKind() == ConversionSpecifier::nArg)
> +    return false;
> +
> +  // Handle Objective-C objects first. Note that while the '%@' specifier
> will
> +  // not warn for structure pointer or void pointer arguments (because
> that's
> +  // how CoreFoundation objects are implemented), we only show a fixit
> for '%@'
> +  // if we know it's an object (block, id, class, or
> __attribute__((NSObject))).
> +  if (QT->isObjCRetainableType()) {
> +    if (!IsObjCLiteral)
> +      return false;
> +
> +    CS.setKind(ConversionSpecifier::ObjCObjArg);
> +
> +    // Disable irrelevant flags
> +    HasThousandsGrouping = false;
> +    HasPlusPrefix = false;
> +    HasSpacePrefix = false;
> +    HasAlternativeForm = false;
> +    HasLeadingZeroes = false;
> +    Precision.setHowSpecified(OptionalAmount::NotSpecified);
> +    LM.setKind(LengthModifier::None);
> +
> +    return true;
> +  }
> +
> +  // Handle strings next (char *, wchar_t *)
> +  if (QT->isPointerType() &&
> (QT->getPointeeType()->isAnyCharacterType())) {
> +    CS.setKind(ConversionSpecifier::sArg);
> +
> +    // Disable irrelevant flags
> +    HasAlternativeForm = 0;
> +    HasLeadingZeroes = 0;
> +
> +    // Set the long length modifier for wide characters
> +    if (QT->getPointeeType()->isWideCharType())
> +      LM.setKind(LengthModifier::AsWideChar);
> +    else
> +      LM.setKind(LengthModifier::None);
> +
> +    return true;
> +  }
> +
> +  // If it's an enum, get its underlying type.
> +  if (const EnumType *ETy = QT->getAs<EnumType>())
> +    QT = ETy->getDecl()->getIntegerType();
> +
> +  // We can only work with builtin types.
> +  const BuiltinType *BT = QT->getAs<BuiltinType>();
> +  if (!BT)
> +    return false;
> +
> +  // Set length modifier
> +  switch (BT->getKind()) {
> +  case BuiltinType::Bool:
> +  case BuiltinType::WChar_U:
> +  case BuiltinType::WChar_S:
> +  case BuiltinType::Char8: // FIXME: Treat like 'char'?
> +  case BuiltinType::Char16:
> +  case BuiltinType::Char32:
> +  case BuiltinType::UInt128:
> +  case BuiltinType::Int128:
> +  case BuiltinType::Half:
> +  case BuiltinType::Float16:
> +  case BuiltinType::Float128:
> +  case BuiltinType::ShortAccum:
> +  case BuiltinType::Accum:
> +  case BuiltinType::LongAccum:
> +  case BuiltinType::UShortAccum:
> +  case BuiltinType::UAccum:
> +  case BuiltinType::ULongAccum:
> +  case BuiltinType::ShortFract:
> +  case BuiltinType::Fract:
> +  case BuiltinType::LongFract:
> +  case BuiltinType::UShortFract:
> +  case BuiltinType::UFract:
> +  case BuiltinType::ULongFract:
> +  case BuiltinType::SatShortAccum:
> +  case BuiltinType::SatAccum:
> +  case BuiltinType::SatLongAccum:
> +  case BuiltinType::SatUShortAccum:
> +  case BuiltinType::SatUAccum:
> +  case BuiltinType::SatULongAccum:
> +  case BuiltinType::SatShortFract:
> +  case BuiltinType::SatFract:
> +  case BuiltinType::SatLongFract:
> +  case BuiltinType::SatUShortFract:
> +  case BuiltinType::SatUFract:
> +  case BuiltinType::SatULongFract:
> +    // Various types which are non-trivial to correct.
> +    return false;
> +
> +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
> +  case BuiltinType::Id:
> +#include "clang/Basic/OpenCLImageTypes.def"
> +#define SIGNED_TYPE(Id, SingletonId)
> +#define UNSIGNED_TYPE(Id, SingletonId)
> +#define FLOATING_TYPE(Id, SingletonId)
> +#define BUILTIN_TYPE(Id, SingletonId) \
> +  case BuiltinType::Id:
> +#include "clang/AST/BuiltinTypes.def"
> +    // Misc other stuff which doesn't make sense here.
> +    return false;
> +
> +  case BuiltinType::UInt:
> +  case BuiltinType::Int:
> +  case BuiltinType::Float:
> +  case BuiltinType::Double:
> +    LM.setKind(LengthModifier::None);
> +    break;
> +
> +  case BuiltinType::Char_U:
> +  case BuiltinType::UChar:
> +  case BuiltinType::Char_S:
> +  case BuiltinType::SChar:
> +    LM.setKind(LengthModifier::AsChar);
> +    break;
> +
> +  case BuiltinType::Short:
> +  case BuiltinType::UShort:
> +    LM.setKind(LengthModifier::AsShort);
> +    break;
> +
> +  case BuiltinType::Long:
> +  case BuiltinType::ULong:
> +    LM.setKind(LengthModifier::AsLong);
> +    break;
> +
> +  case BuiltinType::LongLong:
> +  case BuiltinType::ULongLong:
> +    LM.setKind(LengthModifier::AsLongLong);
> +    break;
> +
> +  case BuiltinType::LongDouble:
> +    LM.setKind(LengthModifier::AsLongDouble);
> +    break;
> +  }
> +
> +  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers
> in C99.
> +  if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
> +    namedTypeToLengthModifier(QT, LM);
> +
> +  // If fixing the length modifier was enough, we might be done.
> +  if (hasValidLengthModifier(Ctx.getTargetInfo())) {
> +    // If we're going to offer a fix anyway, make sure the sign matches.
> +    switch (CS.getKind()) {
> +    case ConversionSpecifier::uArg:
> +    case ConversionSpecifier::UArg:
> +      if (QT->isSignedIntegerType())
> +
> CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
> +      break;
> +    case ConversionSpecifier::dArg:
> +    case ConversionSpecifier::DArg:
> +    case ConversionSpecifier::iArg:
> +      if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
> +
> CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
> +      break;
> +    default:
> +      // Other specifiers do not have signed/unsigned variants.
> +      break;
> +    }
> +
> +    const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
> +    if (ATR.isValid() && ATR.matchesType(Ctx, QT))
> +      return true;
> +  }
> +
> +  // Set conversion specifier and disable any flags which do not apply to
> it.
> +  // Let typedefs to char fall through to int, as %c is silly for uint8_t.
> +  if (!isa<TypedefType>(QT) && QT->isCharType()) {
> +    CS.setKind(ConversionSpecifier::cArg);
> +    LM.setKind(LengthModifier::None);
> +    Precision.setHowSpecified(OptionalAmount::NotSpecified);
> +    HasAlternativeForm = 0;
> +    HasLeadingZeroes = 0;
> +    HasPlusPrefix = 0;
> +  }
> +  // Test for Floating type first as LongDouble can pass
> isUnsignedIntegerType
> +  else if (QT->isRealFloatingType()) {
> +    CS.setKind(ConversionSpecifier::fArg);
> +  }
> +  else if (QT->isSignedIntegerType()) {
> +    CS.setKind(ConversionSpecifier::dArg);
> +    HasAlternativeForm = 0;
> +  }
> +  else if (QT->isUnsignedIntegerType()) {
> +    CS.setKind(ConversionSpecifier::uArg);
> +    HasAlternativeForm = 0;
> +    HasPlusPrefix = 0;
> +  } else {
> +    llvm_unreachable("Unexpected type");
> +  }
> +
> +  return true;
> +}
> +
> +void PrintfSpecifier::toString(raw_ostream &os) const {
> +  // Whilst some features have no defined order, we are using the order
> +  // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
> +  os << "%";
> +
> +  // Positional args
> +  if (usesPositionalArg()) {
> +    os << getPositionalArgIndex() << "$";
> +  }
> +
> +  // Conversion flags
> +  if (IsLeftJustified)    os << "-";
> +  if (HasPlusPrefix)      os << "+";
> +  if (HasSpacePrefix)     os << " ";
> +  if (HasAlternativeForm) os << "#";
> +  if (HasLeadingZeroes)   os << "0";
> +
> +  // Minimum field width
> +  FieldWidth.toString(os);
> +  // Precision
> +  Precision.toString(os);
> +  // Length modifier
> +  os << LM.toString();
> +  // Conversion specifier
> +  os << CS.toString();
> +}
> +
> +bool PrintfSpecifier::hasValidPlusPrefix() const {
> +  if (!HasPlusPrefix)
> +    return true;
> +
> +  // The plus prefix only makes sense for signed conversions
> +  switch (CS.getKind()) {
> +  case ConversionSpecifier::dArg:
> +  case ConversionSpecifier::DArg:
> +  case ConversionSpecifier::iArg:
> +  case ConversionSpecifier::fArg:
> +  case ConversionSpecifier::FArg:
> +  case ConversionSpecifier::eArg:
> +  case ConversionSpecifier::EArg:
> +  case ConversionSpecifier::gArg:
> +  case ConversionSpecifier::GArg:
> +  case ConversionSpecifier::aArg:
> +  case ConversionSpecifier::AArg:
> +  case ConversionSpecifier::FreeBSDrArg:
> +  case ConversionSpecifier::FreeBSDyArg:
> +    return true;
> +
> +  default:
> +    return false;
> +  }
> +}
> +
> +bool PrintfSpecifier::hasValidAlternativeForm() const {
> +  if (!HasAlternativeForm)
> +    return true;
> +
> +  // Alternate form flag only valid with the oxXaAeEfFgG conversions
> +  switch (CS.getKind()) {
> +  case ConversionSpecifier::oArg:
> +  case ConversionSpecifier::OArg:
> +  case ConversionSpecifier::xArg:
> +  case ConversionSpecifier::XArg:
> +  case ConversionSpecifier::aArg:
> +  case ConversionSpecifier::AArg:
> +  case ConversionSpecifier::eArg:
> +  case ConversionSpecifier::EArg:
> +  case ConversionSpecifier::fArg:
> +  case ConversionSpecifier::FArg:
> +  case ConversionSpecifier::gArg:
> +  case ConversionSpecifier::GArg:
> +  case ConversionSpecifier::FreeBSDrArg:
> +  case ConversionSpecifier::FreeBSDyArg:
> +    return true;
> +
> +  default:
> +    return false;
> +  }
> +}
> +
> +bool PrintfSpecifier::hasValidLeadingZeros() const {
> +  if (!HasLeadingZeroes)
> +    return true;
> +
> +  // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
> +  switch (CS.getKind()) {
> +  case ConversionSpecifier::dArg:
> +  case ConversionSpecifier::DArg:
> +  case ConversionSpecifier::iArg:
> +  case ConversionSpecifier::oArg:
> +  case ConversionSpecifier::OArg:
> +  case ConversionSpecifier::uArg:
> +  case ConversionSpecifier::UArg:
> +  case ConversionSpecifier::xArg:
> +  case ConversionSpecifier::XArg:
> +  case ConversionSpecifier::aArg:
> +  case ConversionSpecifier::AArg:
> +  case ConversionSpecifier::eArg:
> +  case ConversionSpecifier::EArg:
> +  case ConversionSpecifier::fArg:
> +  case ConversionSpecifier::FArg:
> +  case ConversionSpecifier::gArg:
> +  case ConversionSpecifier::GArg:
> +  case ConversionSpecifier::FreeBSDrArg:
> +  case ConversionSpecifier::FreeBSDyArg:
> +    return true;
> +
> +  default:
> +    return false;
> +  }
> +}
> +
> +bool PrintfSpecifier::hasValidSpacePrefix() const {
> +  if (!HasSpacePrefix)
> +    return true;
> +
> +  // The space prefix only makes sense for signed conversions
> +  switch (CS.getKind()) {
> +  case ConversionSpecifier::dArg:
> +  case ConversionSpecifier::DArg:
> +  case ConversionSpecifier::iArg:
> +  case ConversionSpecifier::fArg:
> +  case ConversionSpecifier::FArg:
> +  case ConversionSpecifier::eArg:
> +  case ConversionSpecifier::EArg:
> +  case ConversionSpecifier::gArg:
> +  case ConversionSpecifier::GArg:
> +  case ConversionSpecifier::aArg:
> +  case ConversionSpecifier::AArg:
> +  case ConversionSpecifier::FreeBSDrArg:
> +  case ConversionSpecifier::FreeBSDyArg:
> +    return true;
> +
> +  default:
> +    return false;
> +  }
> +}
> +
> +bool PrintfSpecifier::hasValidLeftJustified() const {
> +  if (!IsLeftJustified)
> +    return true;
> +
> +  // The left justified flag is valid for all conversions except n
> +  switch (CS.getKind()) {
> +  case ConversionSpecifier::nArg:
> +    return false;
> +
> +  default:
> +    return true;
> +  }
> +}
> +
> +bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
> +  if (!HasThousandsGrouping)
> +    return true;
> +
> +  switch (CS.getKind()) {
> +    case ConversionSpecifier::dArg:
> +    case ConversionSpecifier::DArg:
> +    case ConversionSpecifier::iArg:
> +    case ConversionSpecifier::uArg:
> +    case ConversionSpecifier::UArg:
> +    case ConversionSpecifier::fArg:
> +    case ConversionSpecifier::FArg:
> +    case ConversionSpecifier::gArg:
> +    case ConversionSpecifier::GArg:
> +      return true;
> +    default:
> +      return false;
> +  }
> +}
> +
> +bool PrintfSpecifier::hasValidPrecision() const {
> +  if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
> +    return true;
> +
> +  // Precision is only valid with the diouxXaAeEfFgGsP conversions
> +  switch (CS.getKind()) {
> +  case ConversionSpecifier::dArg:
> +  case ConversionSpecifier::DArg:
> +  case ConversionSpecifier::iArg:
> +  case ConversionSpecifier::oArg:
> +  case ConversionSpecifier::OArg:
> +  case ConversionSpecifier::uArg:
> +  case ConversionSpecifier::UArg:
> +  case ConversionSpecifier::xArg:
> +  case ConversionSpecifier::XArg:
> +  case ConversionSpecifier::aArg:
> +  case ConversionSpecifier::AArg:
> +  case ConversionSpecifier::eArg:
> +  case ConversionSpecifier::EArg:
> +  case ConversionSpecifier::fArg:
> +  case ConversionSpecifier::FArg:
> +  case ConversionSpecifier::gArg:
> +  case ConversionSpecifier::GArg:
> +  case ConversionSpecifier::sArg:
> +  case ConversionSpecifier::FreeBSDrArg:
> +  case ConversionSpecifier::FreeBSDyArg:
> +  case ConversionSpecifier::PArg:
> +    return true;
> +
> +  default:
> +    return false;
> +  }
> +}
> +bool PrintfSpecifier::hasValidFieldWidth() const {
> +  if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
> +      return true;
> +
> +  // The field width is valid for all conversions except n
> +  switch (CS.getKind()) {
> +  case ConversionSpecifier::nArg:
> +    return false;
> +
> +  default:
> +    return true;
> +  }
> +}
>
> Added: cfe/trunk/lib/AST/ScanfFormatString.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ScanfFormatString.cpp?rev=345971&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ScanfFormatString.cpp (added)
> +++ cfe/trunk/lib/AST/ScanfFormatString.cpp Fri Nov  2 06:14:11 2018
> @@ -0,0 +1,563 @@
> +//= ScanfFormatString.cpp - Analysis of printf format strings --*- C++
> -*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// Handling of format string in scanf and friends.  The structure of
> format
> +// strings for fscanf() are described in C99 7.19.6.2.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "clang/AST/FormatString.h"
> +#include "FormatStringParsing.h"
> +#include "clang/Basic/TargetInfo.h"
> +
> +using clang::analyze_format_string::ArgType;
> +using clang::analyze_format_string::FormatStringHandler;
> +using clang::analyze_format_string::LengthModifier;
> +using clang::analyze_format_string::OptionalAmount;
> +using clang::analyze_format_string::ConversionSpecifier;
> +using clang::analyze_scanf::ScanfConversionSpecifier;
> +using clang::analyze_scanf::ScanfSpecifier;
> +using clang::UpdateOnReturn;
> +using namespace clang;
> +
> +typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier>
> +        ScanfSpecifierResult;
> +
> +static bool ParseScanList(FormatStringHandler &H,
> +                          ScanfConversionSpecifier &CS,
> +                          const char *&Beg, const char *E) {
> +  const char *I = Beg;
> +  const char *start = I - 1;
> +  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
> +
> +  // No more characters?
> +  if (I == E) {
> +    H.HandleIncompleteScanList(start, I);
> +    return true;
> +  }
> +
> +  // Special case: ']' is the first character.
> +  if (*I == ']') {
> +    if (++I == E) {
> +      H.HandleIncompleteScanList(start, I - 1);
> +      return true;
> +    }
> +  }
> +
> +  // Special case: "^]" are the first characters.
> +  if (I + 1 != E && I[0] == '^' && I[1] == ']') {
> +    I += 2;
> +    if (I == E) {
> +      H.HandleIncompleteScanList(start, I - 1);
> +      return true;
> +    }
> +  }
> +
> +  // Look for a ']' character which denotes the end of the scan list.
> +  while (*I != ']') {
> +    if (++I == E) {
> +      H.HandleIncompleteScanList(start, I - 1);
> +      return true;
> +    }
> +  }
> +
> +  CS.setEndScanList(I);
> +  return false;
> +}
> +
> +// FIXME: Much of this is copy-paste from ParsePrintfSpecifier.
> +// We can possibly refactor.
> +static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
> +                                                const char *&Beg,
> +                                                const char *E,
> +                                                unsigned &argIndex,
> +                                                const LangOptions &LO,
> +                                                const TargetInfo &Target)
> {
> +  using namespace clang::analyze_format_string;
> +  using namespace clang::analyze_scanf;
> +  const char *I = Beg;
> +  const char *Start = nullptr;
> +  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
> +
> +    // Look for a '%' character that indicates the start of a format
> specifier.
> +  for ( ; I != E ; ++I) {
> +    char c = *I;
> +    if (c == '\0') {
> +        // Detect spurious null characters, which are likely errors.
> +      H.HandleNullChar(I);
> +      return true;
> +    }
> +    if (c == '%') {
> +      Start = I++;  // Record the start of the format specifier.
> +      break;
> +    }
> +  }
> +
> +    // No format specifier found?
> +  if (!Start)
> +    return false;
> +
> +  if (I == E) {
> +      // No more characters left?
> +    H.HandleIncompleteSpecifier(Start, E - Start);
> +    return true;
> +  }
> +
> +  ScanfSpecifier FS;
> +  if (ParseArgPosition(H, FS, Start, I, E))
> +    return true;
> +
> +  if (I == E) {
> +      // No more characters left?
> +    H.HandleIncompleteSpecifier(Start, E - Start);
> +    return true;
> +  }
> +
> +  // Look for '*' flag if it is present.
> +  if (*I == '*') {
> +    FS.setSuppressAssignment(I);
> +    if (++I == E) {
> +      H.HandleIncompleteSpecifier(Start, E - Start);
> +      return true;
> +    }
> +  }
> +
> +  // Look for the field width (if any).  Unlike printf, this is either
> +  // a fixed integer or isn't present.
> +  const OptionalAmount &Amt =
> clang::analyze_format_string::ParseAmount(I, E);
> +  if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {
> +    assert(Amt.getHowSpecified() == OptionalAmount::Constant);
> +    FS.setFieldWidth(Amt);
> +
> +    if (I == E) {
> +      // No more characters left?
> +      H.HandleIncompleteSpecifier(Start, E - Start);
> +      return true;
> +    }
> +  }
> +
> +  // Look for the length modifier.
> +  if (ParseLengthModifier(FS, I, E, LO, /*scanf=*/true) && I == E) {
> +      // No more characters left?
> +    H.HandleIncompleteSpecifier(Start, E - Start);
> +    return true;
> +  }
> +
> +  // Detect spurious null characters, which are likely errors.
> +  if (*I == '\0') {
> +    H.HandleNullChar(I);
> +    return true;
> +  }
> +
> +  // Finally, look for the conversion specifier.
> +  const char *conversionPosition = I++;
> +  ScanfConversionSpecifier::Kind k =
> ScanfConversionSpecifier::InvalidSpecifier;
> +  switch (*conversionPosition) {
> +    default:
> +      break;
> +    case '%': k = ConversionSpecifier::PercentArg;   break;
> +    case 'A': k = ConversionSpecifier::AArg; break;
> +    case 'E': k = ConversionSpecifier::EArg; break;
> +    case 'F': k = ConversionSpecifier::FArg; break;
> +    case 'G': k = ConversionSpecifier::GArg; break;
> +    case 'X': k = ConversionSpecifier::XArg; break;
> +    case 'a': k = ConversionSpecifier::aArg; break;
> +    case 'd': k = ConversionSpecifier::dArg; break;
> +    case 'e': k = ConversionSpecifier::eArg; break;
> +    case 'f': k = ConversionSpecifier::fArg; break;
> +    case 'g': k = ConversionSpecifier::gArg; break;
> +    case 'i': k = ConversionSpecifier::iArg; break;
> +    case 'n': k = ConversionSpecifier::nArg; break;
> +    case 'c': k = ConversionSpecifier::cArg; break;
> +    case 'C': k = ConversionSpecifier::CArg; break;
> +    case 'S': k = ConversionSpecifier::SArg; break;
> +    case '[': k = ConversionSpecifier::ScanListArg; break;
> +    case 'u': k = ConversionSpecifier::uArg; break;
> +    case 'x': k = ConversionSpecifier::xArg; break;
> +    case 'o': k = ConversionSpecifier::oArg; break;
> +    case 's': k = ConversionSpecifier::sArg; break;
> +    case 'p': k = ConversionSpecifier::pArg; break;
> +    // Apple extensions
> +      // Apple-specific
> +    case 'D':
> +      if (Target.getTriple().isOSDarwin())
> +        k = ConversionSpecifier::DArg;
> +      break;
> +    case 'O':
> +      if (Target.getTriple().isOSDarwin())
> +        k = ConversionSpecifier::OArg;
> +      break;
> +    case 'U':
> +      if (Target.getTriple().isOSDarwin())
> +        k = ConversionSpecifier::UArg;
> +      break;
> +  }
> +  ScanfConversionSpecifier CS(conversionPosition, k);
> +  if (k == ScanfConversionSpecifier::ScanListArg) {
> +    if (ParseScanList(H, CS, I, E))
> +      return true;
> +  }
> +  FS.setConversionSpecifier(CS);
> +  if (CS.consumesDataArgument() && !FS.getSuppressAssignment()
> +      && !FS.usesPositionalArg())
> +    FS.setArgIndex(argIndex++);
> +
> +  // FIXME: '%' and '*' doesn't make sense.  Issue a warning.
> +  // FIXME: 'ConsumedSoFar' and '*' doesn't make sense.
> +
> +  if (k == ScanfConversionSpecifier::InvalidSpecifier) {
> +    unsigned Len = I - Beg;
> +    if (ParseUTF8InvalidSpecifier(Beg, E, Len)) {
> +      CS.setEndScanList(Beg + Len);
> +      FS.setConversionSpecifier(CS);
> +    }
> +    // Assume the conversion takes one argument.
> +    return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len);
> +  }
> +  return ScanfSpecifierResult(Start, FS);
> +}
> +
> +ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
> +  const ScanfConversionSpecifier &CS = getConversionSpecifier();
> +
> +  if (!CS.consumesDataArgument())
> +    return ArgType::Invalid();
> +
> +  switch(CS.getKind()) {
> +    // Signed int.
> +    case ConversionSpecifier::dArg:
> +    case ConversionSpecifier::DArg:
> +    case ConversionSpecifier::iArg:
> +      switch (LM.getKind()) {
> +        case LengthModifier::None:
> +          return ArgType::PtrTo(Ctx.IntTy);
> +        case LengthModifier::AsChar:
> +          return ArgType::PtrTo(ArgType::AnyCharTy);
> +        case LengthModifier::AsShort:
> +          return ArgType::PtrTo(Ctx.ShortTy);
> +        case LengthModifier::AsLong:
> +          return ArgType::PtrTo(Ctx.LongTy);
> +        case LengthModifier::AsLongLong:
> +        case LengthModifier::AsQuad:
> +          return ArgType::PtrTo(Ctx.LongLongTy);
> +        case LengthModifier::AsInt64:
> +          return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
> +        case LengthModifier::AsIntMax:
> +          return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
> +        case LengthModifier::AsSizeT:
> +          return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(),
> "ssize_t"));
> +        case LengthModifier::AsPtrDiff:
> +          return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(),
> "ptrdiff_t"));
> +        case LengthModifier::AsLongDouble:
> +          // GNU extension.
> +          return ArgType::PtrTo(Ctx.LongLongTy);
> +        case LengthModifier::AsAllocate:
> +        case LengthModifier::AsMAllocate:
> +        case LengthModifier::AsInt32:
> +        case LengthModifier::AsInt3264:
> +        case LengthModifier::AsWide:
> +          return ArgType::Invalid();
> +      }
> +
> +    // Unsigned int.
> +    case ConversionSpecifier::oArg:
> +    case ConversionSpecifier::OArg:
> +    case ConversionSpecifier::uArg:
> +    case ConversionSpecifier::UArg:
> +    case ConversionSpecifier::xArg:
> +    case ConversionSpecifier::XArg:
> +      switch (LM.getKind()) {
> +        case LengthModifier::None:
> +          return ArgType::PtrTo(Ctx.UnsignedIntTy);
> +        case LengthModifier::AsChar:
> +          return ArgType::PtrTo(Ctx.UnsignedCharTy);
> +        case LengthModifier::AsShort:
> +          return ArgType::PtrTo(Ctx.UnsignedShortTy);
> +        case LengthModifier::AsLong:
> +          return ArgType::PtrTo(Ctx.UnsignedLongTy);
> +        case LengthModifier::AsLongLong:
> +        case LengthModifier::AsQuad:
> +          return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
> +        case LengthModifier::AsInt64:
> +          return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned
> __int64"));
> +        case LengthModifier::AsIntMax:
> +          return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(),
> "uintmax_t"));
> +        case LengthModifier::AsSizeT:
> +          return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
> +        case LengthModifier::AsPtrDiff:
> +          return ArgType::PtrTo(
> +              ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned
> ptrdiff_t"));
> +        case LengthModifier::AsLongDouble:
> +          // GNU extension.
> +          return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
> +        case LengthModifier::AsAllocate:
> +        case LengthModifier::AsMAllocate:
> +        case LengthModifier::AsInt32:
> +        case LengthModifier::AsInt3264:
> +        case LengthModifier::AsWide:
> +          return ArgType::Invalid();
> +      }
> +
> +    // Float.
> +    case ConversionSpecifier::aArg:
> +    case ConversionSpecifier::AArg:
> +    case ConversionSpecifier::eArg:
> +    case ConversionSpecifier::EArg:
> +    case ConversionSpecifier::fArg:
> +    case ConversionSpecifier::FArg:
> +    case ConversionSpecifier::gArg:
> +    case ConversionSpecifier::GArg:
> +      switch (LM.getKind()) {
> +        case LengthModifier::None:
> +          return ArgType::PtrTo(Ctx.FloatTy);
> +        case LengthModifier::AsLong:
> +          return ArgType::PtrTo(Ctx.DoubleTy);
> +        case LengthModifier::AsLongDouble:
> +          return ArgType::PtrTo(Ctx.LongDoubleTy);
> +        default:
> +          return ArgType::Invalid();
> +      }
> +
> +    // Char, string and scanlist.
> +    case ConversionSpecifier::cArg:
> +    case ConversionSpecifier::sArg:
> +    case ConversionSpecifier::ScanListArg:
> +      switch (LM.getKind()) {
> +        case LengthModifier::None:
> +          return ArgType::PtrTo(ArgType::AnyCharTy);
> +        case LengthModifier::AsLong:
> +        case LengthModifier::AsWide:
> +          return ArgType::PtrTo(ArgType(Ctx.getWideCharType(),
> "wchar_t"));
> +        case LengthModifier::AsAllocate:
> +        case LengthModifier::AsMAllocate:
> +          return ArgType::PtrTo(ArgType::CStrTy);
> +        case LengthModifier::AsShort:
> +          if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
> +            return ArgType::PtrTo(ArgType::AnyCharTy);
> +          LLVM_FALLTHROUGH;
> +        default:
> +          return ArgType::Invalid();
> +      }
> +    case ConversionSpecifier::CArg:
> +    case ConversionSpecifier::SArg:
> +      // FIXME: Mac OS X specific?
> +      switch (LM.getKind()) {
> +        case LengthModifier::None:
> +        case LengthModifier::AsWide:
> +          return ArgType::PtrTo(ArgType(Ctx.getWideCharType(),
> "wchar_t"));
> +        case LengthModifier::AsAllocate:
> +        case LengthModifier::AsMAllocate:
> +          return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
> +        case LengthModifier::AsShort:
> +          if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
> +            return ArgType::PtrTo(ArgType::AnyCharTy);
> +          LLVM_FALLTHROUGH;
> +        default:
> +          return ArgType::Invalid();
> +      }
> +
> +    // Pointer.
> +    case ConversionSpecifier::pArg:
> +      return ArgType::PtrTo(ArgType::CPointerTy);
> +
> +    // Write-back.
> +    case ConversionSpecifier::nArg:
> +      switch (LM.getKind()) {
> +        case LengthModifier::None:
> +          return ArgType::PtrTo(Ctx.IntTy);
> +        case LengthModifier::AsChar:
> +          return ArgType::PtrTo(Ctx.SignedCharTy);
> +        case LengthModifier::AsShort:
> +          return ArgType::PtrTo(Ctx.ShortTy);
> +        case LengthModifier::AsLong:
> +          return ArgType::PtrTo(Ctx.LongTy);
> +        case LengthModifier::AsLongLong:
> +        case LengthModifier::AsQuad:
> +          return ArgType::PtrTo(Ctx.LongLongTy);
> +        case LengthModifier::AsInt64:
> +          return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
> +        case LengthModifier::AsIntMax:
> +          return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
> +        case LengthModifier::AsSizeT:
> +          return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(),
> "ssize_t"));
> +        case LengthModifier::AsPtrDiff:
> +          return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(),
> "ptrdiff_t"));
> +        case LengthModifier::AsLongDouble:
> +          return ArgType(); // FIXME: Is this a known extension?
> +        case LengthModifier::AsAllocate:
> +        case LengthModifier::AsMAllocate:
> +        case LengthModifier::AsInt32:
> +        case LengthModifier::AsInt3264:
> +        case LengthModifier::AsWide:
> +          return ArgType::Invalid();
> +        }
> +
> +    default:
> +      break;
> +  }
> +
> +  return ArgType();
> +}
> +
> +bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
> +                             const LangOptions &LangOpt,
> +                             ASTContext &Ctx) {
> +
> +  // %n is different from other conversion specifiers; don't try to fix
> it.
> +  if (CS.getKind() == ConversionSpecifier::nArg)
> +    return false;
> +
> +  if (!QT->isPointerType())
> +    return false;
> +
> +  QualType PT = QT->getPointeeType();
> +
> +  // If it's an enum, get its underlying type.
> +  if (const EnumType *ETy = PT->getAs<EnumType>()) {
> +    // Don't try to fix incomplete enums.
> +    if (!ETy->getDecl()->isComplete())
> +      return false;
> +    PT = ETy->getDecl()->getIntegerType();
> +  }
> +
> +  const BuiltinType *BT = PT->getAs<BuiltinType>();
> +  if (!BT)
> +    return false;
> +
> +  // Pointer to a character.
> +  if (PT->isAnyCharacterType()) {
> +    CS.setKind(ConversionSpecifier::sArg);
> +    if (PT->isWideCharType())
> +      LM.setKind(LengthModifier::AsWideChar);
> +    else
> +      LM.setKind(LengthModifier::None);
> +
> +    // If we know the target array length, we can use it as a field width.
> +    if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT))
> {
> +      if (CAT->getSizeModifier() == ArrayType::Normal)
> +        FieldWidth = OptionalAmount(OptionalAmount::Constant,
> +                                    CAT->getSize().getZExtValue() - 1,
> +                                    "", 0, false);
> +
> +    }
> +    return true;
> +  }
> +
> +  // Figure out the length modifier.
> +  switch (BT->getKind()) {
> +    // no modifier
> +    case BuiltinType::UInt:
> +    case BuiltinType::Int:
> +    case BuiltinType::Float:
> +      LM.setKind(LengthModifier::None);
> +      break;
> +
> +    // hh
> +    case BuiltinType::Char_U:
> +    case BuiltinType::UChar:
> +    case BuiltinType::Char_S:
> +    case BuiltinType::SChar:
> +      LM.setKind(LengthModifier::AsChar);
> +      break;
> +
> +    // h
> +    case BuiltinType::Short:
> +    case BuiltinType::UShort:
> +      LM.setKind(LengthModifier::AsShort);
> +      break;
> +
> +    // l
> +    case BuiltinType::Long:
> +    case BuiltinType::ULong:
> +    case BuiltinType::Double:
> +      LM.setKind(LengthModifier::AsLong);
> +      break;
> +
> +    // ll
> +    case BuiltinType::LongLong:
> +    case BuiltinType::ULongLong:
> +      LM.setKind(LengthModifier::AsLongLong);
> +      break;
> +
> +    // L
> +    case BuiltinType::LongDouble:
> +      LM.setKind(LengthModifier::AsLongDouble);
> +      break;
> +
> +    // Don't know.
> +    default:
> +      return false;
> +  }
> +
> +  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers
> in C99.
> +  if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
> +    namedTypeToLengthModifier(PT, LM);
> +
> +  // If fixing the length modifier was enough, we are done.
> +  if (hasValidLengthModifier(Ctx.getTargetInfo())) {
> +    const analyze_scanf::ArgType &AT = getArgType(Ctx);
> +    if (AT.isValid() && AT.matchesType(Ctx, QT))
> +      return true;
> +  }
> +
> +  // Figure out the conversion specifier.
> +  if (PT->isRealFloatingType())
> +    CS.setKind(ConversionSpecifier::fArg);
> +  else if (PT->isSignedIntegerType())
> +    CS.setKind(ConversionSpecifier::dArg);
> +  else if (PT->isUnsignedIntegerType())
> +    CS.setKind(ConversionSpecifier::uArg);
> +  else
> +    llvm_unreachable("Unexpected type");
> +
> +  return true;
> +}
> +
> +void ScanfSpecifier::toString(raw_ostream &os) const {
> +  os << "%";
> +
> +  if (usesPositionalArg())
> +    os << getPositionalArgIndex() << "$";
> +  if (SuppressAssignment)
> +    os << "*";
> +
> +  FieldWidth.toString(os);
> +  os << LM.toString();
> +  os << CS.toString();
> +}
> +
> +bool clang::analyze_format_string::ParseScanfString(FormatStringHandler
> &H,
> +                                                    const char *I,
> +                                                    const char *E,
> +                                                    const LangOptions &LO,
> +                                                    const TargetInfo
> &Target) {
> +
> +  unsigned argIndex = 0;
> +
> +  // Keep looking for a format specifier until we have exhausted the
> string.
> +  while (I != E) {
> +    const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E,
> argIndex,
> +                                                          LO, Target);
> +    // Did a fail-stop error of any kind occur when parsing the specifier?
> +    // If so, don't do any more processing.
> +    if (FSR.shouldStop())
> +      return true;
> +      // Did we exhaust the string or encounter an error that
> +      // we can recover from?
> +    if (!FSR.hasValue())
> +      continue;
> +      // We have a format specifier.  Pass it to the callback.
> +    if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(),
> +                                I - FSR.getStart())) {
> +      return true;
> +    }
> +  }
> +  assert(I == E && "Format string not exhausted");
> +  return false;
> +}
>
> Modified: cfe/trunk/lib/Analysis/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=345971&r1=345970&r2=345971&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/CMakeLists.txt (original)
> +++ cfe/trunk/lib/Analysis/CMakeLists.txt Fri Nov  2 06:14:11 2018
> @@ -16,15 +16,11 @@ add_clang_library(clangAnalysis
>    CodeInjector.cpp
>    Dominators.cpp
>    ExprMutationAnalyzer.cpp
> -  FormatString.cpp
>    LiveVariables.cpp
> -  OSLog.cpp
>    ObjCNoReturn.cpp
>    PostOrderCFGView.cpp
> -  PrintfFormatString.cpp
>    ProgramPoint.cpp
>    ReachableCode.cpp
> -  ScanfFormatString.cpp
>    ThreadSafety.cpp
>    ThreadSafetyCommon.cpp
>    ThreadSafetyLogical.cpp
>
> Removed: cfe/trunk/lib/Analysis/FormatString.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/FormatString.cpp?rev=345970&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/FormatString.cpp (original)
> +++ cfe/trunk/lib/Analysis/FormatString.cpp (removed)
> @@ -1,955 +0,0 @@
> -// FormatString.cpp - Common stuff for handling printf/scanf formats -*-
> C++ -*-
> -//
> -//                     The LLVM Compiler Infrastructure
> -//
> -// This file is distributed under the University of Illinois Open Source
> -// License. See LICENSE.TXT for details.
> -//
>
> -//===----------------------------------------------------------------------===//
> -//
> -// Shared details for processing format strings of printf and scanf
> -// (and friends).
> -//
>
> -//===----------------------------------------------------------------------===//
> -
> -#include "FormatStringParsing.h"
> -#include "clang/Basic/LangOptions.h"
> -#include "clang/Basic/TargetInfo.h"
> -#include "llvm/Support/ConvertUTF.h"
> -
> -using clang::analyze_format_string::ArgType;
> -using clang::analyze_format_string::FormatStringHandler;
> -using clang::analyze_format_string::FormatSpecifier;
> -using clang::analyze_format_string::LengthModifier;
> -using clang::analyze_format_string::OptionalAmount;
> -using clang::analyze_format_string::PositionContext;
> -using clang::analyze_format_string::ConversionSpecifier;
> -using namespace clang;
> -
> -// Key function to FormatStringHandler.
> -FormatStringHandler::~FormatStringHandler() {}
> -
>
> -//===----------------------------------------------------------------------===//
> -// Functions for parsing format strings components in both printf and
> -// scanf format strings.
>
> -//===----------------------------------------------------------------------===//
> -
> -OptionalAmount
> -clang::analyze_format_string::ParseAmount(const char *&Beg, const char
> *E) {
> -  const char *I = Beg;
> -  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
> -
> -  unsigned accumulator = 0;
> -  bool hasDigits = false;
> -
> -  for ( ; I != E; ++I) {
> -    char c = *I;
> -    if (c >= '0' && c <= '9') {
> -      hasDigits = true;
> -      accumulator = (accumulator * 10) + (c - '0');
> -      continue;
> -    }
> -
> -    if (hasDigits)
> -      return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I
> - Beg,
> -          false);
> -
> -    break;
> -  }
> -
> -  return OptionalAmount();
> -}
> -
> -OptionalAmount
> -clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg,
> -                                                     const char *E,
> -                                                     unsigned &argIndex) {
> -  if (*Beg == '*') {
> -    ++Beg;
> -    return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
> -  }
> -
> -  return ParseAmount(Beg, E);
> -}
> -
> -OptionalAmount
> -clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H,
> -                                                  const char *Start,
> -                                                  const char *&Beg,
> -                                                  const char *E,
> -                                                  PositionContext p) {
> -  if (*Beg == '*') {
> -    const char *I = Beg + 1;
> -    const OptionalAmount &Amt = ParseAmount(I, E);
> -
> -    if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
> -      H.HandleInvalidPosition(Beg, I - Beg, p);
> -      return OptionalAmount(false);
> -    }
> -
> -    if (I == E) {
> -      // No more characters left?
> -      H.HandleIncompleteSpecifier(Start, E - Start);
> -      return OptionalAmount(false);
> -    }
> -
> -    assert(Amt.getHowSpecified() == OptionalAmount::Constant);
> -
> -    if (*I == '$') {
> -      // Handle positional arguments
> -
> -      // Special case: '*0$', since this is an easy mistake.
> -      if (Amt.getConstantAmount() == 0) {
> -        H.HandleZeroPosition(Beg, I - Beg + 1);
> -        return OptionalAmount(false);
> -      }
> -
> -      const char *Tmp = Beg;
> -      Beg = ++I;
> -
> -      return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount()
> - 1,
> -                            Tmp, 0, true);
> -    }
> -
> -    H.HandleInvalidPosition(Beg, I - Beg, p);
> -    return OptionalAmount(false);
> -  }
> -
> -  return ParseAmount(Beg, E);
> -}
> -
> -
> -bool
> -clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H,
> -                                              FormatSpecifier &CS,
> -                                              const char *Start,
> -                                              const char *&Beg, const
> char *E,
> -                                              unsigned *argIndex) {
> -  // FIXME: Support negative field widths.
> -  if (argIndex) {
> -    CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
> -  }
> -  else {
> -    const OptionalAmount Amt =
> -      ParsePositionAmount(H, Start, Beg, E,
> -                          analyze_format_string::FieldWidthPos);
> -
> -    if (Amt.isInvalid())
> -      return true;
> -    CS.setFieldWidth(Amt);
> -  }
> -  return false;
> -}
> -
> -bool
> -clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
> -                                               FormatSpecifier &FS,
> -                                               const char *Start,
> -                                               const char *&Beg,
> -                                               const char *E) {
> -  const char *I = Beg;
> -
> -  const OptionalAmount &Amt = ParseAmount(I, E);
> -
> -  if (I == E) {
> -    // No more characters left?
> -    H.HandleIncompleteSpecifier(Start, E - Start);
> -    return true;
> -  }
> -
> -  if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$')
> {
> -    // Warn that positional arguments are non-standard.
> -    H.HandlePosition(Start, I - Start);
> -
> -    // Special case: '%0$', since this is an easy mistake.
> -    if (Amt.getConstantAmount() == 0) {
> -      H.HandleZeroPosition(Start, I - Start);
> -      return true;
> -    }
> -
> -    FS.setArgIndex(Amt.getConstantAmount() - 1);
> -    FS.setUsesPositionalArg();
> -    // Update the caller's pointer if we decided to consume
> -    // these characters.
> -    Beg = I;
> -    return false;
> -  }
> -
> -  return false;
> -}
> -
> -bool
> -clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
> -                                                  const char *&I,
> -                                                  const char *E,
> -                                                  const LangOptions &LO,
> -                                                  bool IsScanf) {
> -  LengthModifier::Kind lmKind = LengthModifier::None;
> -  const char *lmPosition = I;
> -  switch (*I) {
> -    default:
> -      return false;
> -    case 'h':
> -      ++I;
> -      if (I != E && *I == 'h') {
> -        ++I;
> -        lmKind = LengthModifier::AsChar;
> -      } else {
> -        lmKind = LengthModifier::AsShort;
> -      }
> -      break;
> -    case 'l':
> -      ++I;
> -      if (I != E && *I == 'l') {
> -        ++I;
> -        lmKind = LengthModifier::AsLongLong;
> -      } else {
> -        lmKind = LengthModifier::AsLong;
> -      }
> -      break;
> -    case 'j': lmKind = LengthModifier::AsIntMax;     ++I; break;
> -    case 'z': lmKind = LengthModifier::AsSizeT;      ++I; break;
> -    case 't': lmKind = LengthModifier::AsPtrDiff;    ++I; break;
> -    case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
> -    case 'q': lmKind = LengthModifier::AsQuad;       ++I; break;
> -    case 'a':
> -      if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {
> -        // For scanf in C90, look at the next character to see if this
> should
> -        // be parsed as the GNU extension 'a' length modifier. If not,
> this
> -        // will be parsed as a conversion specifier.
> -        ++I;
> -        if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {
> -          lmKind = LengthModifier::AsAllocate;
> -          break;
> -        }
> -        --I;
> -      }
> -      return false;
> -    case 'm':
> -      if (IsScanf) {
> -        lmKind = LengthModifier::AsMAllocate;
> -        ++I;
> -        break;
> -      }
> -      return false;
> -    // printf: AsInt64, AsInt32, AsInt3264
> -    // scanf:  AsInt64
> -    case 'I':
> -      if (I + 1 != E && I + 2 != E) {
> -        if (I[1] == '6' && I[2] == '4') {
> -          I += 3;
> -          lmKind = LengthModifier::AsInt64;
> -          break;
> -        }
> -        if (IsScanf)
> -          return false;
> -
> -        if (I[1] == '3' && I[2] == '2') {
> -          I += 3;
> -          lmKind = LengthModifier::AsInt32;
> -          break;
> -        }
> -      }
> -      ++I;
> -      lmKind = LengthModifier::AsInt3264;
> -      break;
> -    case 'w':
> -      lmKind = LengthModifier::AsWide; ++I; break;
> -  }
> -  LengthModifier lm(lmPosition, lmKind);
> -  FS.setLengthModifier(lm);
> -  return true;
> -}
> -
> -bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(
> -    const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len) {
> -  if (SpecifierBegin + 1 >= FmtStrEnd)
> -    return false;
> -
> -  const llvm::UTF8 *SB =
> -      reinterpret_cast<const llvm::UTF8 *>(SpecifierBegin + 1);
> -  const llvm::UTF8 *SE = reinterpret_cast<const llvm::UTF8 *>(FmtStrEnd);
> -  const char FirstByte = *SB;
> -
> -  // If the invalid specifier is a multibyte UTF-8 string, return the
> -  // total length accordingly so that the conversion specifier can be
> -  // properly updated to reflect a complete UTF-8 specifier.
> -  unsigned NumBytes = llvm::getNumBytesForUTF8(FirstByte);
> -  if (NumBytes == 1)
> -    return false;
> -  if (SB + NumBytes > SE)
> -    return false;
> -
> -  Len = NumBytes + 1;
> -  return true;
> -}
> -
>
> -//===----------------------------------------------------------------------===//
> -// Methods on ArgType.
>
> -//===----------------------------------------------------------------------===//
> -
> -clang::analyze_format_string::ArgType::MatchKind
> -ArgType::matchesType(ASTContext &C, QualType argTy) const {
> -  if (Ptr) {
> -    // It has to be a pointer.
> -    const PointerType *PT = argTy->getAs<PointerType>();
> -    if (!PT)
> -      return NoMatch;
> -
> -    // We cannot write through a const qualified pointer.
> -    if (PT->getPointeeType().isConstQualified())
> -      return NoMatch;
> -
> -    argTy = PT->getPointeeType();
> -  }
> -
> -  switch (K) {
> -    case InvalidTy:
> -      llvm_unreachable("ArgType must be valid");
> -
> -    case UnknownTy:
> -      return Match;
> -
> -    case AnyCharTy: {
> -      if (const EnumType *ETy = argTy->getAs<EnumType>()) {
> -        // If the enum is incomplete we know nothing about the underlying
> type.
> -        // Assume that it's 'int'.
> -        if (!ETy->getDecl()->isComplete())
> -          return NoMatch;
> -        argTy = ETy->getDecl()->getIntegerType();
> -      }
> -
> -      if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
> -        switch (BT->getKind()) {
> -          default:
> -            break;
> -          case BuiltinType::Char_S:
> -          case BuiltinType::SChar:
> -          case BuiltinType::UChar:
> -          case BuiltinType::Char_U:
> -            return Match;
> -        }
> -      return NoMatch;
> -    }
> -
> -    case SpecificTy: {
> -      if (const EnumType *ETy = argTy->getAs<EnumType>()) {
> -        // If the enum is incomplete we know nothing about the underlying
> type.
> -        // Assume that it's 'int'.
> -        if (!ETy->getDecl()->isComplete())
> -          argTy = C.IntTy;
> -        else
> -          argTy = ETy->getDecl()->getIntegerType();
> -      }
> -      argTy = C.getCanonicalType(argTy).getUnqualifiedType();
> -
> -      if (T == argTy)
> -        return Match;
> -      // Check for "compatible types".
> -      if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
> -        switch (BT->getKind()) {
> -          default:
> -            break;
> -          case BuiltinType::Char_S:
> -          case BuiltinType::SChar:
> -          case BuiltinType::Char_U:
> -          case BuiltinType::UChar:
> -            return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match
> -                                                                : NoMatch;
> -          case BuiltinType::Short:
> -            return T == C.UnsignedShortTy ? Match : NoMatch;
> -          case BuiltinType::UShort:
> -            return T == C.ShortTy ? Match : NoMatch;
> -          case BuiltinType::Int:
> -            return T == C.UnsignedIntTy ? Match : NoMatch;
> -          case BuiltinType::UInt:
> -            return T == C.IntTy ? Match : NoMatch;
> -          case BuiltinType::Long:
> -            return T == C.UnsignedLongTy ? Match : NoMatch;
> -          case BuiltinType::ULong:
> -            return T == C.LongTy ? Match : NoMatch;
> -          case BuiltinType::LongLong:
> -            return T == C.UnsignedLongLongTy ? Match : NoMatch;
> -          case BuiltinType::ULongLong:
> -            return T == C.LongLongTy ? Match : NoMatch;
> -        }
> -      return NoMatch;
> -    }
> -
> -    case CStrTy: {
> -      const PointerType *PT = argTy->getAs<PointerType>();
> -      if (!PT)
> -        return NoMatch;
> -      QualType pointeeTy = PT->getPointeeType();
> -      if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
> -        switch (BT->getKind()) {
> -          case BuiltinType::Void:
> -          case BuiltinType::Char_U:
> -          case BuiltinType::UChar:
> -          case BuiltinType::Char_S:
> -          case BuiltinType::SChar:
> -            return Match;
> -          default:
> -            break;
> -        }
> -
> -      return NoMatch;
> -    }
> -
> -    case WCStrTy: {
> -      const PointerType *PT = argTy->getAs<PointerType>();
> -      if (!PT)
> -        return NoMatch;
> -      QualType pointeeTy =
> -        C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
> -      return pointeeTy == C.getWideCharType() ? Match : NoMatch;
> -    }
> -
> -    case WIntTy: {
> -      QualType WInt =
> C.getCanonicalType(C.getWIntType()).getUnqualifiedType();
> -
> -      if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)
> -        return Match;
> -
> -      QualType PromoArg = argTy->isPromotableIntegerType()
> -                              ? C.getPromotedIntegerType(argTy)
> -                              : argTy;
> -      PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();
> -
> -      // If the promoted argument is the corresponding signed type of the
> -      // wint_t type, then it should match.
> -      if (PromoArg->hasSignedIntegerRepresentation() &&
> -          C.getCorrespondingUnsignedType(PromoArg) == WInt)
> -        return Match;
> -
> -      return WInt == PromoArg ? Match : NoMatch;
> -    }
> -
> -    case CPointerTy:
> -      if (argTy->isVoidPointerType()) {
> -        return Match;
> -      } if (argTy->isPointerType() || argTy->isObjCObjectPointerType() ||
> -            argTy->isBlockPointerType() || argTy->isNullPtrType()) {
> -        return NoMatchPedantic;
> -      } else {
> -        return NoMatch;
> -      }
> -
> -    case ObjCPointerTy: {
> -      if (argTy->getAs<ObjCObjectPointerType>() ||
> -          argTy->getAs<BlockPointerType>())
> -        return Match;
> -
> -      // Handle implicit toll-free bridging.
> -      if (const PointerType *PT = argTy->getAs<PointerType>()) {
> -        // Things such as CFTypeRef are really just opaque pointers
> -        // to C structs representing CF types that can often be bridged
> -        // to Objective-C objects.  Since the compiler doesn't know which
> -        // structs can be toll-free bridged, we just accept them all.
> -        QualType pointee = PT->getPointeeType();
> -        if (pointee->getAsStructureType() || pointee->isVoidType())
> -          return Match;
> -      }
> -      return NoMatch;
> -    }
> -  }
> -
> -  llvm_unreachable("Invalid ArgType Kind!");
> -}
> -
> -QualType ArgType::getRepresentativeType(ASTContext &C) const {
> -  QualType Res;
> -  switch (K) {
> -    case InvalidTy:
> -      llvm_unreachable("No representative type for Invalid ArgType");
> -    case UnknownTy:
> -      llvm_unreachable("No representative type for Unknown ArgType");
> -    case AnyCharTy:
> -      Res = C.CharTy;
> -      break;
> -    case SpecificTy:
> -      Res = T;
> -      break;
> -    case CStrTy:
> -      Res = C.getPointerType(C.CharTy);
> -      break;
> -    case WCStrTy:
> -      Res = C.getPointerType(C.getWideCharType());
> -      break;
> -    case ObjCPointerTy:
> -      Res = C.ObjCBuiltinIdTy;
> -      break;
> -    case CPointerTy:
> -      Res = C.VoidPtrTy;
> -      break;
> -    case WIntTy: {
> -      Res = C.getWIntType();
> -      break;
> -    }
> -  }
> -
> -  if (Ptr)
> -    Res = C.getPointerType(Res);
> -  return Res;
> -}
> -
> -std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {
> -  std::string S = getRepresentativeType(C).getAsString();
> -
> -  std::string Alias;
> -  if (Name) {
> -    // Use a specific name for this type, e.g. "size_t".
> -    Alias = Name;
> -    if (Ptr) {
> -      // If ArgType is actually a pointer to T, append an asterisk.
> -      Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *";
> -    }
> -    // If Alias is the same as the underlying type, e.g. wchar_t, then
> drop it.
> -    if (S == Alias)
> -      Alias.clear();
> -  }
> -
> -  if (!Alias.empty())
> -    return std::string("'") + Alias + "' (aka '" + S + "')";
> -  return std::string("'") + S + "'";
> -}
> -
> -
>
> -//===----------------------------------------------------------------------===//
> -// Methods on OptionalAmount.
>
> -//===----------------------------------------------------------------------===//
> -
> -ArgType
> -analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {
> -  return Ctx.IntTy;
> -}
> -
>
> -//===----------------------------------------------------------------------===//
> -// Methods on LengthModifier.
>
> -//===----------------------------------------------------------------------===//
> -
> -const char *
> -analyze_format_string::LengthModifier::toString() const {
> -  switch (kind) {
> -  case AsChar:
> -    return "hh";
> -  case AsShort:
> -    return "h";
> -  case AsLong: // or AsWideChar
> -    return "l";
> -  case AsLongLong:
> -    return "ll";
> -  case AsQuad:
> -    return "q";
> -  case AsIntMax:
> -    return "j";
> -  case AsSizeT:
> -    return "z";
> -  case AsPtrDiff:
> -    return "t";
> -  case AsInt32:
> -    return "I32";
> -  case AsInt3264:
> -    return "I";
> -  case AsInt64:
> -    return "I64";
> -  case AsLongDouble:
> -    return "L";
> -  case AsAllocate:
> -    return "a";
> -  case AsMAllocate:
> -    return "m";
> -  case AsWide:
> -    return "w";
> -  case None:
> -    return "";
> -  }
> -  return nullptr;
> -}
> -
>
> -//===----------------------------------------------------------------------===//
> -// Methods on ConversionSpecifier.
>
> -//===----------------------------------------------------------------------===//
> -
> -const char *ConversionSpecifier::toString() const {
> -  switch (kind) {
> -  case dArg: return "d";
> -  case DArg: return "D";
> -  case iArg: return "i";
> -  case oArg: return "o";
> -  case OArg: return "O";
> -  case uArg: return "u";
> -  case UArg: return "U";
> -  case xArg: return "x";
> -  case XArg: return "X";
> -  case fArg: return "f";
> -  case FArg: return "F";
> -  case eArg: return "e";
> -  case EArg: return "E";
> -  case gArg: return "g";
> -  case GArg: return "G";
> -  case aArg: return "a";
> -  case AArg: return "A";
> -  case cArg: return "c";
> -  case sArg: return "s";
> -  case pArg: return "p";
> -  case PArg:
> -    return "P";
> -  case nArg: return "n";
> -  case PercentArg:  return "%";
> -  case ScanListArg: return "[";
> -  case InvalidSpecifier: return nullptr;
> -
> -  // POSIX unicode extensions.
> -  case CArg: return "C";
> -  case SArg: return "S";
> -
> -  // Objective-C specific specifiers.
> -  case ObjCObjArg: return "@";
> -
> -  // FreeBSD kernel specific specifiers.
> -  case FreeBSDbArg: return "b";
> -  case FreeBSDDArg: return "D";
> -  case FreeBSDrArg: return "r";
> -  case FreeBSDyArg: return "y";
> -
> -  // GlibC specific specifiers.
> -  case PrintErrno: return "m";
> -
> -  // MS specific specifiers.
> -  case ZArg: return "Z";
> -  }
> -  return nullptr;
> -}
> -
> -Optional<ConversionSpecifier>
> -ConversionSpecifier::getStandardSpecifier() const {
> -  ConversionSpecifier::Kind NewKind;
> -
> -  switch (getKind()) {
> -  default:
> -    return None;
> -  case DArg:
> -    NewKind = dArg;
> -    break;
> -  case UArg:
> -    NewKind = uArg;
> -    break;
> -  case OArg:
> -    NewKind = oArg;
> -    break;
> -  }
> -
> -  ConversionSpecifier FixedCS(*this);
> -  FixedCS.setKind(NewKind);
> -  return FixedCS;
> -}
> -
>
> -//===----------------------------------------------------------------------===//
> -// Methods on OptionalAmount.
>
> -//===----------------------------------------------------------------------===//
> -
> -void OptionalAmount::toString(raw_ostream &os) const {
> -  switch (hs) {
> -  case Invalid:
> -  case NotSpecified:
> -    return;
> -  case Arg:
> -    if (UsesDotPrefix)
> -        os << ".";
> -    if (usesPositionalArg())
> -      os << "*" << getPositionalArgIndex() << "$";
> -    else
> -      os << "*";
> -    break;
> -  case Constant:
> -    if (UsesDotPrefix)
> -        os << ".";
> -    os << amt;
> -    break;
> -  }
> -}
> -
> -bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target)
> const {
> -  switch (LM.getKind()) {
> -    case LengthModifier::None:
> -      return true;
> -
> -    // Handle most integer flags
> -    case LengthModifier::AsShort:
> -      if (Target.getTriple().isOSMSVCRT()) {
> -        switch (CS.getKind()) {
> -          case ConversionSpecifier::cArg:
> -          case ConversionSpecifier::CArg:
> -          case ConversionSpecifier::sArg:
> -          case ConversionSpecifier::SArg:
> -          case ConversionSpecifier::ZArg:
> -            return true;
> -          default:
> -            break;
> -        }
> -      }
> -      LLVM_FALLTHROUGH;
> -    case LengthModifier::AsChar:
> -    case LengthModifier::AsLongLong:
> -    case LengthModifier::AsQuad:
> -    case LengthModifier::AsIntMax:
> -    case LengthModifier::AsSizeT:
> -    case LengthModifier::AsPtrDiff:
> -      switch (CS.getKind()) {
> -        case ConversionSpecifier::dArg:
> -        case ConversionSpecifier::DArg:
> -        case ConversionSpecifier::iArg:
> -        case ConversionSpecifier::oArg:
> -        case ConversionSpecifier::OArg:
> -        case ConversionSpecifier::uArg:
> -        case ConversionSpecifier::UArg:
> -        case ConversionSpecifier::xArg:
> -        case ConversionSpecifier::XArg:
> -        case ConversionSpecifier::nArg:
> -          return true;
> -        case ConversionSpecifier::FreeBSDrArg:
> -        case ConversionSpecifier::FreeBSDyArg:
> -          return Target.getTriple().isOSFreeBSD() ||
> Target.getTriple().isPS4();
> -        default:
> -          return false;
> -      }
> -
> -    // Handle 'l' flag
> -    case LengthModifier::AsLong: // or AsWideChar
> -      switch (CS.getKind()) {
> -        case ConversionSpecifier::dArg:
> -        case ConversionSpecifier::DArg:
> -        case ConversionSpecifier::iArg:
> -        case ConversionSpecifier::oArg:
> -        case ConversionSpecifier::OArg:
> -        case ConversionSpecifier::uArg:
> -        case ConversionSpecifier::UArg:
> -        case ConversionSpecifier::xArg:
> -        case ConversionSpecifier::XArg:
> -        case ConversionSpecifier::aArg:
> -        case ConversionSpecifier::AArg:
> -        case ConversionSpecifier::fArg:
> -        case ConversionSpecifier::FArg:
> -        case ConversionSpecifier::eArg:
> -        case ConversionSpecifier::EArg:
> -        case ConversionSpecifier::gArg:
> -        case ConversionSpecifier::GArg:
> -        case ConversionSpecifier::nArg:
> -        case ConversionSpecifier::cArg:
> -        case ConversionSpecifier::sArg:
> -        case ConversionSpecifier::ScanListArg:
> -        case ConversionSpecifier::ZArg:
> -          return true;
> -        case ConversionSpecifier::FreeBSDrArg:
> -        case ConversionSpecifier::FreeBSDyArg:
> -          return Target.getTriple().isOSFreeBSD() ||
> Target.getTriple().isPS4();
> -        default:
> -          return false;
> -      }
> -
> -    case LengthModifier::AsLongDouble:
> -      switch (CS.getKind()) {
> -        case ConversionSpecifier::aArg:
> -        case ConversionSpecifier::AArg:
> -        case ConversionSpecifier::fArg:
> -        case ConversionSpecifier::FArg:
> -        case ConversionSpecifier::eArg:
> -        case ConversionSpecifier::EArg:
> -        case ConversionSpecifier::gArg:
> -        case ConversionSpecifier::GArg:
> -          return true;
> -        // GNU libc extension.
> -        case ConversionSpecifier::dArg:
> -        case ConversionSpecifier::iArg:
> -        case ConversionSpecifier::oArg:
> -        case ConversionSpecifier::uArg:
> -        case ConversionSpecifier::xArg:
> -        case ConversionSpecifier::XArg:
> -          return !Target.getTriple().isOSDarwin() &&
> -                 !Target.getTriple().isOSWindows();
> -        default:
> -          return false;
> -      }
> -
> -    case LengthModifier::AsAllocate:
> -      switch (CS.getKind()) {
> -        case ConversionSpecifier::sArg:
> -        case ConversionSpecifier::SArg:
> -        case ConversionSpecifier::ScanListArg:
> -          return true;
> -        default:
> -          return false;
> -      }
> -
> -    case LengthModifier::AsMAllocate:
> -      switch (CS.getKind()) {
> -        case ConversionSpecifier::cArg:
> -        case ConversionSpecifier::CArg:
> -        case ConversionSpecifier::sArg:
> -        case ConversionSpecifier::SArg:
> -        case ConversionSpecifier::ScanListArg:
> -          return true;
> -        default:
> -          return false;
> -      }
> -    case LengthModifier::AsInt32:
> -    case LengthModifier::AsInt3264:
> -    case LengthModifier::AsInt64:
> -      switch (CS.getKind()) {
> -        case ConversionSpecifier::dArg:
> -        case ConversionSpecifier::iArg:
> -        case ConversionSpecifier::oArg:
> -        case ConversionSpecifier::uArg:
> -        case ConversionSpecifier::xArg:
> -        case ConversionSpecifier::XArg:
> -          return Target.getTriple().isOSMSVCRT();
> -        default:
> -          return false;
> -      }
> -    case LengthModifier::AsWide:
> -      switch (CS.getKind()) {
> -        case ConversionSpecifier::cArg:
> -        case ConversionSpecifier::CArg:
> -        case ConversionSpecifier::sArg:
> -        case ConversionSpecifier::SArg:
> -        case ConversionSpecifier::ZArg:
> -          return Target.getTriple().isOSMSVCRT();
> -        default:
> -          return false;
> -      }
> -  }
> -  llvm_unreachable("Invalid LengthModifier Kind!");
> -}
> -
> -bool FormatSpecifier::hasStandardLengthModifier() const {
> -  switch (LM.getKind()) {
> -    case LengthModifier::None:
> -    case LengthModifier::AsChar:
> -    case LengthModifier::AsShort:
> -    case LengthModifier::AsLong:
> -    case LengthModifier::AsLongLong:
> -    case LengthModifier::AsIntMax:
> -    case LengthModifier::AsSizeT:
> -    case LengthModifier::AsPtrDiff:
> -    case LengthModifier::AsLongDouble:
> -      return true;
> -    case LengthModifier::AsAllocate:
> -    case LengthModifier::AsMAllocate:
> -    case LengthModifier::AsQuad:
> -    case LengthModifier::AsInt32:
> -    case LengthModifier::AsInt3264:
> -    case LengthModifier::AsInt64:
> -    case LengthModifier::AsWide:
> -      return false;
> -  }
> -  llvm_unreachable("Invalid LengthModifier Kind!");
> -}
> -
> -bool FormatSpecifier::hasStandardConversionSpecifier(
> -    const LangOptions &LangOpt) const {
> -  switch (CS.getKind()) {
> -    case ConversionSpecifier::cArg:
> -    case ConversionSpecifier::dArg:
> -    case ConversionSpecifier::iArg:
> -    case ConversionSpecifier::oArg:
> -    case ConversionSpecifier::uArg:
> -    case ConversionSpecifier::xArg:
> -    case ConversionSpecifier::XArg:
> -    case ConversionSpecifier::fArg:
> -    case ConversionSpecifier::FArg:
> -    case ConversionSpecifier::eArg:
> -    case ConversionSpecifier::EArg:
> -    case ConversionSpecifier::gArg:
> -    case ConversionSpecifier::GArg:
> -    case ConversionSpecifier::aArg:
> -    case ConversionSpecifier::AArg:
> -    case ConversionSpecifier::sArg:
> -    case ConversionSpecifier::pArg:
> -    case ConversionSpecifier::nArg:
> -    case ConversionSpecifier::ObjCObjArg:
> -    case ConversionSpecifier::ScanListArg:
> -    case ConversionSpecifier::PercentArg:
> -    case ConversionSpecifier::PArg:
> -      return true;
> -    case ConversionSpecifier::CArg:
> -    case ConversionSpecifier::SArg:
> -      return LangOpt.ObjC;
> -    case ConversionSpecifier::InvalidSpecifier:
> -    case ConversionSpecifier::FreeBSDbArg:
> -    case ConversionSpecifier::FreeBSDDArg:
> -    case ConversionSpecifier::FreeBSDrArg:
> -    case ConversionSpecifier::FreeBSDyArg:
> -    case ConversionSpecifier::PrintErrno:
> -    case ConversionSpecifier::DArg:
> -    case ConversionSpecifier::OArg:
> -    case ConversionSpecifier::UArg:
> -    case ConversionSpecifier::ZArg:
> -      return false;
> -  }
> -  llvm_unreachable("Invalid ConversionSpecifier Kind!");
> -}
> -
> -bool FormatSpecifier::hasStandardLengthConversionCombination() const {
> -  if (LM.getKind() == LengthModifier::AsLongDouble) {
> -    switch(CS.getKind()) {
> -        case ConversionSpecifier::dArg:
> -        case ConversionSpecifier::iArg:
> -        case ConversionSpecifier::oArg:
> -        case ConversionSpecifier::uArg:
> -        case ConversionSpecifier::xArg:
> -        case ConversionSpecifier::XArg:
> -          return false;
> -        default:
> -          return true;
> -    }
> -  }
> -  return true;
> -}
> -
> -Optional<LengthModifier> FormatSpecifier::getCorrectedLengthModifier()
> const {
> -  if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
> -    if (LM.getKind() == LengthModifier::AsLongDouble ||
> -        LM.getKind() == LengthModifier::AsQuad) {
> -      LengthModifier FixedLM(LM);
> -      FixedLM.setKind(LengthModifier::AsLongLong);
> -      return FixedLM;
> -    }
> -  }
> -
> -  return None;
> -}
> -
> -bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
> -                                                LengthModifier &LM) {
> -  assert(isa<TypedefType>(QT) && "Expected a TypedefType");
> -  const TypedefNameDecl *Typedef = cast<TypedefType>(QT)->getDecl();
> -
> -  for (;;) {
> -    const IdentifierInfo *Identifier = Typedef->getIdentifier();
> -    if (Identifier->getName() == "size_t") {
> -      LM.setKind(LengthModifier::AsSizeT);
> -      return true;
> -    } else if (Identifier->getName() == "ssize_t") {
> -      // Not C99, but common in Unix.
> -      LM.setKind(LengthModifier::AsSizeT);
> -      return true;
> -    } else if (Identifier->getName() == "intmax_t") {
> -      LM.setKind(LengthModifier::AsIntMax);
> -      return true;
> -    } else if (Identifier->getName() == "uintmax_t") {
> -      LM.setKind(LengthModifier::AsIntMax);
> -      return true;
> -    } else if (Identifier->getName() == "ptrdiff_t") {
> -      LM.setKind(LengthModifier::AsPtrDiff);
> -      return true;
> -    }
> -
> -    QualType T = Typedef->getUnderlyingType();
> -    if (!isa<TypedefType>(T))
> -      break;
> -
> -    Typedef = cast<TypedefType>(T)->getDecl();
> -  }
> -  return false;
> -}
>
> Removed: cfe/trunk/lib/Analysis/FormatStringParsing.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/FormatStringParsing.h?rev=345970&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/FormatStringParsing.h (original)
> +++ cfe/trunk/lib/Analysis/FormatStringParsing.h (removed)
> @@ -1,79 +0,0 @@
> -#ifndef LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
> -#define LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
> -
> -#include "clang/AST/ASTContext.h"
> -#include "clang/AST/Type.h"
> -#include "clang/Analysis/Analyses/FormatString.h"
> -
> -namespace clang {
> -
> -class LangOptions;
> -
> -template <typename T>
> -class UpdateOnReturn {
> -  T &ValueToUpdate;
> -  const T &ValueToCopy;
> -public:
> -  UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
> -    : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
> -
> -  ~UpdateOnReturn() {
> -    ValueToUpdate = ValueToCopy;
> -  }
> -};
> -
> -namespace analyze_format_string {
> -
> -OptionalAmount ParseAmount(const char *&Beg, const char *E);
> -OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
> -                                      unsigned &argIndex);
> -
> -OptionalAmount ParsePositionAmount(FormatStringHandler &H,
> -                                   const char *Start, const char *&Beg,
> -                                   const char *E, PositionContext p);
> -
> -bool ParseFieldWidth(FormatStringHandler &H,
> -                     FormatSpecifier &CS,
> -                     const char *Start, const char *&Beg, const char *E,
> -                     unsigned *argIndex);
> -
> -bool ParseArgPosition(FormatStringHandler &H,
> -                      FormatSpecifier &CS, const char *Start,
> -                      const char *&Beg, const char *E);
> -
> -/// Returns true if a LengthModifier was parsed and installed in the
> -/// FormatSpecifier& argument, and false otherwise.
> -bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const
> char *E,
> -                         const LangOptions &LO, bool IsScanf = false);
> -
> -/// Returns true if the invalid specifier in \p SpecifierBegin is a UTF-8
> -/// string; check that it won't go further than \p FmtStrEnd and write
> -/// up the total size in \p Len.
> -bool ParseUTF8InvalidSpecifier(const char *SpecifierBegin,
> -                               const char *FmtStrEnd, unsigned &Len);
> -
> -template <typename T> class SpecifierResult {
> -  T FS;
> -  const char *Start;
> -  bool Stop;
> -public:
> -  SpecifierResult(bool stop = false)
> -  : Start(nullptr), Stop(stop) {}
> -  SpecifierResult(const char *start,
> -                  const T &fs)
> -  : FS(fs), Start(start), Stop(false) {}
> -
> -  const char *getStart() const { return Start; }
> -  bool shouldStop() const { return Stop; }
> -  bool hasValue() const { return Start != nullptr; }
> -  const T &getValue() const {
> -    assert(hasValue());
> -    return FS;
> -  }
> -  const T &getValue() { return FS; }
> -};
> -
> -} // end analyze_format_string namespace
> -} // end clang namespace
> -
> -#endif
>
> Removed: cfe/trunk/lib/Analysis/OSLog.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/OSLog.cpp?rev=345970&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/OSLog.cpp (original)
> +++ cfe/trunk/lib/Analysis/OSLog.cpp (removed)
> @@ -1,203 +0,0 @@
> -// TODO: header template
> -
> -#include "clang/Analysis/Analyses/OSLog.h"
> -#include "clang/AST/Attr.h"
> -#include "clang/AST/Decl.h"
> -#include "clang/AST/DeclCXX.h"
> -#include "clang/AST/ExprObjC.h"
> -#include "clang/Analysis/Analyses/FormatString.h"
> -#include "clang/Basic/Builtins.h"
> -#include "llvm/ADT/SmallBitVector.h"
> -
> -using namespace clang;
> -
> -using clang::analyze_os_log::OSLogBufferItem;
> -using clang::analyze_os_log::OSLogBufferLayout;
> -
> -namespace {
> -class OSLogFormatStringHandler
> -    : public analyze_format_string::FormatStringHandler {
> -private:
> -  struct ArgData {
> -    const Expr *E = nullptr;
> -    Optional<OSLogBufferItem::Kind> Kind;
> -    Optional<unsigned> Size;
> -    Optional<const Expr *> Count;
> -    Optional<const Expr *> Precision;
> -    Optional<const Expr *> FieldWidth;
> -    unsigned char Flags = 0;
> -  };
> -  SmallVector<ArgData, 4> ArgsData;
> -  ArrayRef<const Expr *> Args;
> -
> -  OSLogBufferItem::Kind
> -  getKind(analyze_format_string::ConversionSpecifier::Kind K) {
> -    switch (K) {
> -    case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"
> -      return OSLogBufferItem::StringKind;
> -    case clang::analyze_format_string::ConversionSpecifier::SArg: // "%S"
> -      return OSLogBufferItem::WideStringKind;
> -    case clang::analyze_format_string::ConversionSpecifier::PArg: { //
> "%P"
> -      return OSLogBufferItem::PointerKind;
> -    case clang::analyze_format_string::ConversionSpecifier::ObjCObjArg:
> // "%@"
> -      return OSLogBufferItem::ObjCObjKind;
> -    case clang::analyze_format_string::ConversionSpecifier::PrintErrno:
> // "%m"
> -      return OSLogBufferItem::ErrnoKind;
> -    default:
> -      return OSLogBufferItem::ScalarKind;
> -    }
> -    }
> -  }
> -
> -public:
> -  OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {
> -    ArgsData.reserve(Args.size());
> -  }
> -
> -  virtual bool HandlePrintfSpecifier(const
> analyze_printf::PrintfSpecifier &FS,
> -                                     const char *StartSpecifier,
> -                                     unsigned SpecifierLen) {
> -    if (!FS.consumesDataArgument() &&
> -        FS.getConversionSpecifier().getKind() !=
> -            clang::analyze_format_string::ConversionSpecifier::PrintErrno)
> -      return true;
> -
> -    ArgsData.emplace_back();
> -    unsigned ArgIndex = FS.getArgIndex();
> -    if (ArgIndex < Args.size())
> -      ArgsData.back().E = Args[ArgIndex];
> -
> -    // First get the Kind
> -    ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());
> -    if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&
> -        !ArgsData.back().E) {
> -      // missing argument
> -      ArgsData.pop_back();
> -      return false;
> -    }
> -
> -    switch (FS.getConversionSpecifier().getKind()) {
> -    case clang::analyze_format_string::ConversionSpecifier::sArg:   //
> "%s"
> -    case clang::analyze_format_string::ConversionSpecifier::SArg: { //
> "%S"
> -      auto &precision = FS.getPrecision();
> -      switch (precision.getHowSpecified()) {
> -      case clang::analyze_format_string::OptionalAmount::NotSpecified: //
> "%s"
> -        break;
> -      case clang::analyze_format_string::OptionalAmount::Constant: //
> "%.16s"
> -        ArgsData.back().Size = precision.getConstantAmount();
> -        break;
> -      case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s"
> -        ArgsData.back().Count = Args[precision.getArgIndex()];
> -        break;
> -      case clang::analyze_format_string::OptionalAmount::Invalid:
> -        return false;
> -      }
> -      break;
> -    }
> -    case clang::analyze_format_string::ConversionSpecifier::PArg: { //
> "%P"
> -      auto &precision = FS.getPrecision();
> -      switch (precision.getHowSpecified()) {
> -      case clang::analyze_format_string::OptionalAmount::NotSpecified: //
> "%P"
> -        return false; // length must be supplied with pointer format
> specifier
> -      case clang::analyze_format_string::OptionalAmount::Constant: //
> "%.16P"
> -        ArgsData.back().Size = precision.getConstantAmount();
> -        break;
> -      case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P"
> -        ArgsData.back().Count = Args[precision.getArgIndex()];
> -        break;
> -      case clang::analyze_format_string::OptionalAmount::Invalid:
> -        return false;
> -      }
> -      break;
> -    }
> -    default:
> -      if (FS.getPrecision().hasDataArgument()) {
> -        ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];
> -      }
> -      break;
> -    }
> -    if (FS.getFieldWidth().hasDataArgument()) {
> -      ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];
> -    }
> -
> -    if (FS.isPrivate()) {
> -      ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;
> -    }
> -    if (FS.isPublic()) {
> -      ArgsData.back().Flags |= OSLogBufferItem::IsPublic;
> -    }
> -    return true;
> -  }
> -
> -  void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {
> -    Layout.Items.clear();
> -    for (auto &Data : ArgsData) {
> -      if (Data.FieldWidth) {
> -        CharUnits Size =
> Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());
> -        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind,
> *Data.FieldWidth,
> -                                  Size, 0);
> -      }
> -      if (Data.Precision) {
> -        CharUnits Size =
> Ctx.getTypeSizeInChars((*Data.Precision)->getType());
> -        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind,
> *Data.Precision,
> -                                  Size, 0);
> -      }
> -      if (Data.Count) {
> -        // "%.*P" has an extra "count" that we insert before the argument.
> -        CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());
> -        Layout.Items.emplace_back(OSLogBufferItem::CountKind,
> *Data.Count, Size,
> -                                  0);
> -      }
> -      if (Data.Size)
> -        Layout.Items.emplace_back(Ctx,
> CharUnits::fromQuantity(*Data.Size),
> -                                  Data.Flags);
> -      if (Data.Kind) {
> -        CharUnits Size;
> -        if (*Data.Kind == OSLogBufferItem::ErrnoKind)
> -          Size = CharUnits::Zero();
> -        else
> -          Size = Ctx.getTypeSizeInChars(Data.E->getType());
> -        Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);
> -      } else {
> -        auto Size = Ctx.getTypeSizeInChars(Data.E->getType());
> -        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E,
> Size,
> -                                  Data.Flags);
> -      }
> -    }
> -  }
> -};
> -} // end anonymous namespace
> -
> -bool clang::analyze_os_log::computeOSLogBufferLayout(
> -    ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {
> -  ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() +
> E->getNumArgs());
> -
> -  const Expr *StringArg;
> -  ArrayRef<const Expr *> VarArgs;
> -  switch (E->getBuiltinCallee()) {
> -  case Builtin::BI__builtin_os_log_format_buffer_size:
> -    assert(E->getNumArgs() >= 1 &&
> -           "__builtin_os_log_format_buffer_size takes at least 1
> argument");
> -    StringArg = E->getArg(0);
> -    VarArgs = Args.slice(1);
> -    break;
> -  case Builtin::BI__builtin_os_log_format:
> -    assert(E->getNumArgs() >= 2 &&
> -           "__builtin_os_log_format takes at least 2 arguments");
> -    StringArg = E->getArg(1);
> -    VarArgs = Args.slice(2);
> -    break;
> -  default:
> -    llvm_unreachable("non-os_log builtin passed to
> computeOSLogBufferLayout");
> -  }
> -
> -  const StringLiteral *Lit =
> cast<StringLiteral>(StringArg->IgnoreParenCasts());
> -  assert(Lit && (Lit->isAscii() || Lit->isUTF8()));
> -  StringRef Data = Lit->getString();
> -  OSLogFormatStringHandler H(VarArgs);
> -  ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),
> -                    Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);
> -
> -  H.computeLayout(Ctx, Layout);
> -  return true;
> -}
>
> Removed: cfe/trunk/lib/Analysis/PrintfFormatString.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PrintfFormatString.cpp?rev=345970&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/PrintfFormatString.cpp (original)
> +++ cfe/trunk/lib/Analysis/PrintfFormatString.cpp (removed)
> @@ -1,1029 +0,0 @@
> -//== PrintfFormatString.cpp - Analysis of printf format strings --*- C++
> -*-==//
> -//
> -//                     The LLVM Compiler Infrastructure
> -//
> -// This file is distributed under the University of Illinois Open Source
> -// License. See LICENSE.TXT for details.
> -//
>
> -//===----------------------------------------------------------------------===//
> -//
> -// Handling of format string in printf and friends.  The structure of
> format
> -// strings for fprintf() are described in C99 7.19.6.1.
> -//
>
> -//===----------------------------------------------------------------------===//
> -
> -#include "clang/Analysis/Analyses/FormatString.h"
> -#include "clang/Analysis/Analyses/OSLog.h"
> -#include "FormatStringParsing.h"
> -#include "clang/Basic/TargetInfo.h"
> -
> -using clang::analyze_format_string::ArgType;
> -using clang::analyze_format_string::FormatStringHandler;
> -using clang::analyze_format_string::LengthModifier;
> -using clang::analyze_format_string::OptionalAmount;
> -using clang::analyze_format_string::ConversionSpecifier;
> -using clang::analyze_printf::PrintfSpecifier;
> -
> -using namespace clang;
> -
> -typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
> -        PrintfSpecifierResult;
> -
>
> -//===----------------------------------------------------------------------===//
> -// Methods for parsing format strings.
>
> -//===----------------------------------------------------------------------===//
> -
> -using analyze_format_string::ParseNonPositionAmount;
> -
> -static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
> -                           const char *Start, const char *&Beg, const
> char *E,
> -                           unsigned *argIndex) {
> -  if (argIndex) {
> -    FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
> -  } else {
> -    const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
> -
>  analyze_format_string::PrecisionPos);
> -    if (Amt.isInvalid())
> -      return true;
> -    FS.setPrecision(Amt);
> -  }
> -  return false;
> -}
> -
> -static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,
> -                           const char *FlagBeg, const char *E, bool Warn)
> {
> -   StringRef Flag(FlagBeg, E - FlagBeg);
> -   // Currently there is only one flag.
> -   if (Flag == "tt") {
> -     FS.setHasObjCTechnicalTerm(FlagBeg);
> -     return false;
> -   }
> -   // Handle either the case of no flag or an invalid flag.
> -   if (Warn) {
> -     if (Flag == "")
> -       H.HandleEmptyObjCModifierFlag(FlagBeg, E  - FlagBeg);
> -     else
> -       H.HandleInvalidObjCModifierFlag(FlagBeg, E  - FlagBeg);
> -   }
> -   return true;
> -}
> -
> -static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
> -                                                  const char *&Beg,
> -                                                  const char *E,
> -                                                  unsigned &argIndex,
> -                                                  const LangOptions &LO,
> -                                                  const TargetInfo
> &Target,
> -                                                  bool Warn,
> -                                                  bool isFreeBSDKPrintf) {
> -
> -  using namespace clang::analyze_format_string;
> -  using namespace clang::analyze_printf;
> -
> -  const char *I = Beg;
> -  const char *Start = nullptr;
> -  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
> -
> -  // Look for a '%' character that indicates the start of a format
> specifier.
> -  for ( ; I != E ; ++I) {
> -    char c = *I;
> -    if (c == '\0') {
> -      // Detect spurious null characters, which are likely errors.
> -      H.HandleNullChar(I);
> -      return true;
> -    }
> -    if (c == '%') {
> -      Start = I++;  // Record the start of the format specifier.
> -      break;
> -    }
> -  }
> -
> -  // No format specifier found?
> -  if (!Start)
> -    return false;
> -
> -  if (I == E) {
> -    // No more characters left?
> -    if (Warn)
> -      H.HandleIncompleteSpecifier(Start, E - Start);
> -    return true;
> -  }
> -
> -  PrintfSpecifier FS;
> -  if (ParseArgPosition(H, FS, Start, I, E))
> -    return true;
> -
> -  if (I == E) {
> -    // No more characters left?
> -    if (Warn)
> -      H.HandleIncompleteSpecifier(Start, E - Start);
> -    return true;
> -  }
> -
> -  if (*I == '{') {
> -    ++I;
> -    unsigned char PrivacyFlags = 0;
> -    StringRef MatchedStr;
> -
> -    do {
> -      StringRef Str(I, E - I);
> -      std::string Match = "^[\t\n\v\f\r ]*(private|public)[\t\n\v\f\r
> ]*(,|})";
> -      llvm::Regex R(Match);
> -      SmallVector<StringRef, 2> Matches;
> -
> -      if (R.match(Str, &Matches)) {
> -        MatchedStr = Matches[1];
> -        I += Matches[0].size();
> -
> -        // Set the privacy flag if the privacy annotation in the
> -        // comma-delimited segment is at least as strict as the privacy
> -        // annotations in previous comma-delimited segments.
> -        if (MatchedStr.equals("private"))
> -          PrivacyFlags =
> clang::analyze_os_log::OSLogBufferItem::IsPrivate;
> -        else if (PrivacyFlags == 0 && MatchedStr.equals("public"))
> -          PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic;
> -      } else {
> -        size_t CommaOrBracePos =
> -            Str.find_if([](char c) { return c == ',' || c == '}'; });
> -
> -        if (CommaOrBracePos == StringRef::npos) {
> -          // Neither a comma nor the closing brace was found.
> -          if (Warn)
> -            H.HandleIncompleteSpecifier(Start, E - Start);
> -          return true;
> -        }
> -
> -        I += CommaOrBracePos + 1;
> -      }
> -      // Continue until the closing brace is found.
> -    } while (*(I - 1) == ',');
> -
> -    // Set the privacy flag.
> -    switch (PrivacyFlags) {
> -    case 0:
> -      break;
> -    case clang::analyze_os_log::OSLogBufferItem::IsPrivate:
> -      FS.setIsPrivate(MatchedStr.data());
> -      break;
> -    case clang::analyze_os_log::OSLogBufferItem::IsPublic:
> -      FS.setIsPublic(MatchedStr.data());
> -      break;
> -    default:
> -      llvm_unreachable("Unexpected privacy flag value");
> -    }
> -  }
> -
> -  // Look for flags (if any).
> -  bool hasMore = true;
> -  for ( ; I != E; ++I) {
> -    switch (*I) {
> -      default: hasMore = false; break;
> -      case '\'':
> -        // FIXME: POSIX specific.  Always accept?
> -        FS.setHasThousandsGrouping(I);
> -        break;
> -      case '-': FS.setIsLeftJustified(I); break;
> -      case '+': FS.setHasPlusPrefix(I); break;
> -      case ' ': FS.setHasSpacePrefix(I); break;
> -      case '#': FS.setHasAlternativeForm(I); break;
> -      case '0': FS.setHasLeadingZeros(I); break;
> -    }
> -    if (!hasMore)
> -      break;
> -  }
> -
> -  if (I == E) {
> -    // No more characters left?
> -    if (Warn)
> -      H.HandleIncompleteSpecifier(Start, E - Start);
> -    return true;
> -  }
> -
> -  // Look for the field width (if any).
> -  if (ParseFieldWidth(H, FS, Start, I, E,
> -                      FS.usesPositionalArg() ? nullptr : &argIndex))
> -    return true;
> -
> -  if (I == E) {
> -    // No more characters left?
> -    if (Warn)
> -      H.HandleIncompleteSpecifier(Start, E - Start);
> -    return true;
> -  }
> -
> -  // Look for the precision (if any).
> -  if (*I == '.') {
> -    ++I;
> -    if (I == E) {
> -      if (Warn)
> -        H.HandleIncompleteSpecifier(Start, E - Start);
> -      return true;
> -    }
> -
> -    if (ParsePrecision(H, FS, Start, I, E,
> -                       FS.usesPositionalArg() ? nullptr : &argIndex))
> -      return true;
> -
> -    if (I == E) {
> -      // No more characters left?
> -      if (Warn)
> -        H.HandleIncompleteSpecifier(Start, E - Start);
> -      return true;
> -    }
> -  }
> -
> -  // Look for the length modifier.
> -  if (ParseLengthModifier(FS, I, E, LO) && I == E) {
> -    // No more characters left?
> -    if (Warn)
> -      H.HandleIncompleteSpecifier(Start, E - Start);
> -    return true;
> -  }
> -
> -  // Look for the Objective-C modifier flags, if any.
> -  // We parse these here, even if they don't apply to
> -  // the conversion specifier, and then emit an error
> -  // later if the conversion specifier isn't '@'.  This
> -  // enables better recovery, and we don't know if
> -  // these flags are applicable until later.
> -  const char *ObjCModifierFlagsStart = nullptr,
> -             *ObjCModifierFlagsEnd = nullptr;
> -  if (*I == '[') {
> -    ObjCModifierFlagsStart = I;
> -    ++I;
> -    auto flagStart = I;
> -    for (;; ++I) {
> -      ObjCModifierFlagsEnd = I;
> -      if (I == E) {
> -        if (Warn)
> -          H.HandleIncompleteSpecifier(Start, E - Start);
> -        return true;
> -      }
> -      // Did we find the closing ']'?
> -      if (*I == ']') {
> -        if (ParseObjCFlags(H, FS, flagStart, I, Warn))
> -          return true;
> -        ++I;
> -        break;
> -      }
> -      // There are no separators defined yet for multiple
> -      // Objective-C modifier flags.  When those are
> -      // defined, this is the place to check.
> -    }
> -  }
> -
> -  if (*I == '\0') {
> -    // Detect spurious null characters, which are likely errors.
> -    H.HandleNullChar(I);
> -    return true;
> -  }
> -
> -  // Finally, look for the conversion specifier.
> -  const char *conversionPosition = I++;
> -  ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
> -  switch (*conversionPosition) {
> -    default:
> -      break;
> -    // C99: 7.19.6.1 (section 8).
> -    case '%': k = ConversionSpecifier::PercentArg;   break;
> -    case 'A': k = ConversionSpecifier::AArg; break;
> -    case 'E': k = ConversionSpecifier::EArg; break;
> -    case 'F': k = ConversionSpecifier::FArg; break;
> -    case 'G': k = ConversionSpecifier::GArg; break;
> -    case 'X': k = ConversionSpecifier::XArg; break;
> -    case 'a': k = ConversionSpecifier::aArg; break;
> -    case 'c': k = ConversionSpecifier::cArg; break;
> -    case 'd': k = ConversionSpecifier::dArg; break;
> -    case 'e': k = ConversionSpecifier::eArg; break;
> -    case 'f': k = ConversionSpecifier::fArg; break;
> -    case 'g': k = ConversionSpecifier::gArg; break;
> -    case 'i': k = ConversionSpecifier::iArg; break;
> -    case 'n': k = ConversionSpecifier::nArg; break;
> -    case 'o': k = ConversionSpecifier::oArg; break;
> -    case 'p': k = ConversionSpecifier::pArg; break;
> -    case 's': k = ConversionSpecifier::sArg; break;
> -    case 'u': k = ConversionSpecifier::uArg; break;
> -    case 'x': k = ConversionSpecifier::xArg; break;
> -    // POSIX specific.
> -    case 'C': k = ConversionSpecifier::CArg; break;
> -    case 'S': k = ConversionSpecifier::SArg; break;
> -    // Apple extension for os_log
> -    case 'P':
> -      k = ConversionSpecifier::PArg;
> -      break;
> -    // Objective-C.
> -    case '@': k = ConversionSpecifier::ObjCObjArg; break;
> -    // Glibc specific.
> -    case 'm': k = ConversionSpecifier::PrintErrno; break;
> -    // FreeBSD kernel specific.
> -    case 'b':
> -      if (isFreeBSDKPrintf)
> -        k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
> -      break;
> -    case 'r':
> -      if (isFreeBSDKPrintf)
> -        k = ConversionSpecifier::FreeBSDrArg; // int
> -      break;
> -    case 'y':
> -      if (isFreeBSDKPrintf)
> -        k = ConversionSpecifier::FreeBSDyArg; // int
> -      break;
> -    // Apple-specific.
> -    case 'D':
> -      if (isFreeBSDKPrintf)
> -        k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *
> -      else if (Target.getTriple().isOSDarwin())
> -        k = ConversionSpecifier::DArg;
> -      break;
> -    case 'O':
> -      if (Target.getTriple().isOSDarwin())
> -        k = ConversionSpecifier::OArg;
> -      break;
> -    case 'U':
> -      if (Target.getTriple().isOSDarwin())
> -        k = ConversionSpecifier::UArg;
> -      break;
> -    // MS specific.
> -    case 'Z':
> -      if (Target.getTriple().isOSMSVCRT())
> -        k = ConversionSpecifier::ZArg;
> -  }
> -
> -  // Check to see if we used the Objective-C modifier flags with
> -  // a conversion specifier other than '@'.
> -  if (k != ConversionSpecifier::ObjCObjArg &&
> -      k != ConversionSpecifier::InvalidSpecifier &&
> -      ObjCModifierFlagsStart) {
> -    H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart,
> -                                           ObjCModifierFlagsEnd + 1,
> -                                           conversionPosition);
> -    return true;
> -  }
> -
> -  PrintfConversionSpecifier CS(conversionPosition, k);
> -  FS.setConversionSpecifier(CS);
> -  if (CS.consumesDataArgument() && !FS.usesPositionalArg())
> -    FS.setArgIndex(argIndex++);
> -  // FreeBSD kernel specific.
> -  if (k == ConversionSpecifier::FreeBSDbArg ||
> -      k == ConversionSpecifier::FreeBSDDArg)
> -    argIndex++;
> -
> -  if (k == ConversionSpecifier::InvalidSpecifier) {
> -    unsigned Len = I - Start;
> -    if (ParseUTF8InvalidSpecifier(Start, E, Len)) {
> -      CS.setEndScanList(Start + Len);
> -      FS.setConversionSpecifier(CS);
> -    }
> -    // Assume the conversion takes one argument.
> -    return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len);
> -  }
> -  return PrintfSpecifierResult(Start, FS);
> -}
> -
> -bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler
> &H,
> -                                                     const char *I,
> -                                                     const char *E,
> -                                                     const LangOptions
> &LO,
> -                                                     const TargetInfo
> &Target,
> -                                                     bool
> isFreeBSDKPrintf) {
> -
> -  unsigned argIndex = 0;
> -
> -  // Keep looking for a format specifier until we have exhausted the
> string.
> -  while (I != E) {
> -    const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E,
> argIndex,
> -                                                            LO, Target,
> true,
> -
> isFreeBSDKPrintf);
> -    // Did a fail-stop error of any kind occur when parsing the specifier?
> -    // If so, don't do any more processing.
> -    if (FSR.shouldStop())
> -      return true;
> -    // Did we exhaust the string or encounter an error that
> -    // we can recover from?
> -    if (!FSR.hasValue())
> -      continue;
> -    // We have a format specifier.  Pass it to the callback.
> -    if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
> -                                 I - FSR.getStart()))
> -      return true;
> -  }
> -  assert(I == E && "Format string not exhausted");
> -  return false;
> -}
> -
> -bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
> -                                                            const char *E,
> -                                                            const
> LangOptions &LO,
> -                                                            const
> TargetInfo &Target) {
> -
> -  unsigned argIndex = 0;
> -
> -  // Keep looking for a %s format specifier until we have exhausted the
> string.
> -  FormatStringHandler H;
> -  while (I != E) {
> -    const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E,
> argIndex,
> -                                                            LO, Target,
> false,
> -                                                            false);
> -    // Did a fail-stop error of any kind occur when parsing the specifier?
> -    // If so, don't do any more processing.
> -    if (FSR.shouldStop())
> -      return false;
> -    // Did we exhaust the string or encounter an error that
> -    // we can recover from?
> -    if (!FSR.hasValue())
> -      continue;
> -    const analyze_printf::PrintfSpecifier &FS = FSR.getValue();
> -    // Return true if this a %s format specifier.
> -    if (FS.getConversionSpecifier().getKind() ==
> ConversionSpecifier::Kind::sArg)
> -      return true;
> -  }
> -  return false;
> -}
> -
>
> -//===----------------------------------------------------------------------===//
> -// Methods on PrintfSpecifier.
>
> -//===----------------------------------------------------------------------===//
> -
> -ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
> -                                    bool IsObjCLiteral) const {
> -  const PrintfConversionSpecifier &CS = getConversionSpecifier();
> -
> -  if (!CS.consumesDataArgument())
> -    return ArgType::Invalid();
> -
> -  if (CS.getKind() == ConversionSpecifier::cArg)
> -    switch (LM.getKind()) {
> -      case LengthModifier::None:
> -        return Ctx.IntTy;
> -      case LengthModifier::AsLong:
> -      case LengthModifier::AsWide:
> -        return ArgType(ArgType::WIntTy, "wint_t");
> -      case LengthModifier::AsShort:
> -        if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
> -          return Ctx.IntTy;
> -        LLVM_FALLTHROUGH;
> -      default:
> -        return ArgType::Invalid();
> -    }
> -
> -  if (CS.isIntArg())
> -    switch (LM.getKind()) {
> -      case LengthModifier::AsLongDouble:
> -        // GNU extension.
> -        return Ctx.LongLongTy;
> -      case LengthModifier::None:
> -        return Ctx.IntTy;
> -      case LengthModifier::AsInt32:
> -        return ArgType(Ctx.IntTy, "__int32");
> -      case LengthModifier::AsChar: return ArgType::AnyCharTy;
> -      case LengthModifier::AsShort: return Ctx.ShortTy;
> -      case LengthModifier::AsLong: return Ctx.LongTy;
> -      case LengthModifier::AsLongLong:
> -      case LengthModifier::AsQuad:
> -        return Ctx.LongLongTy;
> -      case LengthModifier::AsInt64:
> -        return ArgType(Ctx.LongLongTy, "__int64");
> -      case LengthModifier::AsIntMax:
> -        return ArgType(Ctx.getIntMaxType(), "intmax_t");
> -      case LengthModifier::AsSizeT:
> -        return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(),
> "ssize_t"));
> -      case LengthModifier::AsInt3264:
> -        return Ctx.getTargetInfo().getTriple().isArch64Bit()
> -                   ? ArgType(Ctx.LongLongTy, "__int64")
> -                   : ArgType(Ctx.IntTy, "__int32");
> -      case LengthModifier::AsPtrDiff:
> -        return ArgType::makePtrdiffT(
> -            ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
> -      case LengthModifier::AsAllocate:
> -      case LengthModifier::AsMAllocate:
> -      case LengthModifier::AsWide:
> -        return ArgType::Invalid();
> -    }
> -
> -  if (CS.isUIntArg())
> -    switch (LM.getKind()) {
> -      case LengthModifier::AsLongDouble:
> -        // GNU extension.
> -        return Ctx.UnsignedLongLongTy;
> -      case LengthModifier::None:
> -        return Ctx.UnsignedIntTy;
> -      case LengthModifier::AsInt32:
> -        return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
> -      case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
> -      case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
> -      case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
> -      case LengthModifier::AsLongLong:
> -      case LengthModifier::AsQuad:
> -        return Ctx.UnsignedLongLongTy;
> -      case LengthModifier::AsInt64:
> -        return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
> -      case LengthModifier::AsIntMax:
> -        return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
> -      case LengthModifier::AsSizeT:
> -        return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));
> -      case LengthModifier::AsInt3264:
> -        return Ctx.getTargetInfo().getTriple().isArch64Bit()
> -                   ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
> -                   : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
> -      case LengthModifier::AsPtrDiff:
> -        return ArgType::makePtrdiffT(
> -            ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned
> ptrdiff_t"));
> -      case LengthModifier::AsAllocate:
> -      case LengthModifier::AsMAllocate:
> -      case LengthModifier::AsWide:
> -        return ArgType::Invalid();
> -    }
> -
> -  if (CS.isDoubleArg()) {
> -    if (LM.getKind() == LengthModifier::AsLongDouble)
> -      return Ctx.LongDoubleTy;
> -    return Ctx.DoubleTy;
> -  }
> -
> -  if (CS.getKind() == ConversionSpecifier::nArg) {
> -    switch (LM.getKind()) {
> -      case LengthModifier::None:
> -        return ArgType::PtrTo(Ctx.IntTy);
> -      case LengthModifier::AsChar:
> -        return ArgType::PtrTo(Ctx.SignedCharTy);
> -      case LengthModifier::AsShort:
> -        return ArgType::PtrTo(Ctx.ShortTy);
> -      case LengthModifier::AsLong:
> -        return ArgType::PtrTo(Ctx.LongTy);
> -      case LengthModifier::AsLongLong:
> -      case LengthModifier::AsQuad:
> -        return ArgType::PtrTo(Ctx.LongLongTy);
> -      case LengthModifier::AsIntMax:
> -        return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
> -      case LengthModifier::AsSizeT:
> -        return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(),
> "ssize_t"));
> -      case LengthModifier::AsPtrDiff:
> -        return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(),
> "ptrdiff_t"));
> -      case LengthModifier::AsLongDouble:
> -        return ArgType(); // FIXME: Is this a known extension?
> -      case LengthModifier::AsAllocate:
> -      case LengthModifier::AsMAllocate:
> -      case LengthModifier::AsInt32:
> -      case LengthModifier::AsInt3264:
> -      case LengthModifier::AsInt64:
> -      case LengthModifier::AsWide:
> -        return ArgType::Invalid();
> -    }
> -  }
> -
> -  switch (CS.getKind()) {
> -    case ConversionSpecifier::sArg:
> -      if (LM.getKind() == LengthModifier::AsWideChar) {
> -        if (IsObjCLiteral)
> -          return
> ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
> -                         "const unichar *");
> -        return ArgType(ArgType::WCStrTy, "wchar_t *");
> -      }
> -      if (LM.getKind() == LengthModifier::AsWide)
> -        return ArgType(ArgType::WCStrTy, "wchar_t *");
> -      return ArgType::CStrTy;
> -    case ConversionSpecifier::SArg:
> -      if (IsObjCLiteral)
> -        return
> ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
> -                       "const unichar *");
> -      if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
> -          LM.getKind() == LengthModifier::AsShort)
> -        return ArgType::CStrTy;
> -      return ArgType(ArgType::WCStrTy, "wchar_t *");
> -    case ConversionSpecifier::CArg:
> -      if (IsObjCLiteral)
> -        return ArgType(Ctx.UnsignedShortTy, "unichar");
> -      if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
> -          LM.getKind() == LengthModifier::AsShort)
> -        return Ctx.IntTy;
> -      return ArgType(Ctx.WideCharTy, "wchar_t");
> -    case ConversionSpecifier::pArg:
> -    case ConversionSpecifier::PArg:
> -      return ArgType::CPointerTy;
> -    case ConversionSpecifier::ObjCObjArg:
> -      return ArgType::ObjCPointerTy;
> -    default:
> -      break;
> -  }
> -
> -  // FIXME: Handle other cases.
> -  return ArgType();
> -}
> -
> -bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
> -                              ASTContext &Ctx, bool IsObjCLiteral) {
> -  // %n is different from other conversion specifiers; don't try to fix
> it.
> -  if (CS.getKind() == ConversionSpecifier::nArg)
> -    return false;
> -
> -  // Handle Objective-C objects first. Note that while the '%@' specifier
> will
> -  // not warn for structure pointer or void pointer arguments (because
> that's
> -  // how CoreFoundation objects are implemented), we only show a fixit
> for '%@'
> -  // if we know it's an object (block, id, class, or
> __attribute__((NSObject))).
> -  if (QT->isObjCRetainableType()) {
> -    if (!IsObjCLiteral)
> -      return false;
> -
> -    CS.setKind(ConversionSpecifier::ObjCObjArg);
> -
> -    // Disable irrelevant flags
> -    HasThousandsGrouping = false;
> -    HasPlusPrefix = false;
> -    HasSpacePrefix = false;
> -    HasAlternativeForm = false;
> -    HasLeadingZeroes = false;
> -    Precision.setHowSpecified(OptionalAmount::NotSpecified);
> -    LM.setKind(LengthModifier::None);
> -
> -    return true;
> -  }
> -
> -  // Handle strings next (char *, wchar_t *)
> -  if (QT->isPointerType() &&
> (QT->getPointeeType()->isAnyCharacterType())) {
> -    CS.setKind(ConversionSpecifier::sArg);
> -
> -    // Disable irrelevant flags
> -    HasAlternativeForm = 0;
> -    HasLeadingZeroes = 0;
> -
> -    // Set the long length modifier for wide characters
> -    if (QT->getPointeeType()->isWideCharType())
> -      LM.setKind(LengthModifier::AsWideChar);
> -    else
> -      LM.setKind(LengthModifier::None);
> -
> -    return true;
> -  }
> -
> -  // If it's an enum, get its underlying type.
> -  if (const EnumType *ETy = QT->getAs<EnumType>())
> -    QT = ETy->getDecl()->getIntegerType();
> -
> -  // We can only work with builtin types.
> -  const BuiltinType *BT = QT->getAs<BuiltinType>();
> -  if (!BT)
> -    return false;
> -
> -  // Set length modifier
> -  switch (BT->getKind()) {
> -  case BuiltinType::Bool:
> -  case BuiltinType::WChar_U:
> -  case BuiltinType::WChar_S:
> -  case BuiltinType::Char8: // FIXME: Treat like 'char'?
> -  case BuiltinType::Char16:
> -  case BuiltinType::Char32:
> -  case BuiltinType::UInt128:
> -  case BuiltinType::Int128:
> -  case BuiltinType::Half:
> -  case BuiltinType::Float16:
> -  case BuiltinType::Float128:
> -  case BuiltinType::ShortAccum:
> -  case BuiltinType::Accum:
> -  case BuiltinType::LongAccum:
> -  case BuiltinType::UShortAccum:
> -  case BuiltinType::UAccum:
> -  case BuiltinType::ULongAccum:
> -  case BuiltinType::ShortFract:
> -  case BuiltinType::Fract:
> -  case BuiltinType::LongFract:
> -  case BuiltinType::UShortFract:
> -  case BuiltinType::UFract:
> -  case BuiltinType::ULongFract:
> -  case BuiltinType::SatShortAccum:
> -  case BuiltinType::SatAccum:
> -  case BuiltinType::SatLongAccum:
> -  case BuiltinType::SatUShortAccum:
> -  case BuiltinType::SatUAccum:
> -  case BuiltinType::SatULongAccum:
> -  case BuiltinType::SatShortFract:
> -  case BuiltinType::SatFract:
> -  case BuiltinType::SatLongFract:
> -  case BuiltinType::SatUShortFract:
> -  case BuiltinType::SatUFract:
> -  case BuiltinType::SatULongFract:
> -    // Various types which are non-trivial to correct.
> -    return false;
> -
> -#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
> -  case BuiltinType::Id:
> -#include "clang/Basic/OpenCLImageTypes.def"
> -#define SIGNED_TYPE(Id, SingletonId)
> -#define UNSIGNED_TYPE(Id, SingletonId)
> -#define FLOATING_TYPE(Id, SingletonId)
> -#define BUILTIN_TYPE(Id, SingletonId) \
> -  case BuiltinType::Id:
> -#include "clang/AST/BuiltinTypes.def"
> -    // Misc other stuff which doesn't make sense here.
> -    return false;
> -
> -  case BuiltinType::UInt:
> -  case BuiltinType::Int:
> -  case BuiltinType::Float:
> -  case BuiltinType::Double:
> -    LM.setKind(LengthModifier::None);
> -    break;
> -
> -  case BuiltinType::Char_U:
> -  case BuiltinType::UChar:
> -  case BuiltinType::Char_S:
> -  case BuiltinType::SChar:
> -    LM.setKind(LengthModifier::AsChar);
> -    break;
> -
> -  case BuiltinType::Short:
> -  case BuiltinType::UShort:
> -    LM.setKind(LengthModifier::AsShort);
> -    break;
> -
> -  case BuiltinType::Long:
> -  case BuiltinType::ULong:
> -    LM.setKind(LengthModifier::AsLong);
> -    break;
> -
> -  case BuiltinType::LongLong:
> -  case BuiltinType::ULongLong:
> -    LM.setKind(LengthModifier::AsLongLong);
> -    break;
> -
> -  case BuiltinType::LongDouble:
> -    LM.setKind(LengthModifier::AsLongDouble);
> -    break;
> -  }
> -
> -  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers
> in C99.
> -  if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
> -    namedTypeToLengthModifier(QT, LM);
> -
> -  // If fixing the length modifier was enough, we might be done.
> -  if (hasValidLengthModifier(Ctx.getTargetInfo())) {
> -    // If we're going to offer a fix anyway, make sure the sign matches.
> -    switch (CS.getKind()) {
> -    case ConversionSpecifier::uArg:
> -    case ConversionSpecifier::UArg:
> -      if (QT->isSignedIntegerType())
> -
> CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
> -      break;
> -    case ConversionSpecifier::dArg:
> -    case ConversionSpecifier::DArg:
> -    case ConversionSpecifier::iArg:
> -      if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
> -
> CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
> -      break;
> -    default:
> -      // Other specifiers do not have signed/unsigned variants.
> -      break;
> -    }
> -
> -    const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
> -    if (ATR.isValid() && ATR.matchesType(Ctx, QT))
> -      return true;
> -  }
> -
> -  // Set conversion specifier and disable any flags which do not apply to
> it.
> -  // Let typedefs to char fall through to int, as %c is silly for uint8_t.
> -  if (!isa<TypedefType>(QT) && QT->isCharType()) {
> -    CS.setKind(ConversionSpecifier::cArg);
> -    LM.setKind(LengthModifier::None);
> -    Precision.setHowSpecified(OptionalAmount::NotSpecified);
> -    HasAlternativeForm = 0;
> -    HasLeadingZeroes = 0;
> -    HasPlusPrefix = 0;
> -  }
> -  // Test for Floating type first as LongDouble can pass
> isUnsignedIntegerType
> -  else if (QT->isRealFloatingType()) {
> -    CS.setKind(ConversionSpecifier::fArg);
> -  }
> -  else if (QT->isSignedIntegerType()) {
> -    CS.setKind(ConversionSpecifier::dArg);
> -    HasAlternativeForm = 0;
> -  }
> -  else if (QT->isUnsignedIntegerType()) {
> -    CS.setKind(ConversionSpecifier::uArg);
> -    HasAlternativeForm = 0;
> -    HasPlusPrefix = 0;
> -  } else {
> -    llvm_unreachable("Unexpected type");
> -  }
> -
> -  return true;
> -}
> -
> -void PrintfSpecifier::toString(raw_ostream &os) const {
> -  // Whilst some features have no defined order, we are using the order
> -  // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
> -  os << "%";
> -
> -  // Positional args
> -  if (usesPositionalArg()) {
> -    os << getPositionalArgIndex() << "$";
> -  }
> -
> -  // Conversion flags
> -  if (IsLeftJustified)    os << "-";
> -  if (HasPlusPrefix)      os << "+";
> -  if (HasSpacePrefix)     os << " ";
> -  if (HasAlternativeForm) os << "#";
> -  if (HasLeadingZeroes)   os << "0";
> -
> -  // Minimum field width
> -  FieldWidth.toString(os);
> -  // Precision
> -  Precision.toString(os);
> -  // Length modifier
> -  os << LM.toString();
> -  // Conversion specifier
> -  os << CS.toString();
> -}
> -
> -bool PrintfSpecifier::hasValidPlusPrefix() const {
> -  if (!HasPlusPrefix)
> -    return true;
> -
> -  // The plus prefix only makes sense for signed conversions
> -  switch (CS.getKind()) {
> -  case ConversionSpecifier::dArg:
> -  case ConversionSpecifier::DArg:
> -  case ConversionSpecifier::iArg:
> -  case ConversionSpecifier::fArg:
> -  case ConversionSpecifier::FArg:
> -  case ConversionSpecifier::eArg:
> -  case ConversionSpecifier::EArg:
> -  case ConversionSpecifier::gArg:
> -  case ConversionSpecifier::GArg:
> -  case ConversionSpecifier::aArg:
> -  case ConversionSpecifier::AArg:
> -  case ConversionSpecifier::FreeBSDrArg:
> -  case ConversionSpecifier::FreeBSDyArg:
> -    return true;
> -
> -  default:
> -    return false;
> -  }
> -}
> -
> -bool PrintfSpecifier::hasValidAlternativeForm() const {
> -  if (!HasAlternativeForm)
> -    return true;
> -
> -  // Alternate form flag only valid with the oxXaAeEfFgG conversions
> -  switch (CS.getKind()) {
> -  case ConversionSpecifier::oArg:
> -  case ConversionSpecifier::OArg:
> -  case ConversionSpecifier::xArg:
> -  case ConversionSpecifier::XArg:
> -  case ConversionSpecifier::aArg:
> -  case ConversionSpecifier::AArg:
> -  case ConversionSpecifier::eArg:
> -  case ConversionSpecifier::EArg:
> -  case ConversionSpecifier::fArg:
> -  case ConversionSpecifier::FArg:
> -  case ConversionSpecifier::gArg:
> -  case ConversionSpecifier::GArg:
> -  case ConversionSpecifier::FreeBSDrArg:
> -  case ConversionSpecifier::FreeBSDyArg:
> -    return true;
> -
> -  default:
> -    return false;
> -  }
> -}
> -
> -bool PrintfSpecifier::hasValidLeadingZeros() const {
> -  if (!HasLeadingZeroes)
> -    return true;
> -
> -  // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
> -  switch (CS.getKind()) {
> -  case ConversionSpecifier::dArg:
> -  case ConversionSpecifier::DArg:
> -  case ConversionSpecifier::iArg:
> -  case ConversionSpecifier::oArg:
> -  case ConversionSpecifier::OArg:
> -  case ConversionSpecifier::uArg:
> -  case ConversionSpecifier::UArg:
> -  case ConversionSpecifier::xArg:
> -  case ConversionSpecifier::XArg:
> -  case ConversionSpecifier::aArg:
> -  case ConversionSpecifier::AArg:
> -  case ConversionSpecifier::eArg:
> -  case ConversionSpecifier::EArg:
> -  case ConversionSpecifier::fArg:
> -  case ConversionSpecifier::FArg:
> -  case ConversionSpecifier::gArg:
> -  case ConversionSpecifier::GArg:
> -  case ConversionSpecifier::FreeBSDrArg:
> -  case ConversionSpecifier::FreeBSDyArg:
> -    return true;
> -
> -  default:
> -    return false;
> -  }
> -}
> -
> -bool PrintfSpecifier::hasValidSpacePrefix() const {
> -  if (!HasSpacePrefix)
> -    return true;
> -
> -  // The space prefix only makes sense for signed conversions
> -  switch (CS.getKind()) {
> -  case ConversionSpecifier::dArg:
> -  case ConversionSpecifier::DArg:
> -  case ConversionSpecifier::iArg:
> -  case ConversionSpecifier::fArg:
> -  case ConversionSpecifier::FArg:
> -  case ConversionSpecifier::eArg:
> -  case ConversionSpecifier::EArg:
> -  case ConversionSpecifier::gArg:
> -  case ConversionSpecifier::GArg:
> -  case ConversionSpecifier::aArg:
> -  case ConversionSpecifier::AArg:
> -  case ConversionSpecifier::FreeBSDrArg:
> -  case ConversionSpecifier::FreeBSDyArg:
> -    return true;
> -
> -  default:
> -    return false;
> -  }
> -}
> -
> -bool PrintfSpecifier::hasValidLeftJustified() const {
> -  if (!IsLeftJustified)
> -    return true;
> -
> -  // The left justified flag is valid for all conversions except n
> -  switch (CS.getKind()) {
> -  case ConversionSpecifier::nArg:
> -    return false;
> -
> -  default:
> -    return true;
> -  }
> -}
> -
> -bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
> -  if (!HasThousandsGrouping)
> -    return true;
> -
> -  switch (CS.getKind()) {
> -    case ConversionSpecifier::dArg:
> -    case ConversionSpecifier::DArg:
> -    case ConversionSpecifier::iArg:
> -    case ConversionSpecifier::uArg:
> -    case ConversionSpecifier::UArg:
> -    case ConversionSpecifier::fArg:
> -    case ConversionSpecifier::FArg:
> -    case ConversionSpecifier::gArg:
> -    case ConversionSpecifier::GArg:
> -      return true;
> -    default:
> -      return false;
> -  }
> -}
> -
> -bool PrintfSpecifier::hasValidPrecision() const {
> -  if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
> -    return true;
> -
> -  // Precision is only valid with the diouxXaAeEfFgGsP conversions
> -  switch (CS.getKind()) {
> -  case ConversionSpecifier::dArg:
> -  case ConversionSpecifier::DArg:
> -  case ConversionSpecifier::iArg:
> -  case ConversionSpecifier::oArg:
> -  case ConversionSpecifier::OArg:
> -  case ConversionSpecifier::uArg:
> -  case ConversionSpecifier::UArg:
> -  case ConversionSpecifier::xArg:
> -  case ConversionSpecifier::XArg:
> -  case ConversionSpecifier::aArg:
> -  case ConversionSpecifier::AArg:
> -  case ConversionSpecifier::eArg:
> -  case ConversionSpecifier::EArg:
> -  case ConversionSpecifier::fArg:
> -  case ConversionSpecifier::FArg:
> -  case ConversionSpecifier::gArg:
> -  case ConversionSpecifier::GArg:
> -  case ConversionSpecifier::sArg:
> -  case ConversionSpecifier::FreeBSDrArg:
> -  case ConversionSpecifier::FreeBSDyArg:
> -  case ConversionSpecifier::PArg:
> -    return true;
> -
> -  default:
> -    return false;
> -  }
> -}
> -bool PrintfSpecifier::hasValidFieldWidth() const {
> -  if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
> -      return true;
> -
> -  // The field width is valid for all conversions except n
> -  switch (CS.getKind()) {
> -  case ConversionSpecifier::nArg:
> -    return false;
> -
> -  default:
> -    return true;
> -  }
> -}
>
> Removed: cfe/trunk/lib/Analysis/ScanfFormatString.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ScanfFormatString.cpp?rev=345970&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/ScanfFormatString.cpp (original)
> +++ cfe/trunk/lib/Analysis/ScanfFormatString.cpp (removed)
> @@ -1,563 +0,0 @@
> -//= ScanfFormatString.cpp - Analysis of printf format strings --*- C++
> -*-===//
> -//
> -//                     The LLVM Compiler Infrastructure
> -//
> -// This file is distributed under the University of Illinois Open Source
> -// License. See LICENSE.TXT for details.
> -//
>
> -//===----------------------------------------------------------------------===//
> -//
> -// Handling of format string in scanf and friends.  The structure of
> format
> -// strings for fscanf() are described in C99 7.19.6.2.
> -//
>
> -//===----------------------------------------------------------------------===//
> -
> -#include "clang/Analysis/Analyses/FormatString.h"
> -#include "FormatStringParsing.h"
> -#include "clang/Basic/TargetInfo.h"
> -
> -using clang::analyze_format_string::ArgType;
> -using clang::analyze_format_string::FormatStringHandler;
> -using clang::analyze_format_string::LengthModifier;
> -using clang::analyze_format_string::OptionalAmount;
> -using clang::analyze_format_string::ConversionSpecifier;
> -using clang::analyze_scanf::ScanfConversionSpecifier;
> -using clang::analyze_scanf::ScanfSpecifier;
> -using clang::UpdateOnReturn;
> -using namespace clang;
> -
> -typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier>
> -        ScanfSpecifierResult;
> -
> -static bool ParseScanList(FormatStringHandler &H,
> -                          ScanfConversionSpecifier &CS,
> -                          const char *&Beg, const char *E) {
> -  const char *I = Beg;
> -  const char *start = I - 1;
> -  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
> -
> -  // No more characters?
> -  if (I == E) {
> -    H.HandleIncompleteScanList(start, I);
> -    return true;
> -  }
> -
> -  // Special case: ']' is the first character.
> -  if (*I == ']') {
> -    if (++I == E) {
> -      H.HandleIncompleteScanList(start, I - 1);
> -      return true;
> -    }
> -  }
> -
> -  // Special case: "^]" are the first characters.
> -  if (I + 1 != E && I[0] == '^' && I[1] == ']') {
> -    I += 2;
> -    if (I == E) {
> -      H.HandleIncompleteScanList(start, I - 1);
> -      return true;
> -    }
> -  }
> -
> -  // Look for a ']' character which denotes the end of the scan list.
> -  while (*I != ']') {
> -    if (++I == E) {
> -      H.HandleIncompleteScanList(start, I - 1);
> -      return true;
> -    }
> -  }
> -
> -  CS.setEndScanList(I);
> -  return false;
> -}
> -
> -// FIXME: Much of this is copy-paste from ParsePrintfSpecifier.
> -// We can possibly refactor.
> -static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
> -                                                const char *&Beg,
> -                                                const char *E,
> -                                                unsigned &argIndex,
> -                                                const LangOptions &LO,
> -                                                const TargetInfo &Target)
> {
> -  using namespace clang::analyze_format_string;
> -  using namespace clang::analyze_scanf;
> -  const char *I = Beg;
> -  const char *Start = nullptr;
> -  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
> -
> -    // Look for a '%' character that indicates the start of a format
> specifier.
> -  for ( ; I != E ; ++I) {
> -    char c = *I;
> -    if (c == '\0') {
> -        // Detect spurious null characters, which are likely errors.
> -      H.HandleNullChar(I);
> -      return true;
> -    }
> -    if (c == '%') {
> -      Start = I++;  // Record the start of the format specifier.
> -      break;
> -    }
> -  }
> -
> -    // No format specifier found?
> -  if (!Start)
> -    return false;
> -
> -  if (I == E) {
> -      // No more characters left?
> -    H.HandleIncompleteSpecifier(Start, E - Start);
> -    return true;
> -  }
> -
> -  ScanfSpecifier FS;
> -  if (ParseArgPosition(H, FS, Start, I, E))
> -    return true;
> -
> -  if (I == E) {
> -      // No more characters left?
> -    H.HandleIncompleteSpecifier(Start, E - Start);
> -    return true;
> -  }
> -
> -  // Look for '*' flag if it is present.
> -  if (*I == '*') {
> -    FS.setSuppressAssignment(I);
> -    if (++I == E) {
> -      H.HandleIncompleteSpecifier(Start, E - Start);
> -      return true;
> -    }
> -  }
> -
> -  // Look for the field width (if any).  Unlike printf, this is either
> -  // a fixed integer or isn't present.
> -  const OptionalAmount &Amt =
> clang::analyze_format_string::ParseAmount(I, E);
> -  if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {
> -    assert(Amt.getHowSpecified() == OptionalAmount::Constant);
> -    FS.setFieldWidth(Amt);
> -
> -    if (I == E) {
> -      // No more characters left?
> -      H.HandleIncompleteSpecifier(Start, E - Start);
> -      return true;
> -    }
> -  }
> -
> -  // Look for the length modifier.
> -  if (ParseLengthModifier(FS, I, E, LO, /*scanf=*/true) && I == E) {
> -      // No more characters left?
> -    H.HandleIncompleteSpecifier(Start, E - Start);
> -    return true;
> -  }
> -
> -  // Detect spurious null characters, which are likely errors.
> -  if (*I == '\0') {
> -    H.HandleNullChar(I);
> -    return true;
> -  }
> -
> -  // Finally, look for the conversion specifier.
> -  const char *conversionPosition = I++;
> -  ScanfConversionSpecifier::Kind k =
> ScanfConversionSpecifier::InvalidSpecifier;
> -  switch (*conversionPosition) {
> -    default:
> -      break;
> -    case '%': k = ConversionSpecifier::PercentArg;   break;
> -    case 'A': k = ConversionSpecifier::AArg; break;
> -    case 'E': k = ConversionSpecifier::EArg; break;
> -    case 'F': k = ConversionSpecifier::FArg; break;
> -    case 'G': k = ConversionSpecifier::GArg; break;
> -    case 'X': k = ConversionSpecifier::XArg; break;
> -    case 'a': k = ConversionSpecifier::aArg; break;
> -    case 'd': k = ConversionSpecifier::dArg; break;
> -    case 'e': k = ConversionSpecifier::eArg; break;
> -    case 'f': k = ConversionSpecifier::fArg; break;
> -    case 'g': k = ConversionSpecifier::gArg; break;
> -    case 'i': k = ConversionSpecifier::iArg; break;
> -    case 'n': k = ConversionSpecifier::nArg; break;
> -    case 'c': k = ConversionSpecifier::cArg; break;
> -    case 'C': k = ConversionSpecifier::CArg; break;
> -    case 'S': k = ConversionSpecifier::SArg; break;
> -    case '[': k = ConversionSpecifier::ScanListArg; break;
> -    case 'u': k = ConversionSpecifier::uArg; break;
> -    case 'x': k = ConversionSpecifier::xArg; break;
> -    case 'o': k = ConversionSpecifier::oArg; break;
> -    case 's': k = ConversionSpecifier::sArg; break;
> -    case 'p': k = ConversionSpecifier::pArg; break;
> -    // Apple extensions
> -      // Apple-specific
> -    case 'D':
> -      if (Target.getTriple().isOSDarwin())
> -        k = ConversionSpecifier::DArg;
> -      break;
> -    case 'O':
> -      if (Target.getTriple().isOSDarwin())
> -        k = ConversionSpecifier::OArg;
> -      break;
> -    case 'U':
> -      if (Target.getTriple().isOSDarwin())
> -        k = ConversionSpecifier::UArg;
> -      break;
> -  }
> -  ScanfConversionSpecifier CS(conversionPosition, k);
> -  if (k == ScanfConversionSpecifier::ScanListArg) {
> -    if (ParseScanList(H, CS, I, E))
> -      return true;
> -  }
> -  FS.setConversionSpecifier(CS);
> -  if (CS.consumesDataArgument() && !FS.getSuppressAssignment()
> -      && !FS.usesPositionalArg())
> -    FS.setArgIndex(argIndex++);
> -
> -  // FIXME: '%' and '*' doesn't make sense.  Issue a warning.
> -  // FIXME: 'ConsumedSoFar' and '*' doesn't make sense.
> -
> -  if (k == ScanfConversionSpecifier::InvalidSpecifier) {
> -    unsigned Len = I - Beg;
> -    if (ParseUTF8InvalidSpecifier(Beg, E, Len)) {
> -      CS.setEndScanList(Beg + Len);
> -      FS.setConversionSpecifier(CS);
> -    }
> -    // Assume the conversion takes one argument.
> -    return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len);
> -  }
> -  return ScanfSpecifierResult(Start, FS);
> -}
> -
> -ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
> -  const ScanfConversionSpecifier &CS = getConversionSpecifier();
> -
> -  if (!CS.consumesDataArgument())
> -    return ArgType::Invalid();
> -
> -  switch(CS.getKind()) {
> -    // Signed int.
> -    case ConversionSpecifier::dArg:
> -    case ConversionSpecifier::DArg:
> -    case ConversionSpecifier::iArg:
> -      switch (LM.getKind()) {
> -        case LengthModifier::None:
> -          return ArgType::PtrTo(Ctx.IntTy);
> -        case LengthModifier::AsChar:
> -          return ArgType::PtrTo(ArgType::AnyCharTy);
> -        case LengthModifier::AsShort:
> -          return ArgType::PtrTo(Ctx.ShortTy);
> -        case LengthModifier::AsLong:
> -          return ArgType::PtrTo(Ctx.LongTy);
> -        case LengthModifier::AsLongLong:
> -        case LengthModifier::AsQuad:
> -          return ArgType::PtrTo(Ctx.LongLongTy);
> -        case LengthModifier::AsInt64:
> -          return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
> -        case LengthModifier::AsIntMax:
> -          return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
> -        case LengthModifier::AsSizeT:
> -          return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(),
> "ssize_t"));
> -        case LengthModifier::AsPtrDiff:
> -          return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(),
> "ptrdiff_t"));
> -        case LengthModifier::AsLongDouble:
> -          // GNU extension.
> -          return ArgType::PtrTo(Ctx.LongLongTy);
> -        case LengthModifier::AsAllocate:
> -        case LengthModifier::AsMAllocate:
> -        case LengthModifier::AsInt32:
> -        case LengthModifier::AsInt3264:
> -        case LengthModifier::AsWide:
> -          return ArgType::Invalid();
> -      }
> -
> -    // Unsigned int.
> -    case ConversionSpecifier::oArg:
> -    case ConversionSpecifier::OArg:
> -    case ConversionSpecifier::uArg:
> -    case ConversionSpecifier::UArg:
> -    case ConversionSpecifier::xArg:
> -    case ConversionSpecifier::XArg:
> -      switch (LM.getKind()) {
> -        case LengthModifier::None:
> -          return ArgType::PtrTo(Ctx.UnsignedIntTy);
> -        case LengthModifier::AsChar:
> -          return ArgType::PtrTo(Ctx.UnsignedCharTy);
> -        case LengthModifier::AsShort:
> -          return ArgType::PtrTo(Ctx.UnsignedShortTy);
> -        case LengthModifier::AsLong:
> -          return ArgType::PtrTo(Ctx.UnsignedLongTy);
> -        case LengthModifier::AsLongLong:
> -        case LengthModifier::AsQuad:
> -          return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
> -        case LengthModifier::AsInt64:
> -          return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned
> __int64"));
> -        case LengthModifier::AsIntMax:
> -          return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(),
> "uintmax_t"));
> -        case LengthModifier::AsSizeT:
> -          return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
> -        case LengthModifier::AsPtrDiff:
> -          return ArgType::PtrTo(
> -              ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned
> ptrdiff_t"));
> -        case LengthModifier::AsLongDouble:
> -          // GNU extension.
> -          return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
> -        case LengthModifier::AsAllocate:
> -        case LengthModifier::AsMAllocate:
> -        case LengthModifier::AsInt32:
> -        case LengthModifier::AsInt3264:
> -        case LengthModifier::AsWide:
> -          return ArgType::Invalid();
> -      }
> -
> -    // Float.
> -    case ConversionSpecifier::aArg:
> -    case ConversionSpecifier::AArg:
> -    case ConversionSpecifier::eArg:
> -    case ConversionSpecifier::EArg:
> -    case ConversionSpecifier::fArg:
> -    case ConversionSpecifier::FArg:
> -    case ConversionSpecifier::gArg:
> -    case ConversionSpecifier::GArg:
> -      switch (LM.getKind()) {
> -        case LengthModifier::None:
> -          return ArgType::PtrTo(Ctx.FloatTy);
> -        case LengthModifier::AsLong:
> -          return ArgType::PtrTo(Ctx.DoubleTy);
> -        case LengthModifier::AsLongDouble:
> -          return ArgType::PtrTo(Ctx.LongDoubleTy);
> -        default:
> -          return ArgType::Invalid();
> -      }
> -
> -    // Char, string and scanlist.
> -    case ConversionSpecifier::cArg:
> -    case ConversionSpecifier::sArg:
> -    case ConversionSpecifier::ScanListArg:
> -      switch (LM.getKind()) {
> -        case LengthModifier::None:
> -          return ArgType::PtrTo(ArgType::AnyCharTy);
> -        case LengthModifier::AsLong:
> -        case LengthModifier::AsWide:
> -          return ArgType::PtrTo(ArgType(Ctx.getWideCharType(),
> "wchar_t"));
> -        case LengthModifier::AsAllocate:
> -        case LengthModifier::AsMAllocate:
> -          return ArgType::PtrTo(ArgType::CStrTy);
> -        case LengthModifier::AsShort:
> -          if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
> -            return ArgType::PtrTo(ArgType::AnyCharTy);
> -          LLVM_FALLTHROUGH;
> -        default:
> -          return ArgType::Invalid();
> -      }
> -    case ConversionSpecifier::CArg:
> -    case ConversionSpecifier::SArg:
> -      // FIXME: Mac OS X specific?
> -      switch (LM.getKind()) {
> -        case LengthModifier::None:
> -        case LengthModifier::AsWide:
> -          return ArgType::PtrTo(ArgType(Ctx.getWideCharType(),
> "wchar_t"));
> -        case LengthModifier::AsAllocate:
> -        case LengthModifier::AsMAllocate:
> -          return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
> -        case LengthModifier::AsShort:
> -          if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
> -            return ArgType::PtrTo(ArgType::AnyCharTy);
> -          LLVM_FALLTHROUGH;
> -        default:
> -          return ArgType::Invalid();
> -      }
> -
> -    // Pointer.
> -    case ConversionSpecifier::pArg:
> -      return ArgType::PtrTo(ArgType::CPointerTy);
> -
> -    // Write-back.
> -    case ConversionSpecifier::nArg:
> -      switch (LM.getKind()) {
> -        case LengthModifier::None:
> -          return ArgType::PtrTo(Ctx.IntTy);
> -        case LengthModifier::AsChar:
> -          return ArgType::PtrTo(Ctx.SignedCharTy);
> -        case LengthModifier::AsShort:
> -          return ArgType::PtrTo(Ctx.ShortTy);
> -        case LengthModifier::AsLong:
> -          return ArgType::PtrTo(Ctx.LongTy);
> -        case LengthModifier::AsLongLong:
> -        case LengthModifier::AsQuad:
> -          return ArgType::PtrTo(Ctx.LongLongTy);
> -        case LengthModifier::AsInt64:
> -          return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
> -        case LengthModifier::AsIntMax:
> -          return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
> -        case LengthModifier::AsSizeT:
> -          return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(),
> "ssize_t"));
> -        case LengthModifier::AsPtrDiff:
> -          return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(),
> "ptrdiff_t"));
> -        case LengthModifier::AsLongDouble:
> -          return ArgType(); // FIXME: Is this a known extension?
> -        case LengthModifier::AsAllocate:
> -        case LengthModifier::AsMAllocate:
> -        case LengthModifier::AsInt32:
> -        case LengthModifier::AsInt3264:
> -        case LengthModifier::AsWide:
> -          return ArgType::Invalid();
> -        }
> -
> -    default:
> -      break;
> -  }
> -
> -  return ArgType();
> -}
> -
> -bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
> -                             const LangOptions &LangOpt,
> -                             ASTContext &Ctx) {
> -
> -  // %n is different from other conversion specifiers; don't try to fix
> it.
> -  if (CS.getKind() == ConversionSpecifier::nArg)
> -    return false;
> -
> -  if (!QT->isPointerType())
> -    return false;
> -
> -  QualType PT = QT->getPointeeType();
> -
> -  // If it's an enum, get its underlying type.
> -  if (const EnumType *ETy = PT->getAs<EnumType>()) {
> -    // Don't try to fix incomplete enums.
> -    if (!ETy->getDecl()->isComplete())
> -      return false;
> -    PT = ETy->getDecl()->getIntegerType();
> -  }
> -
> -  const BuiltinType *BT = PT->getAs<BuiltinType>();
> -  if (!BT)
> -    return false;
> -
> -  // Pointer to a character.
> -  if (PT->isAnyCharacterType()) {
> -    CS.setKind(ConversionSpecifier::sArg);
> -    if (PT->isWideCharType())
> -      LM.setKind(LengthModifier::AsWideChar);
> -    else
> -      LM.setKind(LengthModifier::None);
> -
> -    // If we know the target array length, we can use it as a field width.
> -    if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT))
> {
> -      if (CAT->getSizeModifier() == ArrayType::Normal)
> -        FieldWidth = OptionalAmount(OptionalAmount::Constant,
> -                                    CAT->getSize().getZExtValue() - 1,
> -                                    "", 0, false);
> -
> -    }
> -    return true;
> -  }
> -
> -  // Figure out the length modifier.
> -  switch (BT->getKind()) {
> -    // no modifier
> -    case BuiltinType::UInt:
> -    case BuiltinType::Int:
> -    case BuiltinType::Float:
> -      LM.setKind(LengthModifier::None);
> -      break;
> -
> -    // hh
> -    case BuiltinType::Char_U:
> -    case BuiltinType::UChar:
> -    case BuiltinType::Char_S:
> -    case BuiltinType::SChar:
> -      LM.setKind(LengthModifier::AsChar);
> -      break;
> -
> -    // h
> -    case BuiltinType::Short:
> -    case BuiltinType::UShort:
> -      LM.setKind(LengthModifier::AsShort);
> -      break;
> -
> -    // l
> -    case BuiltinType::Long:
> -    case BuiltinType::ULong:
> -    case BuiltinType::Double:
> -      LM.setKind(LengthModifier::AsLong);
> -      break;
> -
> -    // ll
> -    case BuiltinType::LongLong:
> -    case BuiltinType::ULongLong:
> -      LM.setKind(LengthModifier::AsLongLong);
> -      break;
> -
> -    // L
> -    case BuiltinType::LongDouble:
> -      LM.setKind(LengthModifier::AsLongDouble);
> -      break;
> -
> -    // Don't know.
> -    default:
> -      return false;
> -  }
> -
> -  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers
> in C99.
> -  if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
> -    namedTypeToLengthModifier(PT, LM);
> -
> -  // If fixing the length modifier was enough, we are done.
> -  if (hasValidLengthModifier(Ctx.getTargetInfo())) {
> -    const analyze_scanf::ArgType &AT = getArgType(Ctx);
> -    if (AT.isValid() && AT.matchesType(Ctx, QT))
> -      return true;
> -  }
> -
> -  // Figure out the conversion specifier.
> -  if (PT->isRealFloatingType())
> -    CS.setKind(ConversionSpecifier::fArg);
> -  else if (PT->isSignedIntegerType())
> -    CS.setKind(ConversionSpecifier::dArg);
> -  else if (PT->isUnsignedIntegerType())
> -    CS.setKind(ConversionSpecifier::uArg);
> -  else
> -    llvm_unreachable("Unexpected type");
> -
> -  return true;
> -}
> -
> -void ScanfSpecifier::toString(raw_ostream &os) const {
> -  os << "%";
> -
> -  if (usesPositionalArg())
> -    os << getPositionalArgIndex() << "$";
> -  if (SuppressAssignment)
> -    os << "*";
> -
> -  FieldWidth.toString(os);
> -  os << LM.toString();
> -  os << CS.toString();
> -}
> -
> -bool clang::analyze_format_string::ParseScanfString(FormatStringHandler
> &H,
> -                                                    const char *I,
> -                                                    const char *E,
> -                                                    const LangOptions &LO,
> -                                                    const TargetInfo
> &Target) {
> -
> -  unsigned argIndex = 0;
> -
> -  // Keep looking for a format specifier until we have exhausted the
> string.
> -  while (I != E) {
> -    const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E,
> argIndex,
> -                                                          LO, Target);
> -    // Did a fail-stop error of any kind occur when parsing the specifier?
> -    // If so, don't do any more processing.
> -    if (FSR.shouldStop())
> -      return true;
> -      // Did we exhaust the string or encounter an error that
> -      // we can recover from?
> -    if (!FSR.hasValue())
> -      continue;
> -      // We have a format specifier.  Pass it to the callback.
> -    if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(),
> -                                I - FSR.getStart())) {
> -      return true;
> -    }
> -  }
> -  assert(I == E && "Format string not exhausted");
> -  return false;
> -}
>
> Modified: cfe/trunk/lib/CodeGen/CGBuiltin.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBuiltin.cpp?rev=345971&r1=345970&r2=345971&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGBuiltin.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp Fri Nov  2 06:14:11 2018
> @@ -21,7 +21,7 @@
>  #include "TargetInfo.h"
>  #include "clang/AST/ASTContext.h"
>  #include "clang/AST/Decl.h"
> -#include "clang/Analysis/Analyses/OSLog.h"
> +#include "clang/AST/OSLog.h"
>  #include "clang/Basic/TargetBuiltins.h"
>  #include "clang/Basic/TargetInfo.h"
>  #include "clang/CodeGen/CGFunctionInfo.h"
> @@ -3606,13 +3606,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(
>    case Builtin::BI__builtin_os_log_format:
>      return emitBuiltinOSLogFormat(*E);
>
> -  case Builtin::BI__builtin_os_log_format_buffer_size: {
> -    analyze_os_log::OSLogBufferLayout Layout;
> -    analyze_os_log::computeOSLogBufferLayout(CGM.getContext(), E, Layout);
> -    return RValue::get(ConstantInt::get(ConvertType(E->getType()),
> -                                        Layout.size().getQuantity()));
> -  }
> -
>    case Builtin::BI__xray_customevent: {
>      if (!ShouldXRayInstrumentFunction())
>        return RValue::getIgnored();
>
> Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=345971&r1=345970&r2=345971&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaChecking.cpp Fri Nov  2 06:14:11 2018
> @@ -27,6 +27,7 @@
>  #include "clang/AST/ExprCXX.h"
>  #include "clang/AST/ExprObjC.h"
>  #include "clang/AST/ExprOpenMP.h"
> +#include "clang/AST/FormatString.h"
>  #include "clang/AST/NSAPI.h"
>  #include "clang/AST/NonTrivialTypeVisitor.h"
>  #include "clang/AST/OperationKinds.h"
> @@ -35,7 +36,6 @@
>  #include "clang/AST/Type.h"
>  #include "clang/AST/TypeLoc.h"
>  #include "clang/AST/UnresolvedSet.h"
> -#include "clang/Analysis/Analyses/FormatString.h"
>  #include "clang/Basic/AddressSpaces.h"
>  #include "clang/Basic/CharInfo.h"
>  #include "clang/Basic/Diagnostic.h"
>
> Modified: cfe/trunk/test/CodeGen/builtins.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/builtins.c?rev=345971&r1=345970&r2=345971&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGen/builtins.c (original)
> +++ cfe/trunk/test/CodeGen/builtins.c Fri Nov  2 06:14:11 2018
> @@ -729,25 +729,28 @@ void test_builtin_os_log_merge_helper1(v
>
>  // CHECK-LABEL: define void @test_builtin_os_log_errno
>  void test_builtin_os_log_errno() {
> -  // CHECK: %[[VLA:.*]] = alloca i8, i64 4, align 16
> -  // CHECK: call void @__os_log_helper_16_2_1_0_96(i8* %[[VLA]])
> +  // CHECK-NOT: @stacksave
> +  // CHECK: %[[BUF:.*]] = alloca [4 x i8], align 1
> +  // CHECK: %[[DECAY:.*]] = getelementptr inbounds [4 x i8], [4 x i8]*
> %[[BUF]], i32 0, i32 0
> +  // CHECK: call void @__os_log_helper_1_2_1_0_96(i8* %[[DECAY]])
> +  // CHECK-NOT: @stackrestore
>
>    char buf[__builtin_os_log_format_buffer_size("%m")];
>    __builtin_os_log_format(buf, "%m");
>  }
>
> -// CHECK-LABEL: define linkonce_odr hidden void
> @__os_log_helper_16_2_1_0_96
> +// CHECK-LABEL: define linkonce_odr hidden void
> @__os_log_helper_1_2_1_0_96
>  // CHECK: (i8* %[[BUFFER:.*]])
>
>  // CHECK: %[[BUFFER_ADDR:.*]] = alloca i8*, align 8
>  // CHECK: store i8* %[[BUFFER]], i8** %[[BUFFER_ADDR]], align 8
>  // CHECK: %[[BUF:.*]] = load i8*, i8** %[[BUFFER_ADDR]], align 8
>  // CHECK: %[[SUMMARY:.*]] = getelementptr i8, i8* %[[BUF]], i64 0
> -// CHECK: store i8 2, i8* %[[SUMMARY]], align 16
> +// CHECK: store i8 2, i8* %[[SUMMARY]], align 1
>  // CHECK: %[[NUMARGS:.*]] = getelementptr i8, i8* %[[BUF]], i64 1
>  // CHECK: store i8 1, i8* %[[NUMARGS]], align 1
>  // CHECK: %[[ARGDESCRIPTOR:.*]] = getelementptr i8, i8* %[[BUF]], i64 2
> -// CHECK: store i8 96, i8* %[[ARGDESCRIPTOR]], align 2
> +// CHECK: store i8 96, i8* %[[ARGDESCRIPTOR]], align 1
>  // CHECK: %[[ARGSIZE:.*]] = getelementptr i8, i8* %[[BUF]], i64 3
>  // CHECK: store i8 0, i8* %[[ARGSIZE]], align 1
>  // CHECK-NEXT: ret void
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20181102/046e3a84/attachment-0001.html>


More information about the cfe-commits mailing list