]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/include/clang/Analysis/Analyses/FormatString.h
Merge ACPICA 20101013.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / include / clang / Analysis / Analyses / FormatString.h
1 //= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines APIs for analyzing the format strings of printf, fscanf,
11 // and friends.
12 //
13 // The structure of format strings for fprintf are described in C99 7.19.6.1.
14 //
15 // The structure of format strings for fscanf are described in C99 7.19.6.2.
16 //
17 //===----------------------------------------------------------------------===//
18
19 #ifndef LLVM_CLANG_FORMAT_H
20 #define LLVM_CLANG_FORMAT_H
21
22 #include "clang/AST/CanonicalType.h"
23
24 namespace clang {
25
26 //===----------------------------------------------------------------------===//
27 /// Common components of both fprintf and fscanf format strings.
28 namespace analyze_format_string {
29
30 /// Class representing optional flags with location and representation
31 /// information.
32 class OptionalFlag {
33 public:
34   OptionalFlag(const char *Representation)
35       : representation(Representation), flag(false) {}
36   bool isSet() { return flag; }
37   void set() { flag = true; }
38   void clear() { flag = false; }
39   void setPosition(const char *position) {
40     assert(position);
41     this->position = position;
42   }
43   const char *getPosition() const {
44     assert(position);
45     return position;
46   }
47   const char *toString() const { return representation; }
48
49   // Overloaded operators for bool like qualities
50   operator bool() const { return flag; }
51   OptionalFlag& operator=(const bool &rhs) {
52     flag = rhs;
53     return *this;  // Return a reference to myself.
54   }
55 private:
56   const char *representation;
57   const char *position;
58   bool flag;
59 };
60
61 /// Represents the length modifier in a format string in scanf/printf.
62 class LengthModifier {
63 public:
64   enum Kind {
65     None,
66     AsChar,       // 'hh'
67     AsShort,      // 'h'
68     AsLong,       // 'l'
69     AsLongLong,   // 'll', 'q' (BSD, deprecated)
70     AsIntMax,     // 'j'
71     AsSizeT,      // 'z'
72     AsPtrDiff,    // 't'
73     AsLongDouble, // 'L'
74     AsWideChar = AsLong // for '%ls', only makes sense for printf
75   };
76
77   LengthModifier()
78     : Position(0), kind(None) {}
79   LengthModifier(const char *pos, Kind k)
80     : Position(pos), kind(k) {}
81
82   const char *getStart() const {
83     return Position;
84   }
85
86   unsigned getLength() const {
87     switch (kind) {
88       default:
89         return 1;
90       case AsLongLong:
91       case AsChar:
92         return 2;
93       case None:
94         return 0;
95     }
96   }
97
98   Kind getKind() const { return kind; }
99   void setKind(Kind k) { kind = k; }
100
101   const char *toString() const;
102
103 private:
104   const char *Position;
105   Kind kind;
106 };
107   
108 class ConversionSpecifier {
109 public:
110   enum Kind {
111     InvalidSpecifier = 0,
112       // C99 conversion specifiers.
113     cArg,
114     dArg,
115     iArg,
116     IntArgBeg = cArg, IntArgEnd = iArg,    
117     
118     oArg,
119     uArg,
120     xArg,
121     XArg,
122     UIntArgBeg = oArg, UIntArgEnd = XArg,
123     
124     fArg,
125     FArg,
126     eArg,
127     EArg,
128     gArg,
129     GArg,
130     aArg,
131     AArg,
132     DoubleArgBeg = fArg, DoubleArgEnd = AArg,
133     
134     sArg,
135     pArg,
136     nArg,
137     PercentArg,
138     CArg,
139     SArg,
140     
141     // ** Printf-specific **
142   
143     // Objective-C specific specifiers.
144     ObjCObjArg,  // '@'
145     ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg,
146     
147     // FreeBSD specific specifiers
148     bArg,
149     DArg,
150     rArg,
151     
152     // GlibC specific specifiers.
153     PrintErrno,   // 'm'
154     
155     PrintfConvBeg = ObjCObjArg, PrintfConvEnd = PrintErrno,
156     
157     // ** Scanf-specific **    
158     ScanListArg, // '['
159     ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg
160   };
161   
162   ConversionSpecifier(bool isPrintf)
163     : IsPrintf(isPrintf), Position(0), EndScanList(0), kind(InvalidSpecifier) {}
164   
165   ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
166     : IsPrintf(isPrintf), Position(pos), EndScanList(0), kind(k) {}
167   
168   const char *getStart() const {
169     return Position;
170   }
171   
172   llvm::StringRef getCharacters() const {
173     return llvm::StringRef(getStart(), getLength());
174   }
175   
176   bool consumesDataArgument() const {
177     switch (kind) {
178       case PrintErrno:
179         assert(IsPrintf);
180       case PercentArg:
181         return false;
182       default:
183         return true;
184     }
185   }
186   
187   Kind getKind() const { return kind; }
188   void setKind(Kind k) { kind = k; }
189   unsigned getLength() const {
190     return EndScanList ? EndScanList - Position : 1;
191   }
192   
193   const char *toString() const;
194   
195   bool isPrintfKind() const { return IsPrintf; }
196
197 protected:
198   bool IsPrintf;
199   const char *Position;
200   const char *EndScanList;
201   Kind kind;
202 };
203
204 class ArgTypeResult {
205 public:
206   enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
207     CStrTy, WCStrTy, WIntTy };
208 private:
209   const Kind K;
210   QualType T;
211   ArgTypeResult(bool) : K(InvalidTy) {}
212 public:
213   ArgTypeResult(Kind k = UnknownTy) : K(k) {}
214   ArgTypeResult(QualType t) : K(SpecificTy), T(t) {}
215   ArgTypeResult(CanQualType t) : K(SpecificTy), T(t) {}
216
217   static ArgTypeResult Invalid() { return ArgTypeResult(true); }
218
219   bool isValid() const { return K != InvalidTy; }
220
221   const QualType *getSpecificType() const {
222     return K == SpecificTy ? &T : 0;
223   }
224
225   bool matchesType(ASTContext &C, QualType argTy) const;
226
227   bool matchesAnyObjCObjectRef() const { return K == ObjCPointerTy; }
228
229   QualType getRepresentativeType(ASTContext &C) const;
230 };
231
232 class OptionalAmount {
233 public:
234   enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
235
236   OptionalAmount(HowSpecified howSpecified,
237                  unsigned amount,
238                  const char *amountStart,
239                  unsigned amountLength,
240                  bool usesPositionalArg)
241   : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
242   UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
243
244   OptionalAmount(bool valid = true)
245   : start(0),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
246   UsesPositionalArg(0), UsesDotPrefix(0) {}
247
248   bool isInvalid() const {
249     return hs == Invalid;
250   }
251
252   HowSpecified getHowSpecified() const { return hs; }
253   void setHowSpecified(HowSpecified h) { hs = h; }
254
255   bool hasDataArgument() const { return hs == Arg; }
256
257   unsigned getArgIndex() const {
258     assert(hasDataArgument());
259     return amt;
260   }
261
262   unsigned getConstantAmount() const {
263     assert(hs == Constant);
264     return amt;
265   }
266
267   const char *getStart() const {
268       // We include the . character if it is given.
269     return start - UsesDotPrefix;
270   }
271
272   unsigned getConstantLength() const {
273     assert(hs == Constant);
274     return length + UsesDotPrefix;
275   }
276
277   ArgTypeResult getArgType(ASTContext &Ctx) const;
278
279   void toString(llvm::raw_ostream &os) const;
280
281   bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
282   unsigned getPositionalArgIndex() const {
283     assert(hasDataArgument());
284     return amt + 1;
285   }
286
287   bool usesDotPrefix() const { return UsesDotPrefix; }
288   void setUsesDotPrefix() { UsesDotPrefix = true; }
289
290 private:
291   const char *start;
292   unsigned length;
293   HowSpecified hs;
294   unsigned amt;
295   bool UsesPositionalArg : 1;
296   bool UsesDotPrefix;
297 };
298
299
300 class FormatSpecifier {
301 protected:
302   LengthModifier LM;
303   OptionalAmount FieldWidth;
304   ConversionSpecifier CS;
305     /// Positional arguments, an IEEE extension:
306     ///  IEEE Std 1003.1, 2004 Edition
307     ///  http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
308   bool UsesPositionalArg;
309   unsigned argIndex;
310 public:
311   FormatSpecifier(bool isPrintf)
312     : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {}
313
314   void setLengthModifier(LengthModifier lm) {
315     LM = lm;
316   }
317
318   void setUsesPositionalArg() { UsesPositionalArg = true; }
319
320   void setArgIndex(unsigned i) {
321     argIndex = i;
322   }
323
324   unsigned getArgIndex() const {
325     return argIndex;
326   }
327
328   unsigned getPositionalArgIndex() const {
329     return argIndex + 1;
330   }
331
332   const LengthModifier &getLengthModifier() const {
333     return LM;
334   }
335
336   const OptionalAmount &getFieldWidth() const {
337     return FieldWidth;
338   }
339
340   void setFieldWidth(const OptionalAmount &Amt) {
341     FieldWidth = Amt;
342   }
343
344   bool usesPositionalArg() const { return UsesPositionalArg; }
345   
346   bool hasValidLengthModifier() const;
347 };
348
349 } // end analyze_format_string namespace
350
351 //===----------------------------------------------------------------------===//
352 /// Pieces specific to fprintf format strings.
353
354 namespace analyze_printf {
355
356 class PrintfConversionSpecifier : 
357   public analyze_format_string::ConversionSpecifier  {
358 public:
359   PrintfConversionSpecifier()
360     : ConversionSpecifier(true, 0, InvalidSpecifier) {}
361
362   PrintfConversionSpecifier(const char *pos, Kind k)
363     : ConversionSpecifier(true, pos, k) {}
364
365   bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
366   bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; }
367   bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
368   bool isDoubleArg() const { return kind >= DoubleArgBeg && 
369                                     kind <= DoubleArgBeg; }
370   unsigned getLength() const {
371       // Conversion specifiers currently only are represented by
372       // single characters, but we be flexible.
373     return 1;
374   }
375
376   static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
377     return CS->isPrintfKind();
378   }
379 };
380
381 using analyze_format_string::ArgTypeResult;
382 using analyze_format_string::LengthModifier;
383 using analyze_format_string::OptionalAmount;
384 using analyze_format_string::OptionalFlag;
385
386 class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
387   OptionalFlag IsLeftJustified; // '-'
388   OptionalFlag HasPlusPrefix; // '+'
389   OptionalFlag HasSpacePrefix; // ' '
390   OptionalFlag HasAlternativeForm; // '#'
391   OptionalFlag HasLeadingZeroes; // '0'
392   OptionalAmount Precision;
393 public:
394   PrintfSpecifier() :
395     FormatSpecifier(/* isPrintf = */ true),
396     IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
397     HasAlternativeForm("#"), HasLeadingZeroes("0") {}
398
399   static PrintfSpecifier Parse(const char *beg, const char *end);
400
401     // Methods for incrementally constructing the PrintfSpecifier.
402   void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
403     CS = cs;
404   }
405   void setIsLeftJustified(const char *position) {
406     IsLeftJustified = true;
407     IsLeftJustified.setPosition(position);
408   }
409   void setHasPlusPrefix(const char *position) {
410     HasPlusPrefix = true;
411     HasPlusPrefix.setPosition(position);
412   }
413   void setHasSpacePrefix(const char *position) {
414     HasSpacePrefix = true;
415     HasSpacePrefix.setPosition(position);
416   }
417   void setHasAlternativeForm(const char *position) {
418     HasAlternativeForm = true;
419     HasAlternativeForm.setPosition(position);
420   }
421   void setHasLeadingZeros(const char *position) {
422     HasLeadingZeroes = true;
423     HasLeadingZeroes.setPosition(position);
424   }
425   void setUsesPositionalArg() { UsesPositionalArg = true; }
426
427     // Methods for querying the format specifier.
428
429   const PrintfConversionSpecifier &getConversionSpecifier() const {
430     return cast<PrintfConversionSpecifier>(CS);
431   }
432
433   void setPrecision(const OptionalAmount &Amt) {
434     Precision = Amt;
435     Precision.setUsesDotPrefix();
436   }
437
438   const OptionalAmount &getPrecision() const {
439     return Precision;
440   }
441   
442   bool consumesDataArgument() const {
443     return getConversionSpecifier().consumesDataArgument();
444   }
445
446   /// \brief Returns the builtin type that a data argument
447   /// paired with this format specifier should have.  This method
448   /// will return null if the format specifier does not have
449   /// a matching data argument or the matching argument matches
450   /// more than one type.
451   ArgTypeResult getArgType(ASTContext &Ctx) const;
452
453   const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
454   const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
455   const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
456   const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
457   const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
458   bool usesPositionalArg() const { return UsesPositionalArg; }
459
460     /// Changes the specifier and length according to a QualType, retaining any
461     /// flags or options. Returns true on success, or false when a conversion
462     /// was not successful.
463   bool fixType(QualType QT);
464
465   void toString(llvm::raw_ostream &os) const;
466
467     // Validation methods - to check if any element results in undefined behavior
468   bool hasValidPlusPrefix() const;
469   bool hasValidAlternativeForm() const;
470   bool hasValidLeadingZeros() const;
471   bool hasValidSpacePrefix() const;
472   bool hasValidLeftJustified() const;
473
474   bool hasValidPrecision() const;
475   bool hasValidFieldWidth() const;
476 };
477 }  // end analyze_printf namespace
478
479 //===----------------------------------------------------------------------===//
480 /// Pieces specific to fscanf format strings.
481
482 namespace analyze_scanf {
483
484 class ScanfConversionSpecifier :
485     public analyze_format_string::ConversionSpecifier  {
486 public:
487   ScanfConversionSpecifier()
488     : ConversionSpecifier(false, 0, InvalidSpecifier) {}
489
490   ScanfConversionSpecifier(const char *pos, Kind k)
491     : ConversionSpecifier(false, pos, k) {}
492
493   void setEndScanList(const char *pos) { EndScanList = pos; }
494       
495   static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
496     return !CS->isPrintfKind();
497   }      
498 };
499
500 using analyze_format_string::LengthModifier;
501 using analyze_format_string::OptionalAmount;
502 using analyze_format_string::OptionalFlag;
503
504 class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
505   OptionalFlag SuppressAssignment; // '*'
506 public:
507   ScanfSpecifier() :
508     FormatSpecifier(/* isPrintf = */ false),
509     SuppressAssignment("*") {}
510
511   void setSuppressAssignment(const char *position) {
512     SuppressAssignment = true;
513     SuppressAssignment.setPosition(position);
514   }
515
516   const OptionalFlag &getSuppressAssignment() const {
517     return SuppressAssignment;
518   }
519
520   void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
521     CS = cs;
522   }
523
524   const ScanfConversionSpecifier &getConversionSpecifier() const {
525     return cast<ScanfConversionSpecifier>(CS);
526   }
527   
528   bool consumesDataArgument() const {
529     return CS.consumesDataArgument() && !SuppressAssignment;
530   }
531
532   static ScanfSpecifier Parse(const char *beg, const char *end);
533 };
534
535 } // end analyze_scanf namespace
536
537 //===----------------------------------------------------------------------===//
538 // Parsing and processing of format strings (both fprintf and fscanf).
539
540 namespace analyze_format_string {
541
542 enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
543
544 class FormatStringHandler {
545 public:
546   FormatStringHandler() {}
547   virtual ~FormatStringHandler();
548
549   virtual void HandleNullChar(const char *nullCharacter) {}
550
551   virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
552                                      PositionContext p) {}
553
554   virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
555
556   virtual void HandleIncompleteSpecifier(const char *startSpecifier,
557                                          unsigned specifierLen) {}
558
559   // Printf-specific handlers.
560
561   virtual bool HandleInvalidPrintfConversionSpecifier(
562                                       const analyze_printf::PrintfSpecifier &FS,
563                                       const char *startSpecifier,
564                                       unsigned specifierLen) {
565     return true;
566   }
567
568   virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
569                                      const char *startSpecifier,
570                                      unsigned specifierLen) {
571     return true;
572   }
573
574     // Scanf-specific handlers.
575
576   virtual bool HandleInvalidScanfConversionSpecifier(
577                                         const analyze_scanf::ScanfSpecifier &FS,
578                                         const char *startSpecifier,
579                                         unsigned specifierLen) {
580     return true;
581   }
582
583   virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
584                                     const char *startSpecifier,
585                                     unsigned specifierLen) {
586     return true;
587   }
588
589   virtual void HandleIncompleteScanList(const char *start, const char *end) {}
590 };
591
592 bool ParsePrintfString(FormatStringHandler &H,
593                        const char *beg, const char *end,
594                        bool FormatExtensions);
595
596 bool ParseScanfString(FormatStringHandler &H,
597                        const char *beg, const char *end);
598
599 } // end analyze_format_string namespace
600 } // end clang namespace
601 #endif