• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  //= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===//
2  //
3  //                     The LLVM Compiler Infrastructure
4  //
5  // This file is distributed under the University of Illinois Open Source
6  // License. See LICENSE.TXT for details.
7  //
8  //===----------------------------------------------------------------------===//
9  //
10  // This file defines APIs for analyzing the format strings of printf, fscanf,
11  // and friends.
12  //
13  // The structure of format strings for fprintf are described in C99 7.19.6.1.
14  //
15  // The structure of format strings for fscanf are described in C99 7.19.6.2.
16  //
17  //===----------------------------------------------------------------------===//
18  
19  #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
20  #define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
21  
22  #include "clang/AST/CanonicalType.h"
23  
24  namespace clang {
25  
26  class TargetInfo;
27  
28  //===----------------------------------------------------------------------===//
29  /// Common components of both fprintf and fscanf format strings.
30  namespace analyze_format_string {
31  
32  /// Class representing optional flags with location and representation
33  /// information.
34  class OptionalFlag {
35  public:
OptionalFlag(const char * Representation)36    OptionalFlag(const char *Representation)
37        : representation(Representation), flag(false) {}
isSet()38    bool isSet() { return flag; }
set()39    void set() { flag = true; }
clear()40    void clear() { flag = false; }
setPosition(const char * position)41    void setPosition(const char *position) {
42      assert(position);
43      flag = true;
44      this->position = position;
45    }
getPosition()46    const char *getPosition() const {
47      assert(position);
48      return position;
49    }
toString()50    const char *toString() const { return representation; }
51  
52    // Overloaded operators for bool like qualities
53    explicit operator bool() const { return flag; }
54    OptionalFlag& operator=(const bool &rhs) {
55      flag = rhs;
56      return *this;  // Return a reference to myself.
57    }
58  private:
59    const char *representation;
60    const char *position;
61    bool flag;
62  };
63  
64  /// Represents the length modifier in a format string in scanf/printf.
65  class LengthModifier {
66  public:
67    enum Kind {
68      None,
69      AsChar,       // 'hh'
70      AsShort,      // 'h'
71      AsLong,       // 'l'
72      AsLongLong,   // 'll'
73      AsQuad,       // 'q' (BSD, deprecated, for 64-bit integer types)
74      AsIntMax,     // 'j'
75      AsSizeT,      // 'z'
76      AsPtrDiff,    // 't'
77      AsInt32,      // 'I32' (MSVCRT, like __int32)
78      AsInt3264,    // 'I'   (MSVCRT, like __int3264 from MIDL)
79      AsInt64,      // 'I64' (MSVCRT, like __int64)
80      AsLongDouble, // 'L'
81      AsAllocate,   // for '%as', GNU extension to C90 scanf
82      AsMAllocate,  // for '%ms', GNU extension to scanf
83      AsWide,       // 'w' (MSVCRT, like l but only for c, C, s, S, or Z
84      AsWideChar = AsLong // for '%ls', only makes sense for printf
85    };
86  
LengthModifier()87    LengthModifier()
88      : Position(nullptr), kind(None) {}
LengthModifier(const char * pos,Kind k)89    LengthModifier(const char *pos, Kind k)
90      : Position(pos), kind(k) {}
91  
getStart()92    const char *getStart() const {
93      return Position;
94    }
95  
getLength()96    unsigned getLength() const {
97      switch (kind) {
98        default:
99          return 1;
100        case AsLongLong:
101        case AsChar:
102          return 2;
103        case AsInt32:
104        case AsInt64:
105          return 3;
106        case None:
107          return 0;
108      }
109    }
110  
getKind()111    Kind getKind() const { return kind; }
setKind(Kind k)112    void setKind(Kind k) { kind = k; }
113  
114    const char *toString() const;
115  
116  private:
117    const char *Position;
118    Kind kind;
119  };
120  
121  class ConversionSpecifier {
122  public:
123    enum Kind {
124      InvalidSpecifier = 0,
125        // C99 conversion specifiers.
126      cArg,
127      dArg,
128      DArg, // Apple extension
129      iArg,
130      IntArgBeg = dArg, IntArgEnd = iArg,
131  
132      oArg,
133      OArg, // Apple extension
134      uArg,
135      UArg, // Apple extension
136      xArg,
137      XArg,
138      UIntArgBeg = oArg, UIntArgEnd = XArg,
139  
140      fArg,
141      FArg,
142      eArg,
143      EArg,
144      gArg,
145      GArg,
146      aArg,
147      AArg,
148      DoubleArgBeg = fArg, DoubleArgEnd = AArg,
149  
150      sArg,
151      pArg,
152      nArg,
153      PercentArg,
154      CArg,
155      SArg,
156  
157      // ** Printf-specific **
158  
159      ZArg, // MS extension
160  
161      // Objective-C specific specifiers.
162      ObjCObjArg,  // '@'
163      ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg,
164  
165      // FreeBSD kernel specific specifiers.
166      FreeBSDbArg,
167      FreeBSDDArg,
168      FreeBSDrArg,
169      FreeBSDyArg,
170  
171      // GlibC specific specifiers.
172      PrintErrno,   // 'm'
173  
174      PrintfConvBeg = ObjCObjArg, PrintfConvEnd = PrintErrno,
175  
176      // ** Scanf-specific **
177      ScanListArg, // '['
178      ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg
179    };
180  
181    ConversionSpecifier(bool isPrintf = true)
IsPrintf(isPrintf)182      : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
183        kind(InvalidSpecifier) {}
184  
ConversionSpecifier(bool isPrintf,const char * pos,Kind k)185    ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
186      : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
187  
getStart()188    const char *getStart() const {
189      return Position;
190    }
191  
getCharacters()192    StringRef getCharacters() const {
193      return StringRef(getStart(), getLength());
194    }
195  
consumesDataArgument()196    bool consumesDataArgument() const {
197      switch (kind) {
198        case PrintErrno:
199          assert(IsPrintf);
200          return false;
201        case PercentArg:
202          return false;
203        default:
204          return true;
205      }
206    }
207  
getKind()208    Kind getKind() const { return kind; }
setKind(Kind k)209    void setKind(Kind k) { kind = k; }
getLength()210    unsigned getLength() const {
211      return EndScanList ? EndScanList - Position : 1;
212    }
setEndScanList(const char * pos)213    void setEndScanList(const char *pos) { EndScanList = pos; }
214  
isIntArg()215    bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
216      kind == FreeBSDrArg || kind == FreeBSDyArg; }
isUIntArg()217    bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
isAnyIntArg()218    bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
isDoubleArg()219    bool isDoubleArg() const {
220      return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
221    }
222  
223    const char *toString() const;
224  
isPrintfKind()225    bool isPrintfKind() const { return IsPrintf; }
226  
227    Optional<ConversionSpecifier> getStandardSpecifier() const;
228  
229  protected:
230    bool IsPrintf;
231    const char *Position;
232    const char *EndScanList;
233    Kind kind;
234  };
235  
236  class ArgType {
237  public:
238    enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
239                AnyCharTy, CStrTy, WCStrTy, WIntTy };
240  
241    enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic };
242  
243  private:
244    const Kind K;
245    QualType T;
246    const char *Name;
247    bool Ptr;
248  public:
249    ArgType(Kind k = UnknownTy, const char *n = nullptr)
K(k)250        : K(k), Name(n), Ptr(false) {}
251    ArgType(QualType t, const char *n = nullptr)
K(SpecificTy)252        : K(SpecificTy), T(t), Name(n), Ptr(false) {}
ArgType(CanQualType t)253    ArgType(CanQualType t) : K(SpecificTy), T(t), Name(nullptr), Ptr(false) {}
254  
Invalid()255    static ArgType Invalid() { return ArgType(InvalidTy); }
isValid()256    bool isValid() const { return K != InvalidTy; }
257  
258    /// Create an ArgType which corresponds to the type pointer to A.
PtrTo(const ArgType & A)259    static ArgType PtrTo(const ArgType& A) {
260      assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
261      ArgType Res = A;
262      Res.Ptr = true;
263      return Res;
264    }
265  
266    MatchKind matchesType(ASTContext &C, QualType argTy) const;
267  
268    QualType getRepresentativeType(ASTContext &C) const;
269  
270    std::string getRepresentativeTypeName(ASTContext &C) const;
271  };
272  
273  class OptionalAmount {
274  public:
275    enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
276  
OptionalAmount(HowSpecified howSpecified,unsigned amount,const char * amountStart,unsigned amountLength,bool usesPositionalArg)277    OptionalAmount(HowSpecified howSpecified,
278                   unsigned amount,
279                   const char *amountStart,
280                   unsigned amountLength,
281                   bool usesPositionalArg)
282    : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
283    UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
284  
285    OptionalAmount(bool valid = true)
start(nullptr)286    : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
287    UsesPositionalArg(0), UsesDotPrefix(0) {}
288  
isInvalid()289    bool isInvalid() const {
290      return hs == Invalid;
291    }
292  
getHowSpecified()293    HowSpecified getHowSpecified() const { return hs; }
setHowSpecified(HowSpecified h)294    void setHowSpecified(HowSpecified h) { hs = h; }
295  
hasDataArgument()296    bool hasDataArgument() const { return hs == Arg; }
297  
getArgIndex()298    unsigned getArgIndex() const {
299      assert(hasDataArgument());
300      return amt;
301    }
302  
getConstantAmount()303    unsigned getConstantAmount() const {
304      assert(hs == Constant);
305      return amt;
306    }
307  
getStart()308    const char *getStart() const {
309        // We include the . character if it is given.
310      return start - UsesDotPrefix;
311    }
312  
getConstantLength()313    unsigned getConstantLength() const {
314      assert(hs == Constant);
315      return length + UsesDotPrefix;
316    }
317  
318    ArgType getArgType(ASTContext &Ctx) const;
319  
320    void toString(raw_ostream &os) const;
321  
usesPositionalArg()322    bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
getPositionalArgIndex()323    unsigned getPositionalArgIndex() const {
324      assert(hasDataArgument());
325      return amt + 1;
326    }
327  
usesDotPrefix()328    bool usesDotPrefix() const { return UsesDotPrefix; }
setUsesDotPrefix()329    void setUsesDotPrefix() { UsesDotPrefix = true; }
330  
331  private:
332    const char *start;
333    unsigned length;
334    HowSpecified hs;
335    unsigned amt;
336    bool UsesPositionalArg : 1;
337    bool UsesDotPrefix;
338  };
339  
340  
341  class FormatSpecifier {
342  protected:
343    LengthModifier LM;
344    OptionalAmount FieldWidth;
345    ConversionSpecifier CS;
346    /// Positional arguments, an IEEE extension:
347    ///  IEEE Std 1003.1, 2004 Edition
348    ///  http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
349    bool UsesPositionalArg;
350    unsigned argIndex;
351  public:
FormatSpecifier(bool isPrintf)352    FormatSpecifier(bool isPrintf)
353      : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {}
354  
setLengthModifier(LengthModifier lm)355    void setLengthModifier(LengthModifier lm) {
356      LM = lm;
357    }
358  
setUsesPositionalArg()359    void setUsesPositionalArg() { UsesPositionalArg = true; }
360  
setArgIndex(unsigned i)361    void setArgIndex(unsigned i) {
362      argIndex = i;
363    }
364  
getArgIndex()365    unsigned getArgIndex() const {
366      return argIndex;
367    }
368  
getPositionalArgIndex()369    unsigned getPositionalArgIndex() const {
370      return argIndex + 1;
371    }
372  
getLengthModifier()373    const LengthModifier &getLengthModifier() const {
374      return LM;
375    }
376  
getFieldWidth()377    const OptionalAmount &getFieldWidth() const {
378      return FieldWidth;
379    }
380  
setFieldWidth(const OptionalAmount & Amt)381    void setFieldWidth(const OptionalAmount &Amt) {
382      FieldWidth = Amt;
383    }
384  
usesPositionalArg()385    bool usesPositionalArg() const { return UsesPositionalArg; }
386  
387    bool hasValidLengthModifier(const TargetInfo &Target) const;
388  
389    bool hasStandardLengthModifier() const;
390  
391    Optional<LengthModifier> getCorrectedLengthModifier() const;
392  
393    bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
394  
395    bool hasStandardLengthConversionCombination() const;
396  
397    /// For a TypedefType QT, if it is a named integer type such as size_t,
398    /// assign the appropriate value to LM and return true.
399    static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
400  };
401  
402  } // end analyze_format_string namespace
403  
404  //===----------------------------------------------------------------------===//
405  /// Pieces specific to fprintf format strings.
406  
407  namespace analyze_printf {
408  
409  class PrintfConversionSpecifier :
410    public analyze_format_string::ConversionSpecifier  {
411  public:
PrintfConversionSpecifier()412    PrintfConversionSpecifier()
413      : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
414  
PrintfConversionSpecifier(const char * pos,Kind k)415    PrintfConversionSpecifier(const char *pos, Kind k)
416      : ConversionSpecifier(true, pos, k) {}
417  
isObjCArg()418    bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
isDoubleArg()419    bool isDoubleArg() const { return kind >= DoubleArgBeg &&
420                                      kind <= DoubleArgEnd; }
421  
classof(const analyze_format_string::ConversionSpecifier * CS)422    static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
423      return CS->isPrintfKind();
424    }
425  };
426  
427  using analyze_format_string::ArgType;
428  using analyze_format_string::LengthModifier;
429  using analyze_format_string::OptionalAmount;
430  using analyze_format_string::OptionalFlag;
431  
432  class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
433    OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
434    OptionalFlag IsLeftJustified; // '-'
435    OptionalFlag HasPlusPrefix; // '+'
436    OptionalFlag HasSpacePrefix; // ' '
437    OptionalFlag HasAlternativeForm; // '#'
438    OptionalFlag HasLeadingZeroes; // '0'
439    OptionalFlag HasObjCTechnicalTerm; // '[tt]'
440    OptionalAmount Precision;
441  public:
PrintfSpecifier()442    PrintfSpecifier() :
443      FormatSpecifier(/* isPrintf = */ true),
444      HasThousandsGrouping("'"), IsLeftJustified("-"), HasPlusPrefix("+"),
445      HasSpacePrefix(" "), HasAlternativeForm("#"), HasLeadingZeroes("0"),
446      HasObjCTechnicalTerm("tt") {}
447  
448    static PrintfSpecifier Parse(const char *beg, const char *end);
449  
450      // Methods for incrementally constructing the PrintfSpecifier.
setConversionSpecifier(const PrintfConversionSpecifier & cs)451    void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
452      CS = cs;
453    }
setHasThousandsGrouping(const char * position)454    void setHasThousandsGrouping(const char *position) {
455      HasThousandsGrouping.setPosition(position);
456    }
setIsLeftJustified(const char * position)457    void setIsLeftJustified(const char *position) {
458      IsLeftJustified.setPosition(position);
459    }
setHasPlusPrefix(const char * position)460    void setHasPlusPrefix(const char *position) {
461      HasPlusPrefix.setPosition(position);
462    }
setHasSpacePrefix(const char * position)463    void setHasSpacePrefix(const char *position) {
464      HasSpacePrefix.setPosition(position);
465    }
setHasAlternativeForm(const char * position)466    void setHasAlternativeForm(const char *position) {
467      HasAlternativeForm.setPosition(position);
468    }
setHasLeadingZeros(const char * position)469    void setHasLeadingZeros(const char *position) {
470      HasLeadingZeroes.setPosition(position);
471    }
setHasObjCTechnicalTerm(const char * position)472    void setHasObjCTechnicalTerm(const char *position) {
473      HasObjCTechnicalTerm.setPosition(position);
474    }
setUsesPositionalArg()475    void setUsesPositionalArg() { UsesPositionalArg = true; }
476  
477      // Methods for querying the format specifier.
478  
getConversionSpecifier()479    const PrintfConversionSpecifier &getConversionSpecifier() const {
480      return cast<PrintfConversionSpecifier>(CS);
481    }
482  
setPrecision(const OptionalAmount & Amt)483    void setPrecision(const OptionalAmount &Amt) {
484      Precision = Amt;
485      Precision.setUsesDotPrefix();
486    }
487  
getPrecision()488    const OptionalAmount &getPrecision() const {
489      return Precision;
490    }
491  
consumesDataArgument()492    bool consumesDataArgument() const {
493      return getConversionSpecifier().consumesDataArgument();
494    }
495  
496    /// \brief Returns the builtin type that a data argument
497    /// paired with this format specifier should have.  This method
498    /// will return null if the format specifier does not have
499    /// a matching data argument or the matching argument matches
500    /// more than one type.
501    ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
502  
hasThousandsGrouping()503    const OptionalFlag &hasThousandsGrouping() const {
504        return HasThousandsGrouping;
505    }
isLeftJustified()506    const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
hasPlusPrefix()507    const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
hasAlternativeForm()508    const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
hasLeadingZeros()509    const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
hasSpacePrefix()510    const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
hasObjCTechnicalTerm()511    const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }
usesPositionalArg()512    bool usesPositionalArg() const { return UsesPositionalArg; }
513  
514    /// Changes the specifier and length according to a QualType, retaining any
515    /// flags or options. Returns true on success, or false when a conversion
516    /// was not successful.
517    bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
518                 bool IsObjCLiteral);
519  
520    void toString(raw_ostream &os) const;
521  
522    // Validation methods - to check if any element results in undefined behavior
523    bool hasValidPlusPrefix() const;
524    bool hasValidAlternativeForm() const;
525    bool hasValidLeadingZeros() const;
526    bool hasValidSpacePrefix() const;
527    bool hasValidLeftJustified() const;
528    bool hasValidThousandsGroupingPrefix() const;
529  
530    bool hasValidPrecision() const;
531    bool hasValidFieldWidth() const;
532  };
533  }  // end analyze_printf namespace
534  
535  //===----------------------------------------------------------------------===//
536  /// Pieces specific to fscanf format strings.
537  
538  namespace analyze_scanf {
539  
540  class ScanfConversionSpecifier :
541      public analyze_format_string::ConversionSpecifier  {
542  public:
ScanfConversionSpecifier()543    ScanfConversionSpecifier()
544      : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
545  
ScanfConversionSpecifier(const char * pos,Kind k)546    ScanfConversionSpecifier(const char *pos, Kind k)
547      : ConversionSpecifier(false, pos, k) {}
548  
classof(const analyze_format_string::ConversionSpecifier * CS)549    static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
550      return !CS->isPrintfKind();
551    }
552  };
553  
554  using analyze_format_string::ArgType;
555  using analyze_format_string::LengthModifier;
556  using analyze_format_string::OptionalAmount;
557  using analyze_format_string::OptionalFlag;
558  
559  class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
560    OptionalFlag SuppressAssignment; // '*'
561  public:
ScanfSpecifier()562    ScanfSpecifier() :
563      FormatSpecifier(/* isPrintf = */ false),
564      SuppressAssignment("*") {}
565  
setSuppressAssignment(const char * position)566    void setSuppressAssignment(const char *position) {
567      SuppressAssignment.setPosition(position);
568    }
569  
getSuppressAssignment()570    const OptionalFlag &getSuppressAssignment() const {
571      return SuppressAssignment;
572    }
573  
setConversionSpecifier(const ScanfConversionSpecifier & cs)574    void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
575      CS = cs;
576    }
577  
getConversionSpecifier()578    const ScanfConversionSpecifier &getConversionSpecifier() const {
579      return cast<ScanfConversionSpecifier>(CS);
580    }
581  
consumesDataArgument()582    bool consumesDataArgument() const {
583      return CS.consumesDataArgument() && !SuppressAssignment;
584    }
585  
586    ArgType getArgType(ASTContext &Ctx) const;
587  
588    bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
589                 ASTContext &Ctx);
590  
591    void toString(raw_ostream &os) const;
592  
593    static ScanfSpecifier Parse(const char *beg, const char *end);
594  };
595  
596  } // end analyze_scanf namespace
597  
598  //===----------------------------------------------------------------------===//
599  // Parsing and processing of format strings (both fprintf and fscanf).
600  
601  namespace analyze_format_string {
602  
603  enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
604  
605  class FormatStringHandler {
606  public:
FormatStringHandler()607    FormatStringHandler() {}
608    virtual ~FormatStringHandler();
609  
HandleNullChar(const char * nullCharacter)610    virtual void HandleNullChar(const char *nullCharacter) {}
611  
HandlePosition(const char * startPos,unsigned posLen)612    virtual void HandlePosition(const char *startPos, unsigned posLen) {}
613  
HandleInvalidPosition(const char * startPos,unsigned posLen,PositionContext p)614    virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
615                                       PositionContext p) {}
616  
HandleZeroPosition(const char * startPos,unsigned posLen)617    virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
618  
HandleIncompleteSpecifier(const char * startSpecifier,unsigned specifierLen)619    virtual void HandleIncompleteSpecifier(const char *startSpecifier,
620                                           unsigned specifierLen) {}
621  
HandleEmptyObjCModifierFlag(const char * startFlags,unsigned flagsLen)622    virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
623                                             unsigned flagsLen) {}
624  
HandleInvalidObjCModifierFlag(const char * startFlag,unsigned flagLen)625    virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
626                                               unsigned flagLen) {}
627  
HandleObjCFlagsWithNonObjCConversion(const char * flagsStart,const char * flagsEnd,const char * conversionPosition)628    virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
629                                              const char *flagsEnd,
630                                              const char *conversionPosition) {}
631    // Printf-specific handlers.
632  
HandleInvalidPrintfConversionSpecifier(const analyze_printf::PrintfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)633    virtual bool HandleInvalidPrintfConversionSpecifier(
634                                        const analyze_printf::PrintfSpecifier &FS,
635                                        const char *startSpecifier,
636                                        unsigned specifierLen) {
637      return true;
638    }
639  
HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)640    virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
641                                       const char *startSpecifier,
642                                       unsigned specifierLen) {
643      return true;
644    }
645  
646      // Scanf-specific handlers.
647  
HandleInvalidScanfConversionSpecifier(const analyze_scanf::ScanfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)648    virtual bool HandleInvalidScanfConversionSpecifier(
649                                          const analyze_scanf::ScanfSpecifier &FS,
650                                          const char *startSpecifier,
651                                          unsigned specifierLen) {
652      return true;
653    }
654  
HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)655    virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
656                                      const char *startSpecifier,
657                                      unsigned specifierLen) {
658      return true;
659    }
660  
HandleIncompleteScanList(const char * start,const char * end)661    virtual void HandleIncompleteScanList(const char *start, const char *end) {}
662  };
663  
664  bool ParsePrintfString(FormatStringHandler &H,
665                         const char *beg, const char *end, const LangOptions &LO,
666                         const TargetInfo &Target, bool isFreeBSDKPrintf);
667  
668  bool ParseFormatStringHasSArg(const char *beg, const char *end,
669                                const LangOptions &LO, const TargetInfo &Target);
670  
671  bool ParseScanfString(FormatStringHandler &H,
672                        const char *beg, const char *end, const LangOptions &LO,
673                        const TargetInfo &Target);
674  
675  } // end analyze_format_string namespace
676  } // end clang namespace
677  #endif
678