1212795Sdim//= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===//
2212795Sdim//
3212795Sdim//                     The LLVM Compiler Infrastructure
4212795Sdim//
5212795Sdim// This file is distributed under the University of Illinois Open Source
6212795Sdim// License. See LICENSE.TXT for details.
7212795Sdim//
8212795Sdim//===----------------------------------------------------------------------===//
9212795Sdim//
10212795Sdim// This file defines APIs for analyzing the format strings of printf, fscanf,
11212795Sdim// and friends.
12212795Sdim//
13212795Sdim// The structure of format strings for fprintf are described in C99 7.19.6.1.
14212795Sdim//
15212795Sdim// The structure of format strings for fscanf are described in C99 7.19.6.2.
16212795Sdim//
17212795Sdim//===----------------------------------------------------------------------===//
18212795Sdim
19212795Sdim#ifndef LLVM_CLANG_FORMAT_H
20212795Sdim#define LLVM_CLANG_FORMAT_H
21212795Sdim
22212795Sdim#include "clang/AST/CanonicalType.h"
23212795Sdim
24212795Sdimnamespace clang {
25212795Sdim
26245431Sdimclass TargetInfo;
27245431Sdim
28212795Sdim//===----------------------------------------------------------------------===//
29212795Sdim/// Common components of both fprintf and fscanf format strings.
30212795Sdimnamespace analyze_format_string {
31212795Sdim
32212795Sdim/// Class representing optional flags with location and representation
33212795Sdim/// information.
34212795Sdimclass OptionalFlag {
35212795Sdimpublic:
36212795Sdim  OptionalFlag(const char *Representation)
37212795Sdim      : representation(Representation), flag(false) {}
38212795Sdim  bool isSet() { return flag; }
39212795Sdim  void set() { flag = true; }
40212795Sdim  void clear() { flag = false; }
41212795Sdim  void setPosition(const char *position) {
42212795Sdim    assert(position);
43212795Sdim    this->position = position;
44212795Sdim  }
45212795Sdim  const char *getPosition() const {
46212795Sdim    assert(position);
47212795Sdim    return position;
48212795Sdim  }
49212795Sdim  const char *toString() const { return representation; }
50212795Sdim
51212795Sdim  // Overloaded operators for bool like qualities
52263509Sdim  LLVM_EXPLICIT operator bool() const { return flag; }
53212795Sdim  OptionalFlag& operator=(const bool &rhs) {
54212795Sdim    flag = rhs;
55212795Sdim    return *this;  // Return a reference to myself.
56212795Sdim  }
57212795Sdimprivate:
58212795Sdim  const char *representation;
59212795Sdim  const char *position;
60212795Sdim  bool flag;
61212795Sdim};
62212795Sdim
63212795Sdim/// Represents the length modifier in a format string in scanf/printf.
64212795Sdimclass LengthModifier {
65212795Sdimpublic:
66212795Sdim  enum Kind {
67212795Sdim    None,
68212795Sdim    AsChar,       // 'hh'
69212795Sdim    AsShort,      // 'h'
70212795Sdim    AsLong,       // 'l'
71235633Sdim    AsLongLong,   // 'll'
72235633Sdim    AsQuad,       // 'q' (BSD, deprecated, for 64-bit integer types)
73212795Sdim    AsIntMax,     // 'j'
74212795Sdim    AsSizeT,      // 'z'
75212795Sdim    AsPtrDiff,    // 't'
76263509Sdim    AsInt32,      // 'I32' (MSVCRT, like __int32)
77263509Sdim    AsInt3264,    // 'I'   (MSVCRT, like __int3264 from MIDL)
78263509Sdim    AsInt64,      // 'I64' (MSVCRT, like __int64)
79212795Sdim    AsLongDouble, // 'L'
80235633Sdim    AsAllocate,   // for '%as', GNU extension to C90 scanf
81235633Sdim    AsMAllocate,  // for '%ms', GNU extension to scanf
82212795Sdim    AsWideChar = AsLong // for '%ls', only makes sense for printf
83212795Sdim  };
84212795Sdim
85212795Sdim  LengthModifier()
86212795Sdim    : Position(0), kind(None) {}
87212795Sdim  LengthModifier(const char *pos, Kind k)
88212795Sdim    : Position(pos), kind(k) {}
89212795Sdim
90212795Sdim  const char *getStart() const {
91212795Sdim    return Position;
92212795Sdim  }
93212795Sdim
94212795Sdim  unsigned getLength() const {
95212795Sdim    switch (kind) {
96212795Sdim      default:
97212795Sdim        return 1;
98212795Sdim      case AsLongLong:
99212795Sdim      case AsChar:
100212795Sdim        return 2;
101263509Sdim      case AsInt32:
102263509Sdim      case AsInt64:
103263509Sdim        return 3;
104212795Sdim      case None:
105212795Sdim        return 0;
106212795Sdim    }
107212795Sdim  }
108212795Sdim
109212795Sdim  Kind getKind() const { return kind; }
110212795Sdim  void setKind(Kind k) { kind = k; }
111212795Sdim
112212795Sdim  const char *toString() const;
113212795Sdim
114212795Sdimprivate:
115212795Sdim  const char *Position;
116212795Sdim  Kind kind;
117212795Sdim};
118235633Sdim
119212795Sdimclass ConversionSpecifier {
120212795Sdimpublic:
121212795Sdim  enum Kind {
122212795Sdim    InvalidSpecifier = 0,
123212795Sdim      // C99 conversion specifiers.
124212795Sdim    cArg,
125212795Sdim    dArg,
126245431Sdim    DArg, // Apple extension
127212795Sdim    iArg,
128245431Sdim    IntArgBeg = dArg, IntArgEnd = iArg,
129235633Sdim
130212795Sdim    oArg,
131245431Sdim    OArg, // Apple extension
132212795Sdim    uArg,
133245431Sdim    UArg, // Apple extension
134212795Sdim    xArg,
135212795Sdim    XArg,
136212795Sdim    UIntArgBeg = oArg, UIntArgEnd = XArg,
137235633Sdim
138212795Sdim    fArg,
139212795Sdim    FArg,
140212795Sdim    eArg,
141212795Sdim    EArg,
142212795Sdim    gArg,
143212795Sdim    GArg,
144212795Sdim    aArg,
145212795Sdim    AArg,
146212795Sdim    DoubleArgBeg = fArg, DoubleArgEnd = AArg,
147235633Sdim
148212795Sdim    sArg,
149212795Sdim    pArg,
150212795Sdim    nArg,
151212795Sdim    PercentArg,
152212795Sdim    CArg,
153212795Sdim    SArg,
154235633Sdim
155212795Sdim    // ** Printf-specific **
156235633Sdim
157212795Sdim    // Objective-C specific specifiers.
158212795Sdim    ObjCObjArg,  // '@'
159212795Sdim    ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg,
160235633Sdim
161212904Sdim    // FreeBSD specific specifiers
162245431Sdim    FreeBSDbArg,
163245431Sdim    FreeBSDDArg,
164245431Sdim    FreeBSDrArg,
165235633Sdim
166212795Sdim    // GlibC specific specifiers.
167212795Sdim    PrintErrno,   // 'm'
168235633Sdim
169212795Sdim    PrintfConvBeg = ObjCObjArg, PrintfConvEnd = PrintErrno,
170235633Sdim
171235633Sdim    // ** Scanf-specific **
172212795Sdim    ScanListArg, // '['
173212795Sdim    ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg
174212795Sdim  };
175235633Sdim
176245431Sdim  ConversionSpecifier(bool isPrintf = true)
177212795Sdim    : IsPrintf(isPrintf), Position(0), EndScanList(0), kind(InvalidSpecifier) {}
178235633Sdim
179212795Sdim  ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
180212795Sdim    : IsPrintf(isPrintf), Position(pos), EndScanList(0), kind(k) {}
181235633Sdim
182212795Sdim  const char *getStart() const {
183212795Sdim    return Position;
184212795Sdim  }
185235633Sdim
186226890Sdim  StringRef getCharacters() const {
187226890Sdim    return StringRef(getStart(), getLength());
188212795Sdim  }
189235633Sdim
190212795Sdim  bool consumesDataArgument() const {
191212795Sdim    switch (kind) {
192212795Sdim      case PrintErrno:
193212795Sdim        assert(IsPrintf);
194245431Sdim        return false;
195212795Sdim      case PercentArg:
196212795Sdim        return false;
197212795Sdim      default:
198212795Sdim        return true;
199212795Sdim    }
200212795Sdim  }
201235633Sdim
202212795Sdim  Kind getKind() const { return kind; }
203212795Sdim  void setKind(Kind k) { kind = k; }
204212795Sdim  unsigned getLength() const {
205212795Sdim    return EndScanList ? EndScanList - Position : 1;
206212795Sdim  }
207235633Sdim
208245431Sdim  bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; }
209235633Sdim  bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
210245431Sdim  bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
211212795Sdim  const char *toString() const;
212235633Sdim
213212795Sdim  bool isPrintfKind() const { return IsPrintf; }
214245431Sdim
215252723Sdim  Optional<ConversionSpecifier> getStandardSpecifier() const;
216212795Sdim
217212795Sdimprotected:
218212795Sdim  bool IsPrintf;
219212795Sdim  const char *Position;
220212795Sdim  const char *EndScanList;
221212795Sdim  Kind kind;
222212795Sdim};
223212795Sdim
224245431Sdimclass ArgType {
225212795Sdimpublic:
226212795Sdim  enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
227235633Sdim              AnyCharTy, CStrTy, WCStrTy, WIntTy };
228212795Sdimprivate:
229212795Sdim  const Kind K;
230212795Sdim  QualType T;
231235633Sdim  const char *Name;
232245431Sdim  bool Ptr;
233212795Sdimpublic:
234245431Sdim  ArgType(Kind k = UnknownTy, const char *n = 0) : K(k), Name(n), Ptr(false) {}
235245431Sdim  ArgType(QualType t, const char *n = 0)
236245431Sdim      : K(SpecificTy), T(t), Name(n), Ptr(false) {}
237245431Sdim  ArgType(CanQualType t) : K(SpecificTy), T(t), Name(0), Ptr(false) {}
238212795Sdim
239245431Sdim  static ArgType Invalid() { return ArgType(InvalidTy); }
240212795Sdim  bool isValid() const { return K != InvalidTy; }
241212795Sdim
242245431Sdim  /// Create an ArgType which corresponds to the type pointer to A.
243245431Sdim  static ArgType PtrTo(const ArgType& A) {
244245431Sdim    assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
245245431Sdim    ArgType Res = A;
246245431Sdim    Res.Ptr = true;
247245431Sdim    return Res;
248212795Sdim  }
249212795Sdim
250212795Sdim  bool matchesType(ASTContext &C, QualType argTy) const;
251212795Sdim
252212795Sdim  QualType getRepresentativeType(ASTContext &C) const;
253235633Sdim
254235633Sdim  std::string getRepresentativeTypeName(ASTContext &C) const;
255212795Sdim};
256212795Sdim
257212795Sdimclass OptionalAmount {
258212795Sdimpublic:
259212795Sdim  enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
260212795Sdim
261212795Sdim  OptionalAmount(HowSpecified howSpecified,
262212795Sdim                 unsigned amount,
263212795Sdim                 const char *amountStart,
264212795Sdim                 unsigned amountLength,
265212795Sdim                 bool usesPositionalArg)
266212795Sdim  : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
267212795Sdim  UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
268212795Sdim
269212795Sdim  OptionalAmount(bool valid = true)
270212795Sdim  : start(0),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
271212795Sdim  UsesPositionalArg(0), UsesDotPrefix(0) {}
272212795Sdim
273212795Sdim  bool isInvalid() const {
274212795Sdim    return hs == Invalid;
275212795Sdim  }
276212795Sdim
277212795Sdim  HowSpecified getHowSpecified() const { return hs; }
278212795Sdim  void setHowSpecified(HowSpecified h) { hs = h; }
279212795Sdim
280212795Sdim  bool hasDataArgument() const { return hs == Arg; }
281212795Sdim
282212795Sdim  unsigned getArgIndex() const {
283212795Sdim    assert(hasDataArgument());
284212795Sdim    return amt;
285212795Sdim  }
286212795Sdim
287212795Sdim  unsigned getConstantAmount() const {
288212795Sdim    assert(hs == Constant);
289212795Sdim    return amt;
290212795Sdim  }
291212795Sdim
292212795Sdim  const char *getStart() const {
293212795Sdim      // We include the . character if it is given.
294212795Sdim    return start - UsesDotPrefix;
295212795Sdim  }
296212795Sdim
297212795Sdim  unsigned getConstantLength() const {
298212795Sdim    assert(hs == Constant);
299212795Sdim    return length + UsesDotPrefix;
300212795Sdim  }
301212795Sdim
302245431Sdim  ArgType getArgType(ASTContext &Ctx) const;
303212795Sdim
304226890Sdim  void toString(raw_ostream &os) const;
305212795Sdim
306212795Sdim  bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
307212795Sdim  unsigned getPositionalArgIndex() const {
308212795Sdim    assert(hasDataArgument());
309212795Sdim    return amt + 1;
310212795Sdim  }
311212795Sdim
312212795Sdim  bool usesDotPrefix() const { return UsesDotPrefix; }
313212795Sdim  void setUsesDotPrefix() { UsesDotPrefix = true; }
314212795Sdim
315212795Sdimprivate:
316212795Sdim  const char *start;
317212795Sdim  unsigned length;
318212795Sdim  HowSpecified hs;
319212795Sdim  unsigned amt;
320212795Sdim  bool UsesPositionalArg : 1;
321212795Sdim  bool UsesDotPrefix;
322212795Sdim};
323212795Sdim
324212795Sdim
325212795Sdimclass FormatSpecifier {
326212795Sdimprotected:
327212795Sdim  LengthModifier LM;
328212795Sdim  OptionalAmount FieldWidth;
329212795Sdim  ConversionSpecifier CS;
330235633Sdim  /// Positional arguments, an IEEE extension:
331235633Sdim  ///  IEEE Std 1003.1, 2004 Edition
332235633Sdim  ///  http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
333212795Sdim  bool UsesPositionalArg;
334212795Sdim  unsigned argIndex;
335212795Sdimpublic:
336212795Sdim  FormatSpecifier(bool isPrintf)
337212795Sdim    : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {}
338212795Sdim
339212795Sdim  void setLengthModifier(LengthModifier lm) {
340212795Sdim    LM = lm;
341212795Sdim  }
342212795Sdim
343212795Sdim  void setUsesPositionalArg() { UsesPositionalArg = true; }
344212795Sdim
345212795Sdim  void setArgIndex(unsigned i) {
346212795Sdim    argIndex = i;
347212795Sdim  }
348212795Sdim
349212795Sdim  unsigned getArgIndex() const {
350212795Sdim    return argIndex;
351212795Sdim  }
352212795Sdim
353212795Sdim  unsigned getPositionalArgIndex() const {
354212795Sdim    return argIndex + 1;
355212795Sdim  }
356212795Sdim
357212795Sdim  const LengthModifier &getLengthModifier() const {
358212795Sdim    return LM;
359212795Sdim  }
360212795Sdim
361212795Sdim  const OptionalAmount &getFieldWidth() const {
362212795Sdim    return FieldWidth;
363212795Sdim  }
364212795Sdim
365212795Sdim  void setFieldWidth(const OptionalAmount &Amt) {
366212795Sdim    FieldWidth = Amt;
367212795Sdim  }
368212795Sdim
369212795Sdim  bool usesPositionalArg() const { return UsesPositionalArg; }
370235633Sdim
371245431Sdim  bool hasValidLengthModifier(const TargetInfo &Target) const;
372235633Sdim
373235633Sdim  bool hasStandardLengthModifier() const;
374235633Sdim
375252723Sdim  Optional<LengthModifier> getCorrectedLengthModifier() const;
376245431Sdim
377235633Sdim  bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
378235633Sdim
379235633Sdim  bool hasStandardLengthConversionCombination() const;
380245431Sdim
381245431Sdim  /// For a TypedefType QT, if it is a named integer type such as size_t,
382245431Sdim  /// assign the appropriate value to LM and return true.
383245431Sdim  static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
384212795Sdim};
385212795Sdim
386212795Sdim} // end analyze_format_string namespace
387212795Sdim
388212795Sdim//===----------------------------------------------------------------------===//
389212795Sdim/// Pieces specific to fprintf format strings.
390212795Sdim
391212795Sdimnamespace analyze_printf {
392212795Sdim
393235633Sdimclass PrintfConversionSpecifier :
394212795Sdim  public analyze_format_string::ConversionSpecifier  {
395212795Sdimpublic:
396212795Sdim  PrintfConversionSpecifier()
397212795Sdim    : ConversionSpecifier(true, 0, InvalidSpecifier) {}
398212795Sdim
399212795Sdim  PrintfConversionSpecifier(const char *pos, Kind k)
400212795Sdim    : ConversionSpecifier(true, pos, k) {}
401212795Sdim
402212795Sdim  bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
403235633Sdim  bool isDoubleArg() const { return kind >= DoubleArgBeg &&
404235633Sdim                                    kind <= DoubleArgEnd; }
405212795Sdim  unsigned getLength() const {
406212795Sdim      // Conversion specifiers currently only are represented by
407212795Sdim      // single characters, but we be flexible.
408212795Sdim    return 1;
409212795Sdim  }
410212795Sdim
411212795Sdim  static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
412212795Sdim    return CS->isPrintfKind();
413212795Sdim  }
414212795Sdim};
415212795Sdim
416245431Sdimusing analyze_format_string::ArgType;
417212795Sdimusing analyze_format_string::LengthModifier;
418212795Sdimusing analyze_format_string::OptionalAmount;
419212795Sdimusing analyze_format_string::OptionalFlag;
420212795Sdim
421212795Sdimclass PrintfSpecifier : public analyze_format_string::FormatSpecifier {
422218893Sdim  OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
423212795Sdim  OptionalFlag IsLeftJustified; // '-'
424212795Sdim  OptionalFlag HasPlusPrefix; // '+'
425212795Sdim  OptionalFlag HasSpacePrefix; // ' '
426212795Sdim  OptionalFlag HasAlternativeForm; // '#'
427212795Sdim  OptionalFlag HasLeadingZeroes; // '0'
428212795Sdim  OptionalAmount Precision;
429212795Sdimpublic:
430212795Sdim  PrintfSpecifier() :
431212795Sdim    FormatSpecifier(/* isPrintf = */ true),
432218893Sdim    HasThousandsGrouping("'"), IsLeftJustified("-"), HasPlusPrefix("+"),
433218893Sdim    HasSpacePrefix(" "), HasAlternativeForm("#"), HasLeadingZeroes("0") {}
434212795Sdim
435212795Sdim  static PrintfSpecifier Parse(const char *beg, const char *end);
436212795Sdim
437212795Sdim    // Methods for incrementally constructing the PrintfSpecifier.
438212795Sdim  void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
439212795Sdim    CS = cs;
440212795Sdim  }
441218893Sdim  void setHasThousandsGrouping(const char *position) {
442218893Sdim    HasThousandsGrouping = true;
443218893Sdim    HasThousandsGrouping.setPosition(position);
444218893Sdim  }
445212795Sdim  void setIsLeftJustified(const char *position) {
446212795Sdim    IsLeftJustified = true;
447212795Sdim    IsLeftJustified.setPosition(position);
448212795Sdim  }
449212795Sdim  void setHasPlusPrefix(const char *position) {
450212795Sdim    HasPlusPrefix = true;
451212795Sdim    HasPlusPrefix.setPosition(position);
452212795Sdim  }
453212795Sdim  void setHasSpacePrefix(const char *position) {
454212795Sdim    HasSpacePrefix = true;
455212795Sdim    HasSpacePrefix.setPosition(position);
456212795Sdim  }
457212795Sdim  void setHasAlternativeForm(const char *position) {
458212795Sdim    HasAlternativeForm = true;
459212795Sdim    HasAlternativeForm.setPosition(position);
460212795Sdim  }
461212795Sdim  void setHasLeadingZeros(const char *position) {
462212795Sdim    HasLeadingZeroes = true;
463212795Sdim    HasLeadingZeroes.setPosition(position);
464212795Sdim  }
465212795Sdim  void setUsesPositionalArg() { UsesPositionalArg = true; }
466212795Sdim
467212795Sdim    // Methods for querying the format specifier.
468212795Sdim
469212795Sdim  const PrintfConversionSpecifier &getConversionSpecifier() const {
470212795Sdim    return cast<PrintfConversionSpecifier>(CS);
471212795Sdim  }
472212795Sdim
473212795Sdim  void setPrecision(const OptionalAmount &Amt) {
474212795Sdim    Precision = Amt;
475212795Sdim    Precision.setUsesDotPrefix();
476212795Sdim  }
477212795Sdim
478212795Sdim  const OptionalAmount &getPrecision() const {
479212795Sdim    return Precision;
480212795Sdim  }
481235633Sdim
482212795Sdim  bool consumesDataArgument() const {
483212795Sdim    return getConversionSpecifier().consumesDataArgument();
484212795Sdim  }
485212795Sdim
486212795Sdim  /// \brief Returns the builtin type that a data argument
487212795Sdim  /// paired with this format specifier should have.  This method
488212795Sdim  /// will return null if the format specifier does not have
489212795Sdim  /// a matching data argument or the matching argument matches
490212795Sdim  /// more than one type.
491245431Sdim  ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
492212795Sdim
493235633Sdim  const OptionalFlag &hasThousandsGrouping() const {
494218893Sdim      return HasThousandsGrouping;
495218893Sdim  }
496212795Sdim  const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
497212795Sdim  const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
498212795Sdim  const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
499212795Sdim  const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
500212795Sdim  const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
501212795Sdim  bool usesPositionalArg() const { return UsesPositionalArg; }
502212795Sdim
503235633Sdim  /// Changes the specifier and length according to a QualType, retaining any
504235633Sdim  /// flags or options. Returns true on success, or false when a conversion
505235633Sdim  /// was not successful.
506235633Sdim  bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
507235633Sdim               bool IsObjCLiteral);
508212795Sdim
509226890Sdim  void toString(raw_ostream &os) const;
510212795Sdim
511235633Sdim  // Validation methods - to check if any element results in undefined behavior
512212795Sdim  bool hasValidPlusPrefix() const;
513212795Sdim  bool hasValidAlternativeForm() const;
514212795Sdim  bool hasValidLeadingZeros() const;
515212795Sdim  bool hasValidSpacePrefix() const;
516212795Sdim  bool hasValidLeftJustified() const;
517218893Sdim  bool hasValidThousandsGroupingPrefix() const;
518212795Sdim
519212795Sdim  bool hasValidPrecision() const;
520212795Sdim  bool hasValidFieldWidth() const;
521212795Sdim};
522212795Sdim}  // end analyze_printf namespace
523212795Sdim
524212795Sdim//===----------------------------------------------------------------------===//
525212795Sdim/// Pieces specific to fscanf format strings.
526212795Sdim
527212795Sdimnamespace analyze_scanf {
528212795Sdim
529212795Sdimclass ScanfConversionSpecifier :
530212795Sdim    public analyze_format_string::ConversionSpecifier  {
531212795Sdimpublic:
532212795Sdim  ScanfConversionSpecifier()
533212795Sdim    : ConversionSpecifier(false, 0, InvalidSpecifier) {}
534212795Sdim
535212795Sdim  ScanfConversionSpecifier(const char *pos, Kind k)
536212795Sdim    : ConversionSpecifier(false, pos, k) {}
537212795Sdim
538212795Sdim  void setEndScanList(const char *pos) { EndScanList = pos; }
539235633Sdim
540212795Sdim  static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
541212795Sdim    return !CS->isPrintfKind();
542235633Sdim  }
543212795Sdim};
544212795Sdim
545245431Sdimusing analyze_format_string::ArgType;
546212795Sdimusing analyze_format_string::LengthModifier;
547212795Sdimusing analyze_format_string::OptionalAmount;
548212795Sdimusing analyze_format_string::OptionalFlag;
549212795Sdim
550212795Sdimclass ScanfSpecifier : public analyze_format_string::FormatSpecifier {
551212795Sdim  OptionalFlag SuppressAssignment; // '*'
552212795Sdimpublic:
553212795Sdim  ScanfSpecifier() :
554212795Sdim    FormatSpecifier(/* isPrintf = */ false),
555212795Sdim    SuppressAssignment("*") {}
556212795Sdim
557212795Sdim  void setSuppressAssignment(const char *position) {
558212795Sdim    SuppressAssignment = true;
559212795Sdim    SuppressAssignment.setPosition(position);
560212795Sdim  }
561212795Sdim
562212795Sdim  const OptionalFlag &getSuppressAssignment() const {
563212795Sdim    return SuppressAssignment;
564212795Sdim  }
565212795Sdim
566212795Sdim  void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
567212795Sdim    CS = cs;
568212795Sdim  }
569212795Sdim
570212795Sdim  const ScanfConversionSpecifier &getConversionSpecifier() const {
571212795Sdim    return cast<ScanfConversionSpecifier>(CS);
572212795Sdim  }
573235633Sdim
574212795Sdim  bool consumesDataArgument() const {
575212795Sdim    return CS.consumesDataArgument() && !SuppressAssignment;
576212795Sdim  }
577212795Sdim
578245431Sdim  ArgType getArgType(ASTContext &Ctx) const;
579235633Sdim
580235633Sdim  bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx);
581235633Sdim
582235633Sdim  void toString(raw_ostream &os) const;
583235633Sdim
584212795Sdim  static ScanfSpecifier Parse(const char *beg, const char *end);
585212795Sdim};
586212795Sdim
587212795Sdim} // end analyze_scanf namespace
588212795Sdim
589212795Sdim//===----------------------------------------------------------------------===//
590212795Sdim// Parsing and processing of format strings (both fprintf and fscanf).
591212795Sdim
592212795Sdimnamespace analyze_format_string {
593212795Sdim
594212795Sdimenum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
595212795Sdim
596212795Sdimclass FormatStringHandler {
597212795Sdimpublic:
598212795Sdim  FormatStringHandler() {}
599212795Sdim  virtual ~FormatStringHandler();
600212795Sdim
601212795Sdim  virtual void HandleNullChar(const char *nullCharacter) {}
602212795Sdim
603235633Sdim  virtual void HandlePosition(const char *startPos, unsigned posLen) {}
604235633Sdim
605212795Sdim  virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
606212795Sdim                                     PositionContext p) {}
607212795Sdim
608212795Sdim  virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
609212795Sdim
610212795Sdim  virtual void HandleIncompleteSpecifier(const char *startSpecifier,
611212795Sdim                                         unsigned specifierLen) {}
612212795Sdim
613212795Sdim  // Printf-specific handlers.
614212795Sdim
615212795Sdim  virtual bool HandleInvalidPrintfConversionSpecifier(
616212795Sdim                                      const analyze_printf::PrintfSpecifier &FS,
617212795Sdim                                      const char *startSpecifier,
618212795Sdim                                      unsigned specifierLen) {
619212795Sdim    return true;
620212795Sdim  }
621212795Sdim
622212795Sdim  virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
623212795Sdim                                     const char *startSpecifier,
624212795Sdim                                     unsigned specifierLen) {
625212795Sdim    return true;
626212795Sdim  }
627212795Sdim
628212795Sdim    // Scanf-specific handlers.
629212795Sdim
630212795Sdim  virtual bool HandleInvalidScanfConversionSpecifier(
631212795Sdim                                        const analyze_scanf::ScanfSpecifier &FS,
632212795Sdim                                        const char *startSpecifier,
633212795Sdim                                        unsigned specifierLen) {
634212795Sdim    return true;
635212795Sdim  }
636212795Sdim
637212795Sdim  virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
638212795Sdim                                    const char *startSpecifier,
639212795Sdim                                    unsigned specifierLen) {
640212795Sdim    return true;
641212795Sdim  }
642212795Sdim
643212795Sdim  virtual void HandleIncompleteScanList(const char *start, const char *end) {}
644212795Sdim};
645212795Sdim
646212795Sdimbool ParsePrintfString(FormatStringHandler &H,
647245431Sdim                       const char *beg, const char *end, const LangOptions &LO,
648245431Sdim                       const TargetInfo &Target);
649212795Sdim
650212795Sdimbool ParseScanfString(FormatStringHandler &H,
651245431Sdim                      const char *beg, const char *end, const LangOptions &LO,
652245431Sdim                      const TargetInfo &Target);
653212795Sdim
654212795Sdim} // end analyze_format_string namespace
655212795Sdim} // end clang namespace
656212795Sdim#endif
657