1//= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines APIs for analyzing the format strings of printf, fscanf,
10// and friends.
11//
12// The structure of format strings for fprintf are described in C99 7.19.6.1.
13//
14// The structure of format strings for fscanf are described in C99 7.19.6.2.
15//
16//===----------------------------------------------------------------------===//
17
18#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
19#define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
20
21#include "clang/AST/CanonicalType.h"
22
23namespace clang {
24
25class TargetInfo;
26
27//===----------------------------------------------------------------------===//
28/// Common components of both fprintf and fscanf format strings.
29namespace analyze_format_string {
30
31/// Class representing optional flags with location and representation
32/// information.
33class OptionalFlag {
34public:
35  OptionalFlag(const char *Representation)
36      : representation(Representation), flag(false) {}
37  bool isSet() const { return flag; }
38  void set() { flag = true; }
39  void clear() { flag = false; }
40  void setPosition(const char *position) {
41    assert(position);
42    flag = true;
43    this->position = position;
44  }
45  const char *getPosition() const {
46    assert(position);
47    return position;
48  }
49  const char *toString() const { return representation; }
50
51  // Overloaded operators for bool like qualities
52  explicit operator bool() const { return flag; }
53  OptionalFlag& operator=(const bool &rhs) {
54    flag = rhs;
55    return *this;  // Return a reference to myself.
56  }
57private:
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.
64class LengthModifier {
65public:
66  enum Kind {
67    None,
68    AsChar,       // 'hh'
69    AsShort,      // 'h'
70    AsShortLong,  // 'hl' (OpenCL float/int vector element)
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
87  LengthModifier()
88    : Position(nullptr), kind(None) {}
89  LengthModifier(const char *pos, Kind k)
90    : Position(pos), kind(k) {}
91
92  const char *getStart() const {
93    return Position;
94  }
95
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
111  Kind getKind() const { return kind; }
112  void setKind(Kind k) { kind = k; }
113
114  const char *toString() const;
115
116private:
117  const char *Position;
118  Kind kind;
119};
120
121class ConversionSpecifier {
122public:
123  enum Kind {
124    InvalidSpecifier = 0,
125    // C99 conversion specifiers.
126    cArg,
127    dArg,
128    DArg, // Apple extension
129    iArg,
130    IntArgBeg = dArg,
131    IntArgEnd = iArg,
132
133    oArg,
134    OArg, // Apple extension
135    uArg,
136    UArg, // Apple extension
137    xArg,
138    XArg,
139    UIntArgBeg = oArg,
140    UIntArgEnd = XArg,
141
142    fArg,
143    FArg,
144    eArg,
145    EArg,
146    gArg,
147    GArg,
148    aArg,
149    AArg,
150    DoubleArgBeg = fArg,
151    DoubleArgEnd = AArg,
152
153    sArg,
154    pArg,
155    nArg,
156    PercentArg,
157    CArg,
158    SArg,
159
160    // Apple extension: P specifies to os_log that the data being pointed to is
161    // to be copied by os_log. The precision indicates the number of bytes to
162    // copy.
163    PArg,
164
165    // ** Printf-specific **
166
167    ZArg, // MS extension
168
169    // Objective-C specific specifiers.
170    ObjCObjArg, // '@'
171    ObjCBeg = ObjCObjArg,
172    ObjCEnd = ObjCObjArg,
173
174    // FreeBSD kernel specific specifiers.
175    FreeBSDbArg,
176    FreeBSDDArg,
177    FreeBSDrArg,
178    FreeBSDyArg,
179
180    // GlibC specific specifiers.
181    PrintErrno, // 'm'
182
183    PrintfConvBeg = ObjCObjArg,
184    PrintfConvEnd = PrintErrno,
185
186    // ** Scanf-specific **
187    ScanListArg, // '['
188    ScanfConvBeg = ScanListArg,
189    ScanfConvEnd = ScanListArg
190  };
191
192  ConversionSpecifier(bool isPrintf = true)
193    : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
194      kind(InvalidSpecifier) {}
195
196  ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
197    : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
198
199  const char *getStart() const {
200    return Position;
201  }
202
203  StringRef getCharacters() const {
204    return StringRef(getStart(), getLength());
205  }
206
207  bool consumesDataArgument() const {
208    switch (kind) {
209      case PrintErrno:
210        assert(IsPrintf);
211        return false;
212      case PercentArg:
213        return false;
214      case InvalidSpecifier:
215        return false;
216      default:
217        return true;
218    }
219  }
220
221  Kind getKind() const { return kind; }
222  void setKind(Kind k) { kind = k; }
223  unsigned getLength() const {
224    return EndScanList ? EndScanList - Position : 1;
225  }
226  void setEndScanList(const char *pos) { EndScanList = pos; }
227
228  bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
229    kind == FreeBSDrArg || kind == FreeBSDyArg; }
230  bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
231  bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
232  bool isDoubleArg() const {
233    return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
234  }
235
236  const char *toString() const;
237
238  bool isPrintfKind() const { return IsPrintf; }
239
240  Optional<ConversionSpecifier> getStandardSpecifier() const;
241
242protected:
243  bool IsPrintf;
244  const char *Position;
245  const char *EndScanList;
246  Kind kind;
247};
248
249class ArgType {
250public:
251  enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
252              AnyCharTy, CStrTy, WCStrTy, WIntTy };
253
254  /// How well a given conversion specifier matches its argument.
255  enum MatchKind {
256    /// The conversion specifier and the argument types are incompatible. For
257    /// instance, "%d" and float.
258    NoMatch = 0,
259    /// The conversion specifier and the argument type are compatible. For
260    /// instance, "%d" and _Bool.
261    Match = 1,
262    /// The conversion specifier and the argument type are disallowed by the C
263    /// standard, but are in practice harmless. For instance, "%p" and int*.
264    NoMatchPedantic,
265    /// The conversion specifier and the argument type are compatible, but still
266    /// seems likely to be an error. For instance, "%hd" and _Bool.
267    NoMatchTypeConfusion,
268  };
269
270private:
271  const Kind K;
272  QualType T;
273  const char *Name = nullptr;
274  bool Ptr = false;
275
276  /// The TypeKind identifies certain well-known types like size_t and
277  /// ptrdiff_t.
278  enum class TypeKind { DontCare, SizeT, PtrdiffT };
279  TypeKind TK = TypeKind::DontCare;
280
281public:
282  ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
283  ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}
284  ArgType(CanQualType T) : K(SpecificTy), T(T) {}
285
286  static ArgType Invalid() { return ArgType(InvalidTy); }
287  bool isValid() const { return K != InvalidTy; }
288
289  bool isSizeT() const { return TK == TypeKind::SizeT; }
290
291  bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }
292
293  /// Create an ArgType which corresponds to the type pointer to A.
294  static ArgType PtrTo(const ArgType& A) {
295    assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
296    ArgType Res = A;
297    Res.Ptr = true;
298    return Res;
299  }
300
301  /// Create an ArgType which corresponds to the size_t/ssize_t type.
302  static ArgType makeSizeT(const ArgType &A) {
303    ArgType Res = A;
304    Res.TK = TypeKind::SizeT;
305    return Res;
306  }
307
308  /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t
309  /// type.
310  static ArgType makePtrdiffT(const ArgType &A) {
311    ArgType Res = A;
312    Res.TK = TypeKind::PtrdiffT;
313    return Res;
314  }
315
316  MatchKind matchesType(ASTContext &C, QualType argTy) const;
317
318  QualType getRepresentativeType(ASTContext &C) const;
319
320  ArgType makeVectorType(ASTContext &C, unsigned NumElts) const;
321
322  std::string getRepresentativeTypeName(ASTContext &C) const;
323};
324
325class OptionalAmount {
326public:
327  enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
328
329  OptionalAmount(HowSpecified howSpecified,
330                 unsigned amount,
331                 const char *amountStart,
332                 unsigned amountLength,
333                 bool usesPositionalArg)
334  : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
335  UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
336
337  OptionalAmount(bool valid = true)
338  : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
339  UsesPositionalArg(0), UsesDotPrefix(0) {}
340
341  explicit OptionalAmount(unsigned Amount)
342    : start(nullptr), length(0), hs(Constant), amt(Amount),
343    UsesPositionalArg(false), UsesDotPrefix(false) {}
344
345  bool isInvalid() const {
346    return hs == Invalid;
347  }
348
349  HowSpecified getHowSpecified() const { return hs; }
350  void setHowSpecified(HowSpecified h) { hs = h; }
351
352  bool hasDataArgument() const { return hs == Arg; }
353
354  unsigned getArgIndex() const {
355    assert(hasDataArgument());
356    return amt;
357  }
358
359  unsigned getConstantAmount() const {
360    assert(hs == Constant);
361    return amt;
362  }
363
364  const char *getStart() const {
365      // We include the . character if it is given.
366    return start - UsesDotPrefix;
367  }
368
369  unsigned getConstantLength() const {
370    assert(hs == Constant);
371    return length + UsesDotPrefix;
372  }
373
374  ArgType getArgType(ASTContext &Ctx) const;
375
376  void toString(raw_ostream &os) const;
377
378  bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
379  unsigned getPositionalArgIndex() const {
380    assert(hasDataArgument());
381    return amt + 1;
382  }
383
384  bool usesDotPrefix() const { return UsesDotPrefix; }
385  void setUsesDotPrefix() { UsesDotPrefix = true; }
386
387private:
388  const char *start;
389  unsigned length;
390  HowSpecified hs;
391  unsigned amt;
392  bool UsesPositionalArg : 1;
393  bool UsesDotPrefix;
394};
395
396
397class FormatSpecifier {
398protected:
399  LengthModifier LM;
400  OptionalAmount FieldWidth;
401  ConversionSpecifier CS;
402  OptionalAmount VectorNumElts;
403
404  /// Positional arguments, an IEEE extension:
405  ///  IEEE Std 1003.1, 2004 Edition
406  ///  http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
407  bool UsesPositionalArg;
408  unsigned argIndex;
409public:
410  FormatSpecifier(bool isPrintf)
411    : CS(isPrintf), VectorNumElts(false),
412      UsesPositionalArg(false), argIndex(0) {}
413
414  void setLengthModifier(LengthModifier lm) {
415    LM = lm;
416  }
417
418  void setUsesPositionalArg() { UsesPositionalArg = true; }
419
420  void setArgIndex(unsigned i) {
421    argIndex = i;
422  }
423
424  unsigned getArgIndex() const {
425    return argIndex;
426  }
427
428  unsigned getPositionalArgIndex() const {
429    return argIndex + 1;
430  }
431
432  const LengthModifier &getLengthModifier() const {
433    return LM;
434  }
435
436  const OptionalAmount &getFieldWidth() const {
437    return FieldWidth;
438  }
439
440  void setVectorNumElts(const OptionalAmount &Amt) {
441    VectorNumElts = Amt;
442  }
443
444  const OptionalAmount &getVectorNumElts() const {
445    return VectorNumElts;
446  }
447
448  void setFieldWidth(const OptionalAmount &Amt) {
449    FieldWidth = Amt;
450  }
451
452  bool usesPositionalArg() const { return UsesPositionalArg; }
453
454  bool hasValidLengthModifier(const TargetInfo &Target,
455                              const LangOptions &LO) const;
456
457  bool hasStandardLengthModifier() const;
458
459  Optional<LengthModifier> getCorrectedLengthModifier() const;
460
461  bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
462
463  bool hasStandardLengthConversionCombination() const;
464
465  /// For a TypedefType QT, if it is a named integer type such as size_t,
466  /// assign the appropriate value to LM and return true.
467  static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
468};
469
470} // end analyze_format_string namespace
471
472//===----------------------------------------------------------------------===//
473/// Pieces specific to fprintf format strings.
474
475namespace analyze_printf {
476
477class PrintfConversionSpecifier :
478  public analyze_format_string::ConversionSpecifier  {
479public:
480  PrintfConversionSpecifier()
481    : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
482
483  PrintfConversionSpecifier(const char *pos, Kind k)
484    : ConversionSpecifier(true, pos, k) {}
485
486  bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
487  bool isDoubleArg() const { return kind >= DoubleArgBeg &&
488                                    kind <= DoubleArgEnd; }
489
490  static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
491    return CS->isPrintfKind();
492  }
493};
494
495using analyze_format_string::ArgType;
496using analyze_format_string::LengthModifier;
497using analyze_format_string::OptionalAmount;
498using analyze_format_string::OptionalFlag;
499
500class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
501  OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
502  OptionalFlag IsLeftJustified; // '-'
503  OptionalFlag HasPlusPrefix; // '+'
504  OptionalFlag HasSpacePrefix; // ' '
505  OptionalFlag HasAlternativeForm; // '#'
506  OptionalFlag HasLeadingZeroes; // '0'
507  OptionalFlag HasObjCTechnicalTerm; // '[tt]'
508  OptionalFlag IsPrivate;            // '{private}'
509  OptionalFlag IsPublic;             // '{public}'
510  OptionalFlag IsSensitive;          // '{sensitive}'
511  OptionalAmount Precision;
512  StringRef MaskType;
513
514  ArgType getScalarArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
515
516public:
517  PrintfSpecifier()
518      : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
519        IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
520        HasAlternativeForm("#"), HasLeadingZeroes("0"),
521        HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public"),
522        IsSensitive("sensitive") {}
523
524  static PrintfSpecifier Parse(const char *beg, const char *end);
525
526    // Methods for incrementally constructing the PrintfSpecifier.
527  void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
528    CS = cs;
529  }
530  void setHasThousandsGrouping(const char *position) {
531    HasThousandsGrouping.setPosition(position);
532  }
533  void setIsLeftJustified(const char *position) {
534    IsLeftJustified.setPosition(position);
535  }
536  void setHasPlusPrefix(const char *position) {
537    HasPlusPrefix.setPosition(position);
538  }
539  void setHasSpacePrefix(const char *position) {
540    HasSpacePrefix.setPosition(position);
541  }
542  void setHasAlternativeForm(const char *position) {
543    HasAlternativeForm.setPosition(position);
544  }
545  void setHasLeadingZeros(const char *position) {
546    HasLeadingZeroes.setPosition(position);
547  }
548  void setHasObjCTechnicalTerm(const char *position) {
549    HasObjCTechnicalTerm.setPosition(position);
550  }
551  void setIsPrivate(const char *position) { IsPrivate.setPosition(position); }
552  void setIsPublic(const char *position) { IsPublic.setPosition(position); }
553  void setIsSensitive(const char *position) {
554    IsSensitive.setPosition(position);
555  }
556  void setUsesPositionalArg() { UsesPositionalArg = true; }
557
558    // Methods for querying the format specifier.
559
560  const PrintfConversionSpecifier &getConversionSpecifier() const {
561    return cast<PrintfConversionSpecifier>(CS);
562  }
563
564  void setPrecision(const OptionalAmount &Amt) {
565    Precision = Amt;
566    Precision.setUsesDotPrefix();
567  }
568
569  const OptionalAmount &getPrecision() const {
570    return Precision;
571  }
572
573  bool consumesDataArgument() const {
574    return getConversionSpecifier().consumesDataArgument();
575  }
576
577  /// Returns the builtin type that a data argument
578  /// paired with this format specifier should have.  This method
579  /// will return null if the format specifier does not have
580  /// a matching data argument or the matching argument matches
581  /// more than one type.
582  ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
583
584  const OptionalFlag &hasThousandsGrouping() const {
585      return HasThousandsGrouping;
586  }
587  const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
588  const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
589  const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
590  const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
591  const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
592  const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }
593  const OptionalFlag &isPrivate() const { return IsPrivate; }
594  const OptionalFlag &isPublic() const { return IsPublic; }
595  const OptionalFlag &isSensitive() const { return IsSensitive; }
596  bool usesPositionalArg() const { return UsesPositionalArg; }
597
598  StringRef getMaskType() const { return MaskType; }
599  void setMaskType(StringRef S) { MaskType = S; }
600
601  /// Changes the specifier and length according to a QualType, retaining any
602  /// flags or options. Returns true on success, or false when a conversion
603  /// was not successful.
604  bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
605               bool IsObjCLiteral);
606
607  void toString(raw_ostream &os) const;
608
609  // Validation methods - to check if any element results in undefined behavior
610  bool hasValidPlusPrefix() const;
611  bool hasValidAlternativeForm() const;
612  bool hasValidLeadingZeros() const;
613  bool hasValidSpacePrefix() const;
614  bool hasValidLeftJustified() const;
615  bool hasValidThousandsGroupingPrefix() const;
616
617  bool hasValidPrecision() const;
618  bool hasValidFieldWidth() const;
619};
620}  // end analyze_printf namespace
621
622//===----------------------------------------------------------------------===//
623/// Pieces specific to fscanf format strings.
624
625namespace analyze_scanf {
626
627class ScanfConversionSpecifier :
628    public analyze_format_string::ConversionSpecifier  {
629public:
630  ScanfConversionSpecifier()
631    : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
632
633  ScanfConversionSpecifier(const char *pos, Kind k)
634    : ConversionSpecifier(false, pos, k) {}
635
636  static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
637    return !CS->isPrintfKind();
638  }
639};
640
641using analyze_format_string::ArgType;
642using analyze_format_string::LengthModifier;
643using analyze_format_string::OptionalAmount;
644using analyze_format_string::OptionalFlag;
645
646class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
647  OptionalFlag SuppressAssignment; // '*'
648public:
649  ScanfSpecifier() :
650    FormatSpecifier(/* isPrintf = */ false),
651    SuppressAssignment("*") {}
652
653  void setSuppressAssignment(const char *position) {
654    SuppressAssignment.setPosition(position);
655  }
656
657  const OptionalFlag &getSuppressAssignment() const {
658    return SuppressAssignment;
659  }
660
661  void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
662    CS = cs;
663  }
664
665  const ScanfConversionSpecifier &getConversionSpecifier() const {
666    return cast<ScanfConversionSpecifier>(CS);
667  }
668
669  bool consumesDataArgument() const {
670    return CS.consumesDataArgument() && !SuppressAssignment;
671  }
672
673  ArgType getArgType(ASTContext &Ctx) const;
674
675  bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
676               ASTContext &Ctx);
677
678  void toString(raw_ostream &os) const;
679
680  static ScanfSpecifier Parse(const char *beg, const char *end);
681};
682
683} // end analyze_scanf namespace
684
685//===----------------------------------------------------------------------===//
686// Parsing and processing of format strings (both fprintf and fscanf).
687
688namespace analyze_format_string {
689
690enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
691
692class FormatStringHandler {
693public:
694  FormatStringHandler() {}
695  virtual ~FormatStringHandler();
696
697  virtual void HandleNullChar(const char *nullCharacter) {}
698
699  virtual void HandlePosition(const char *startPos, unsigned posLen) {}
700
701  virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
702                                     PositionContext p) {}
703
704  virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
705
706  virtual void HandleIncompleteSpecifier(const char *startSpecifier,
707                                         unsigned specifierLen) {}
708
709  virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
710                                           unsigned flagsLen) {}
711
712  virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
713                                             unsigned flagLen) {}
714
715  virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
716                                            const char *flagsEnd,
717                                            const char *conversionPosition) {}
718  // Printf-specific handlers.
719
720  virtual bool HandleInvalidPrintfConversionSpecifier(
721                                      const analyze_printf::PrintfSpecifier &FS,
722                                      const char *startSpecifier,
723                                      unsigned specifierLen) {
724    return true;
725  }
726
727  virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
728                                     const char *startSpecifier,
729                                     unsigned specifierLen) {
730    return true;
731  }
732
733  /// Handle mask types whose sizes are not between one and eight bytes.
734  virtual void handleInvalidMaskType(StringRef MaskType) {}
735
736    // Scanf-specific handlers.
737
738  virtual bool HandleInvalidScanfConversionSpecifier(
739                                        const analyze_scanf::ScanfSpecifier &FS,
740                                        const char *startSpecifier,
741                                        unsigned specifierLen) {
742    return true;
743  }
744
745  virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
746                                    const char *startSpecifier,
747                                    unsigned specifierLen) {
748    return true;
749  }
750
751  virtual void HandleIncompleteScanList(const char *start, const char *end) {}
752};
753
754bool ParsePrintfString(FormatStringHandler &H,
755                       const char *beg, const char *end, const LangOptions &LO,
756                       const TargetInfo &Target, bool isFreeBSDKPrintf);
757
758bool ParseFormatStringHasSArg(const char *beg, const char *end,
759                              const LangOptions &LO, const TargetInfo &Target);
760
761bool ParseScanfString(FormatStringHandler &H,
762                      const char *beg, const char *end, const LangOptions &LO,
763                      const TargetInfo &Target);
764
765/// Return true if the given string has at least one formatting specifier.
766bool parseFormatStringHasFormattingSpecifiers(const char *Begin,
767                                              const char *End,
768                                              const LangOptions &LO,
769                                              const TargetInfo &Target);
770
771} // end analyze_format_string namespace
772} // end clang namespace
773#endif
774