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