• Home
  • 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    }
213  
isIntArg()214    bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
215      kind == FreeBSDrArg || kind == FreeBSDyArg; }
isUIntArg()216    bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
isAnyIntArg()217    bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
218    const char *toString() const;
219  
isPrintfKind()220    bool isPrintfKind() const { return IsPrintf; }
221  
222    Optional<ConversionSpecifier> getStandardSpecifier() const;
223  
224  protected:
225    bool IsPrintf;
226    const char *Position;
227    const char *EndScanList;
228    Kind kind;
229  };
230  
231  class ArgType {
232  public:
233    enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
234                AnyCharTy, CStrTy, WCStrTy, WIntTy };
235  
236    enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic };
237  
238  private:
239    const Kind K;
240    QualType T;
241    const char *Name;
242    bool Ptr;
243  public:
244    ArgType(Kind k = UnknownTy, const char *n = nullptr)
K(k)245        : K(k), Name(n), Ptr(false) {}
246    ArgType(QualType t, const char *n = nullptr)
K(SpecificTy)247        : K(SpecificTy), T(t), Name(n), Ptr(false) {}
ArgType(CanQualType t)248    ArgType(CanQualType t) : K(SpecificTy), T(t), Name(nullptr), Ptr(false) {}
249  
Invalid()250    static ArgType Invalid() { return ArgType(InvalidTy); }
isValid()251    bool isValid() const { return K != InvalidTy; }
252  
253    /// Create an ArgType which corresponds to the type pointer to A.
PtrTo(const ArgType & A)254    static ArgType PtrTo(const ArgType& A) {
255      assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
256      ArgType Res = A;
257      Res.Ptr = true;
258      return Res;
259    }
260  
261    MatchKind matchesType(ASTContext &C, QualType argTy) const;
262  
263    QualType getRepresentativeType(ASTContext &C) const;
264  
265    std::string getRepresentativeTypeName(ASTContext &C) const;
266  };
267  
268  class OptionalAmount {
269  public:
270    enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
271  
OptionalAmount(HowSpecified howSpecified,unsigned amount,const char * amountStart,unsigned amountLength,bool usesPositionalArg)272    OptionalAmount(HowSpecified howSpecified,
273                   unsigned amount,
274                   const char *amountStart,
275                   unsigned amountLength,
276                   bool usesPositionalArg)
277    : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
278    UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
279  
280    OptionalAmount(bool valid = true)
start(nullptr)281    : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
282    UsesPositionalArg(0), UsesDotPrefix(0) {}
283  
isInvalid()284    bool isInvalid() const {
285      return hs == Invalid;
286    }
287  
getHowSpecified()288    HowSpecified getHowSpecified() const { return hs; }
setHowSpecified(HowSpecified h)289    void setHowSpecified(HowSpecified h) { hs = h; }
290  
hasDataArgument()291    bool hasDataArgument() const { return hs == Arg; }
292  
getArgIndex()293    unsigned getArgIndex() const {
294      assert(hasDataArgument());
295      return amt;
296    }
297  
getConstantAmount()298    unsigned getConstantAmount() const {
299      assert(hs == Constant);
300      return amt;
301    }
302  
getStart()303    const char *getStart() const {
304        // We include the . character if it is given.
305      return start - UsesDotPrefix;
306    }
307  
getConstantLength()308    unsigned getConstantLength() const {
309      assert(hs == Constant);
310      return length + UsesDotPrefix;
311    }
312  
313    ArgType getArgType(ASTContext &Ctx) const;
314  
315    void toString(raw_ostream &os) const;
316  
usesPositionalArg()317    bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
getPositionalArgIndex()318    unsigned getPositionalArgIndex() const {
319      assert(hasDataArgument());
320      return amt + 1;
321    }
322  
usesDotPrefix()323    bool usesDotPrefix() const { return UsesDotPrefix; }
setUsesDotPrefix()324    void setUsesDotPrefix() { UsesDotPrefix = true; }
325  
326  private:
327    const char *start;
328    unsigned length;
329    HowSpecified hs;
330    unsigned amt;
331    bool UsesPositionalArg : 1;
332    bool UsesDotPrefix;
333  };
334  
335  
336  class FormatSpecifier {
337  protected:
338    LengthModifier LM;
339    OptionalAmount FieldWidth;
340    ConversionSpecifier CS;
341    /// Positional arguments, an IEEE extension:
342    ///  IEEE Std 1003.1, 2004 Edition
343    ///  http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
344    bool UsesPositionalArg;
345    unsigned argIndex;
346  public:
FormatSpecifier(bool isPrintf)347    FormatSpecifier(bool isPrintf)
348      : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {}
349  
setLengthModifier(LengthModifier lm)350    void setLengthModifier(LengthModifier lm) {
351      LM = lm;
352    }
353  
setUsesPositionalArg()354    void setUsesPositionalArg() { UsesPositionalArg = true; }
355  
setArgIndex(unsigned i)356    void setArgIndex(unsigned i) {
357      argIndex = i;
358    }
359  
getArgIndex()360    unsigned getArgIndex() const {
361      return argIndex;
362    }
363  
getPositionalArgIndex()364    unsigned getPositionalArgIndex() const {
365      return argIndex + 1;
366    }
367  
getLengthModifier()368    const LengthModifier &getLengthModifier() const {
369      return LM;
370    }
371  
getFieldWidth()372    const OptionalAmount &getFieldWidth() const {
373      return FieldWidth;
374    }
375  
setFieldWidth(const OptionalAmount & Amt)376    void setFieldWidth(const OptionalAmount &Amt) {
377      FieldWidth = Amt;
378    }
379  
usesPositionalArg()380    bool usesPositionalArg() const { return UsesPositionalArg; }
381  
382    bool hasValidLengthModifier(const TargetInfo &Target) const;
383  
384    bool hasStandardLengthModifier() const;
385  
386    Optional<LengthModifier> getCorrectedLengthModifier() const;
387  
388    bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
389  
390    bool hasStandardLengthConversionCombination() const;
391  
392    /// For a TypedefType QT, if it is a named integer type such as size_t,
393    /// assign the appropriate value to LM and return true.
394    static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
395  };
396  
397  } // end analyze_format_string namespace
398  
399  //===----------------------------------------------------------------------===//
400  /// Pieces specific to fprintf format strings.
401  
402  namespace analyze_printf {
403  
404  class PrintfConversionSpecifier :
405    public analyze_format_string::ConversionSpecifier  {
406  public:
PrintfConversionSpecifier()407    PrintfConversionSpecifier()
408      : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
409  
PrintfConversionSpecifier(const char * pos,Kind k)410    PrintfConversionSpecifier(const char *pos, Kind k)
411      : ConversionSpecifier(true, pos, k) {}
412  
isObjCArg()413    bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
isDoubleArg()414    bool isDoubleArg() const { return kind >= DoubleArgBeg &&
415                                      kind <= DoubleArgEnd; }
getLength()416    unsigned getLength() const {
417        // Conversion specifiers currently only are represented by
418        // single characters, but we be flexible.
419      return 1;
420    }
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  
setEndScanList(const char * pos)549    void setEndScanList(const char *pos) { EndScanList = pos; }
550  
classof(const analyze_format_string::ConversionSpecifier * CS)551    static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
552      return !CS->isPrintfKind();
553    }
554  };
555  
556  using analyze_format_string::ArgType;
557  using analyze_format_string::LengthModifier;
558  using analyze_format_string::OptionalAmount;
559  using analyze_format_string::OptionalFlag;
560  
561  class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
562    OptionalFlag SuppressAssignment; // '*'
563  public:
ScanfSpecifier()564    ScanfSpecifier() :
565      FormatSpecifier(/* isPrintf = */ false),
566      SuppressAssignment("*") {}
567  
setSuppressAssignment(const char * position)568    void setSuppressAssignment(const char *position) {
569      SuppressAssignment.setPosition(position);
570    }
571  
getSuppressAssignment()572    const OptionalFlag &getSuppressAssignment() const {
573      return SuppressAssignment;
574    }
575  
setConversionSpecifier(const ScanfConversionSpecifier & cs)576    void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
577      CS = cs;
578    }
579  
getConversionSpecifier()580    const ScanfConversionSpecifier &getConversionSpecifier() const {
581      return cast<ScanfConversionSpecifier>(CS);
582    }
583  
consumesDataArgument()584    bool consumesDataArgument() const {
585      return CS.consumesDataArgument() && !SuppressAssignment;
586    }
587  
588    ArgType getArgType(ASTContext &Ctx) const;
589  
590    bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
591                 ASTContext &Ctx);
592  
593    void toString(raw_ostream &os) const;
594  
595    static ScanfSpecifier Parse(const char *beg, const char *end);
596  };
597  
598  } // end analyze_scanf namespace
599  
600  //===----------------------------------------------------------------------===//
601  // Parsing and processing of format strings (both fprintf and fscanf).
602  
603  namespace analyze_format_string {
604  
605  enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
606  
607  class FormatStringHandler {
608  public:
FormatStringHandler()609    FormatStringHandler() {}
610    virtual ~FormatStringHandler();
611  
HandleNullChar(const char * nullCharacter)612    virtual void HandleNullChar(const char *nullCharacter) {}
613  
HandlePosition(const char * startPos,unsigned posLen)614    virtual void HandlePosition(const char *startPos, unsigned posLen) {}
615  
HandleInvalidPosition(const char * startPos,unsigned posLen,PositionContext p)616    virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
617                                       PositionContext p) {}
618  
HandleZeroPosition(const char * startPos,unsigned posLen)619    virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
620  
HandleIncompleteSpecifier(const char * startSpecifier,unsigned specifierLen)621    virtual void HandleIncompleteSpecifier(const char *startSpecifier,
622                                           unsigned specifierLen) {}
623  
HandleEmptyObjCModifierFlag(const char * startFlags,unsigned flagsLen)624    virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
625                                             unsigned flagsLen) {}
626  
HandleInvalidObjCModifierFlag(const char * startFlag,unsigned flagLen)627    virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
628                                               unsigned flagLen) {}
629  
HandleObjCFlagsWithNonObjCConversion(const char * flagsStart,const char * flagsEnd,const char * conversionPosition)630    virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
631                                              const char *flagsEnd,
632                                              const char *conversionPosition) {}
633    // Printf-specific handlers.
634  
HandleInvalidPrintfConversionSpecifier(const analyze_printf::PrintfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)635    virtual bool HandleInvalidPrintfConversionSpecifier(
636                                        const analyze_printf::PrintfSpecifier &FS,
637                                        const char *startSpecifier,
638                                        unsigned specifierLen) {
639      return true;
640    }
641  
HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)642    virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
643                                       const char *startSpecifier,
644                                       unsigned specifierLen) {
645      return true;
646    }
647  
648      // Scanf-specific handlers.
649  
HandleInvalidScanfConversionSpecifier(const analyze_scanf::ScanfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)650    virtual bool HandleInvalidScanfConversionSpecifier(
651                                          const analyze_scanf::ScanfSpecifier &FS,
652                                          const char *startSpecifier,
653                                          unsigned specifierLen) {
654      return true;
655    }
656  
HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)657    virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
658                                      const char *startSpecifier,
659                                      unsigned specifierLen) {
660      return true;
661    }
662  
HandleIncompleteScanList(const char * start,const char * end)663    virtual void HandleIncompleteScanList(const char *start, const char *end) {}
664  };
665  
666  bool ParsePrintfString(FormatStringHandler &H,
667                         const char *beg, const char *end, const LangOptions &LO,
668                         const TargetInfo &Target, bool isFreeBSDKPrintf);
669  
670  bool ParseFormatStringHasSArg(const char *beg, const char *end,
671                                const LangOptions &LO, const TargetInfo &Target);
672  
673  bool ParseScanfString(FormatStringHandler &H,
674                        const char *beg, const char *end, const LangOptions &LO,
675                        const TargetInfo &Target);
676  
677  } // end analyze_format_string namespace
678  } // end clang namespace
679  #endif
680