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