11541Srgrimes//= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===//
214500Shsu//
31541Srgrimes//                     The LLVM Compiler Infrastructure
41541Srgrimes//
51541Srgrimes// This file is distributed under the University of Illinois Open Source
61541Srgrimes// License. See LICENSE.TXT for details.
71541Srgrimes//
81541Srgrimes//===----------------------------------------------------------------------===//
91541Srgrimes//
101541Srgrimes// This file defines APIs for analyzing the format strings of printf, fscanf,
111541Srgrimes// and friends.
121541Srgrimes//
131541Srgrimes// The structure of format strings for fprintf are described in C99 7.19.6.1.
141541Srgrimes//
151541Srgrimes// The structure of format strings for fscanf are described in C99 7.19.6.2.
161541Srgrimes//
171541Srgrimes//===----------------------------------------------------------------------===//
181541Srgrimes
191541Srgrimes#ifndef LLVM_CLANG_FORMAT_H
201541Srgrimes#define LLVM_CLANG_FORMAT_H
211541Srgrimes
221541Srgrimes#include "clang/AST/CanonicalType.h"
231541Srgrimes
241541Srgrimesnamespace clang {
251541Srgrimes
261541Srgrimesclass TargetInfo;
271541Srgrimes
281541Srgrimes//===----------------------------------------------------------------------===//
291541Srgrimes/// Common components of both fprintf and fscanf format strings.
301541Srgrimesnamespace analyze_format_string {
311541Srgrimes
321541Srgrimes/// Class representing optional flags with location and representation
331541Srgrimes/// information.
3414500Shsuclass OptionalFlag {
3550477Speterpublic:
361541Srgrimes  OptionalFlag(const char *Representation)
371541Srgrimes      : representation(Representation), flag(false) {}
381541Srgrimes  bool isSet() { return flag; }
391541Srgrimes  void set() { flag = true; }
401541Srgrimes  void clear() { flag = false; }
4133778Sbde  void setPosition(const char *position) {
4233778Sbde    assert(position);
431541Srgrimes    this->position = position;
4490868Smike  }
4593514Smike  const char *getPosition() const {
461541Srgrimes    assert(position);
47104341Smike    return position;
481541Srgrimes  }
491541Srgrimes  const char *toString() const { return representation; }
501541Srgrimes
511541Srgrimes  // Overloaded operators for bool like qualities
52128448Sobrien  LLVM_EXPLICIT operator bool() const { return flag; }
531541Srgrimes  OptionalFlag& operator=(const bool &rhs) {
541541Srgrimes    flag = rhs;
551541Srgrimes    return *this;  // Return a reference to myself.
56128448Sobrien  }
571541Srgrimesprivate:
5893514Smike  const char *representation;
5993514Smike  const char *position;
6093514Smike  bool flag;
6193514Smike};
6293514Smike
6393514Smike/// Represents the length modifier in a format string in scanf/printf.
6493514Smikeclass LengthModifier {
6593514Smikepublic:
6693514Smike  enum Kind {
6793514Smike    None,
6893514Smike    AsChar,       // 'hh'
6993514Smike    AsShort,      // 'h'
7093514Smike    AsLong,       // 'l'
7193514Smike    AsLongLong,   // 'll'
7293514Smike    AsQuad,       // 'q' (BSD, deprecated, for 64-bit integer types)
7393514Smike    AsIntMax,     // 'j'
7493514Smike    AsSizeT,      // 'z'
7593514Smike    AsPtrDiff,    // 't'
7693514Smike    AsInt32,      // 'I32' (MSVCRT, like __int32)
7793514Smike    AsInt3264,    // 'I'   (MSVCRT, like __int3264 from MIDL)
7893514Smike    AsInt64,      // 'I64' (MSVCRT, like __int64)
7993514Smike    AsLongDouble, // 'L'
8093514Smike    AsAllocate,   // for '%as', GNU extension to C90 scanf
8193514Smike    AsMAllocate,  // for '%ms', GNU extension to scanf
8293514Smike    AsWideChar = AsLong // for '%ls', only makes sense for printf
8393514Smike  };
8493514Smike
8593514Smike  LengthModifier()
8693514Smike    : Position(0), kind(None) {}
8793514Smike  LengthModifier(const char *pos, Kind k)
8893514Smike    : Position(pos), kind(k) {}
8993514Smike
9093514Smike  const char *getStart() const {
9193514Smike    return Position;
9293514Smike  }
9393514Smike
9493514Smike  unsigned getLength() const {
9593514Smike    switch (kind) {
9693514Smike      default:
9793514Smike        return 1;
9893514Smike      case AsLongLong:
9993514Smike      case AsChar:
10093514Smike        return 2;
10193514Smike      case AsInt32:
10293514Smike      case AsInt64:
10393514Smike        return 3;
10493514Smike      case None:
10593514Smike        return 0;
10693514Smike    }
107104341Smike  }
10841927Sdt
10941927Sdt  Kind getKind() const { return kind; }
11041927Sdt  void setKind(Kind k) { kind = k; }
11141927Sdt
112104341Smike  const char *toString() const;
113104341Smike
1141541Srgrimesprivate:
1151541Srgrimes  const char *Position;
1161541Srgrimes  Kind kind;
11751901Smarcel};
11851901Smarcel
119110051Smikeclass ConversionSpecifier {
120110051Smikepublic:
121110051Smike  enum Kind {
122110051Smike    InvalidSpecifier = 0,
123110051Smike      // C99 conversion specifiers.
124110051Smike    cArg,
125110051Smike    dArg,
126110051Smike    DArg, // Apple extension
127110051Smike    iArg,
128110051Smike    IntArgBeg = dArg, IntArgEnd = iArg,
129110051Smike
130102227Smike    oArg,
131104341Smike    OArg, // Apple extension
132110051Smike    uArg,
133112745Smike    UArg, // Apple extension
134112745Smike    xArg,
135112745Smike    XArg,
136112745Smike    UIntArgBeg = oArg, UIntArgEnd = XArg,
137112745Smike
138110051Smike    fArg,
139110051Smike    FArg,
140110051Smike    eArg,
141110051Smike    EArg,
142110051Smike    gArg,
143130434Sdas    GArg,
14491325Smike    aArg,
145110051Smike    AArg,
146110051Smike    DoubleArgBeg = fArg, DoubleArgEnd = AArg,
147110051Smike
148110051Smike    sArg,
149110051Smike    pArg,
150110051Smike    nArg,
151102227Smike    PercentArg,
152102227Smike    CArg,
153102227Smike    SArg,
15491325Smike
15591325Smike    // ** Printf-specific **
156105683Stjr
157105683Stjr    // Objective-C specific specifiers.
158105683Stjr    ObjCObjArg,  // '@'
159105683Stjr    ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg,
160105683Stjr
161105683Stjr    // FreeBSD specific specifiers
162105683Stjr    FreeBSDbArg,
163105683Stjr    FreeBSDDArg,
164105683Stjr    FreeBSDrArg,
165105683Stjr
166105650Smike    // GlibC specific specifiers.
167105650Smike    PrintErrno,   // 'm'
168105650Smike
169105650Smike    PrintfConvBeg = ObjCObjArg, PrintfConvEnd = PrintErrno,
170105650Smike
171111705Smike    // ** Scanf-specific **
172111705Smike    ScanListArg, // '['
173111705Smike    ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg
174111705Smike  };
175102325Smike
176105142Smike  ConversionSpecifier(bool isPrintf = true)
177105142Smike    : IsPrintf(isPrintf), Position(0), EndScanList(0), kind(InvalidSpecifier) {}
178105142Smike
179105142Smike  ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
180105142Smike    : IsPrintf(isPrintf), Position(pos), EndScanList(0), kind(k) {}
181130735Smarcel
182130735Smarcel  const char *getStart() const {
183130735Smarcel    return Position;
184130735Smarcel  }
185130735Smarcel
186102325Smike  StringRef getCharacters() const {
187102325Smike    return StringRef(getStart(), getLength());
188102325Smike  }
189102325Smike
190102325Smike  bool consumesDataArgument() const {
191111705Smike    switch (kind) {
192111705Smike      case PrintErrno:
193111705Smike        assert(IsPrintf);
194111705Smike        return false;
195102325Smike      case PercentArg:
196102325Smike        return false;
197102227Smike      default:
198102325Smike        return true;
199102325Smike    }
200102325Smike  }
201103457Smike
202102227Smike  Kind getKind() const { return kind; }
203103457Smike  void setKind(Kind k) { kind = k; }
204103457Smike  unsigned getLength() const {
205103457Smike    return EndScanList ? EndScanList - Position : 1;
206102227Smike  }
207105650Smike
208105650Smike  bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; }
209105650Smike  bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
210105650Smike  bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
211105650Smike  const char *toString() const;
212105650Smike
213102227Smike  bool isPrintfKind() const { return IsPrintf; }
214108190Smike
215110051Smike  Optional<ConversionSpecifier> getStandardSpecifier() const;
216110051Smike
217110051Smikeprotected:
218110051Smike  bool IsPrintf;
219110051Smike  const char *Position;
220110051Smike  const char *EndScanList;
221110051Smike  Kind kind;
222110051Smike};
223110051Smike
224110051Smikeclass ArgType {
225108190Smikepublic:
226108190Smike  enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
227108190Smike              AnyCharTy, CStrTy, WCStrTy, WIntTy };
228108190Smikeprivate:
229108190Smike  const Kind K;
230110051Smike  QualType T;
231110051Smike  const char *Name;
232110051Smike  bool Ptr;
233110051Smikepublic:
234110051Smike  ArgType(Kind k = UnknownTy, const char *n = 0) : K(k), Name(n), Ptr(false) {}
235110051Smike  ArgType(QualType t, const char *n = 0)
236110051Smike      : K(SpecificTy), T(t), Name(n), Ptr(false) {}
237110051Smike  ArgType(CanQualType t) : K(SpecificTy), T(t), Name(0), Ptr(false) {}
238110051Smike
239110051Smike  static ArgType Invalid() { return ArgType(InvalidTy); }
240102227Smike  bool isValid() const { return K != InvalidTy; }
24194363Smike
242102227Smike  /// Create an ArgType which corresponds to the type pointer to A.
243102227Smike  static ArgType PtrTo(const ArgType& A) {
244102227Smike    assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
24536735Sdfr    ArgType Res = A;
24694363Smike    Res.Ptr = true;
247108190Smike    return Res;
248108190Smike  }
249108190Smike
250108190Smike  bool matchesType(ASTContext &C, QualType argTy) const;
251108190Smike
252102227Smike  QualType getRepresentativeType(ASTContext &C) const;
253102227Smike
254112569Sjake  std::string getRepresentativeTypeName(ASTContext &C) const;
255102227Smike};
256102227Smike
2571541Srgrimesclass OptionalAmount {
25855205Speterpublic:
25915481Sbde  enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
260127239Smarcel
261102227Smike  OptionalAmount(HowSpecified howSpecified,
262102421Smike                 unsigned amount,
263102421Smike                 const char *amountStart,
264102421Smike                 unsigned amountLength,
265102421Smike                 bool usesPositionalArg)
266102421Smike  : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
267102421Smike  UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
268102421Smike
269102421Smike  OptionalAmount(bool valid = true)
270102421Smike  : start(0),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
271102421Smike  UsesPositionalArg(0), UsesDotPrefix(0) {}
272102421Smike
273102227Smike  bool isInvalid() const {
274104341Smike    return hs == Invalid;
27515481Sbde  }
27612642Sbde
27767708Sphk  HowSpecified getHowSpecified() const { return hs; }
27867708Sphk  void setHowSpecified(HowSpecified h) { hs = h; }
27955205Speter
28046818Sphk  bool hasDataArgument() const { return hs == Arg; }
2811541Srgrimes
282103867Smike  unsigned getArgIndex() const {
283103867Smike    assert(hasDataArgument());
2841541Srgrimes    return amt;
285103867Smike  }
2861541Srgrimes
287103867Smike  unsigned getConstantAmount() const {
2881541Srgrimes    assert(hs == Constant);
289104341Smike    return amt;
29024896Sbde  }
291104341Smike
292104341Smike  const char *getStart() const {
293104341Smike      // We include the . character if it is given.
294104341Smike    return start - UsesDotPrefix;
295104341Smike  }
296104341Smike
297104341Smike  unsigned getConstantLength() const {
298104341Smike    assert(hs == Constant);
299130640Sphk    return length + UsesDotPrefix;
300130640Sphk  }
301104341Smike
30224896Sbde  ArgType getArgType(ASTContext &Ctx) const;
30324896Sbde
30424896Sbde  void toString(raw_ostream &os) const;
30524896Sbde
30655205Speter  bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
30724896Sbde  unsigned getPositionalArgIndex() const {
30824896Sbde    assert(hasDataArgument());
30924896Sbde    return amt + 1;
31092719Salfred  }
31124896Sbde
31224896Sbde  bool usesDotPrefix() const { return UsesDotPrefix; }
31324896Sbde  void setUsesDotPrefix() { UsesDotPrefix = true; }
31492719Salfred
31524896Sbdeprivate:
31624896Sbde  const char *start;
31724896Sbde  unsigned length;
31892719Salfred  HowSpecified hs;
31924896Sbde  unsigned amt;
32024896Sbde  bool UsesPositionalArg : 1;
32124896Sbde  bool UsesDotPrefix;
32292719Salfred};
32324896Sbde
32424896Sbde
32555205Speterclass FormatSpecifier {
32624896Sbdeprotected:
32798271Swollman  LengthModifier LM;
3281541Srgrimes  OptionalAmount FieldWidth;
3291541Srgrimes  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;
335public:
336  FormatSpecifier(bool isPrintf)
337    : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {}
338
339  void setLengthModifier(LengthModifier lm) {
340    LM = lm;
341  }
342
343  void setUsesPositionalArg() { UsesPositionalArg = true; }
344
345  void setArgIndex(unsigned i) {
346    argIndex = i;
347  }
348
349  unsigned getArgIndex() const {
350    return argIndex;
351  }
352
353  unsigned getPositionalArgIndex() const {
354    return argIndex + 1;
355  }
356
357  const LengthModifier &getLengthModifier() const {
358    return LM;
359  }
360
361  const OptionalAmount &getFieldWidth() const {
362    return FieldWidth;
363  }
364
365  void setFieldWidth(const OptionalAmount &Amt) {
366    FieldWidth = Amt;
367  }
368
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
391namespace analyze_printf {
392
393class PrintfConversionSpecifier :
394  public analyze_format_string::ConversionSpecifier  {
395public:
396  PrintfConversionSpecifier()
397    : ConversionSpecifier(true, 0, InvalidSpecifier) {}
398
399  PrintfConversionSpecifier(const char *pos, Kind k)
400    : ConversionSpecifier(true, pos, k) {}
401
402  bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
403  bool isDoubleArg() const { return kind >= DoubleArgBeg &&
404                                    kind <= DoubleArgEnd; }
405  unsigned getLength() const {
406      // Conversion specifiers currently only are represented by
407      // single characters, but we be flexible.
408    return 1;
409  }
410
411  static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
412    return CS->isPrintfKind();
413  }
414};
415
416using analyze_format_string::ArgType;
417using analyze_format_string::LengthModifier;
418using analyze_format_string::OptionalAmount;
419using analyze_format_string::OptionalFlag;
420
421class 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;
429public:
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.
438  void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
439    CS = cs;
440  }
441  void setHasThousandsGrouping(const char *position) {
442    HasThousandsGrouping = true;
443    HasThousandsGrouping.setPosition(position);
444  }
445  void setIsLeftJustified(const char *position) {
446    IsLeftJustified = true;
447    IsLeftJustified.setPosition(position);
448  }
449  void setHasPlusPrefix(const char *position) {
450    HasPlusPrefix = true;
451    HasPlusPrefix.setPosition(position);
452  }
453  void setHasSpacePrefix(const char *position) {
454    HasSpacePrefix = true;
455    HasSpacePrefix.setPosition(position);
456  }
457  void setHasAlternativeForm(const char *position) {
458    HasAlternativeForm = true;
459    HasAlternativeForm.setPosition(position);
460  }
461  void setHasLeadingZeros(const char *position) {
462    HasLeadingZeroes = true;
463    HasLeadingZeroes.setPosition(position);
464  }
465  void setUsesPositionalArg() { UsesPositionalArg = true; }
466
467    // Methods for querying the format specifier.
468
469  const PrintfConversionSpecifier &getConversionSpecifier() const {
470    return cast<PrintfConversionSpecifier>(CS);
471  }
472
473  void setPrecision(const OptionalAmount &Amt) {
474    Precision = Amt;
475    Precision.setUsesDotPrefix();
476  }
477
478  const OptionalAmount &getPrecision() const {
479    return Precision;
480  }
481
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
493  const OptionalFlag &hasThousandsGrouping() const {
494      return HasThousandsGrouping;
495  }
496  const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
497  const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
498  const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
499  const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
500  const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
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
527namespace analyze_scanf {
528
529class ScanfConversionSpecifier :
530    public analyze_format_string::ConversionSpecifier  {
531public:
532  ScanfConversionSpecifier()
533    : ConversionSpecifier(false, 0, InvalidSpecifier) {}
534
535  ScanfConversionSpecifier(const char *pos, Kind k)
536    : ConversionSpecifier(false, pos, k) {}
537
538  void setEndScanList(const char *pos) { EndScanList = pos; }
539
540  static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
541    return !CS->isPrintfKind();
542  }
543};
544
545using analyze_format_string::ArgType;
546using analyze_format_string::LengthModifier;
547using analyze_format_string::OptionalAmount;
548using analyze_format_string::OptionalFlag;
549
550class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
551  OptionalFlag SuppressAssignment; // '*'
552public:
553  ScanfSpecifier() :
554    FormatSpecifier(/* isPrintf = */ false),
555    SuppressAssignment("*") {}
556
557  void setSuppressAssignment(const char *position) {
558    SuppressAssignment = true;
559    SuppressAssignment.setPosition(position);
560  }
561
562  const OptionalFlag &getSuppressAssignment() const {
563    return SuppressAssignment;
564  }
565
566  void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
567    CS = cs;
568  }
569
570  const ScanfConversionSpecifier &getConversionSpecifier() const {
571    return cast<ScanfConversionSpecifier>(CS);
572  }
573
574  bool consumesDataArgument() const {
575    return CS.consumesDataArgument() && !SuppressAssignment;
576  }
577
578  ArgType getArgType(ASTContext &Ctx) const;
579
580  bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx);
581
582  void toString(raw_ostream &os) const;
583
584  static ScanfSpecifier Parse(const char *beg, const char *end);
585};
586
587} // end analyze_scanf namespace
588
589//===----------------------------------------------------------------------===//
590// Parsing and processing of format strings (both fprintf and fscanf).
591
592namespace analyze_format_string {
593
594enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
595
596class FormatStringHandler {
597public:
598  FormatStringHandler() {}
599  virtual ~FormatStringHandler();
600
601  virtual void HandleNullChar(const char *nullCharacter) {}
602
603  virtual void HandlePosition(const char *startPos, unsigned posLen) {}
604
605  virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
606                                     PositionContext p) {}
607
608  virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
609
610  virtual void HandleIncompleteSpecifier(const char *startSpecifier,
611                                         unsigned specifierLen) {}
612
613  // Printf-specific handlers.
614
615  virtual bool HandleInvalidPrintfConversionSpecifier(
616                                      const analyze_printf::PrintfSpecifier &FS,
617                                      const char *startSpecifier,
618                                      unsigned specifierLen) {
619    return true;
620  }
621
622  virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
623                                     const char *startSpecifier,
624                                     unsigned specifierLen) {
625    return true;
626  }
627
628    // Scanf-specific handlers.
629
630  virtual bool HandleInvalidScanfConversionSpecifier(
631                                        const analyze_scanf::ScanfSpecifier &FS,
632                                        const char *startSpecifier,
633                                        unsigned specifierLen) {
634    return true;
635  }
636
637  virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
638                                    const char *startSpecifier,
639                                    unsigned specifierLen) {
640    return true;
641  }
642
643  virtual void HandleIncompleteScanList(const char *start, const char *end) {}
644};
645
646bool ParsePrintfString(FormatStringHandler &H,
647                       const char *beg, const char *end, const LangOptions &LO,
648                       const TargetInfo &Target);
649
650bool ParseScanfString(FormatStringHandler &H,
651                      const char *beg, const char *end, const LangOptions &LO,
652                      const TargetInfo &Target);
653
654} // end analyze_format_string namespace
655} // end clang namespace
656#endif
657