PrintfFormatString.cpp revision 876e994957472eda4b40136d4e1d6e08e2be338f
1//= PrintfFormatStrings.cpp - Analysis of printf 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// Handling of format string in printf and friends.  The structure of format
11// strings for fprintf() are described in C99 7.19.6.1.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/Analysis/Analyses/PrintfFormatString.h"
16#include "clang/AST/ASTContext.h"
17#include "clang/AST/Type.h"
18#include "llvm/Support/raw_ostream.h"
19
20using clang::analyze_printf::ArgTypeResult;
21using clang::analyze_printf::FormatSpecifier;
22using clang::analyze_printf::FormatStringHandler;
23using clang::analyze_printf::OptionalAmount;
24using clang::analyze_printf::PositionContext;
25using clang::analyze_printf::ConversionSpecifier;
26using clang::analyze_printf::LengthModifier;
27
28using namespace clang;
29
30namespace {
31class FormatSpecifierResult {
32  FormatSpecifier FS;
33  const char *Start;
34  bool Stop;
35public:
36  FormatSpecifierResult(bool stop = false)
37    : Start(0), Stop(stop) {}
38  FormatSpecifierResult(const char *start,
39                        const FormatSpecifier &fs)
40    : FS(fs), Start(start), Stop(false) {}
41
42
43  const char *getStart() const { return Start; }
44  bool shouldStop() const { return Stop; }
45  bool hasValue() const { return Start != 0; }
46  const FormatSpecifier &getValue() const {
47    assert(hasValue());
48    return FS;
49  }
50  const FormatSpecifier &getValue() { return FS; }
51};
52} // end anonymous namespace
53
54template <typename T>
55class UpdateOnReturn {
56  T &ValueToUpdate;
57  const T &ValueToCopy;
58public:
59  UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
60    : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
61
62  ~UpdateOnReturn() {
63    ValueToUpdate = ValueToCopy;
64  }
65};
66
67//===----------------------------------------------------------------------===//
68// Methods for parsing format strings.
69//===----------------------------------------------------------------------===//
70
71static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
72  const char *I = Beg;
73  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
74
75  unsigned accumulator = 0;
76  bool hasDigits = false;
77
78  for ( ; I != E; ++I) {
79    char c = *I;
80    if (c >= '0' && c <= '9') {
81      hasDigits = true;
82      accumulator = (accumulator * 10) + (c - '0');
83      continue;
84    }
85
86    if (hasDigits)
87      return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, 0);
88
89    break;
90  }
91
92  return OptionalAmount();
93}
94
95static OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
96                                             unsigned &argIndex) {
97  if (*Beg == '*') {
98    ++Beg;
99    return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0);
100  }
101
102  return ParseAmount(Beg, E);
103}
104
105static OptionalAmount ParsePositionAmount(FormatStringHandler &H,
106                                          const char *Start,
107                                          const char *&Beg, const char *E,
108                                          PositionContext p) {
109  if (*Beg == '*') {
110    const char *I = Beg + 1;
111    const OptionalAmount &Amt = ParseAmount(I, E);
112
113    if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
114      H.HandleInvalidPosition(Beg, I - Beg, p);
115      return OptionalAmount(false);
116    }
117
118    if (I== E) {
119      // No more characters left?
120      H.HandleIncompleteFormatSpecifier(Start, E - Start);
121      return OptionalAmount(false);
122    }
123
124    assert(Amt.getHowSpecified() == OptionalAmount::Constant);
125
126    if (*I == '$') {
127      // Handle positional arguments
128
129      // Special case: '*0$', since this is an easy mistake.
130      if (Amt.getConstantAmount() == 0) {
131        H.HandleZeroPosition(Beg, I - Beg + 1);
132        return OptionalAmount(false);
133      }
134
135      const char *Tmp = Beg;
136      Beg = ++I;
137
138      return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,
139                            Tmp, 1);
140    }
141
142    H.HandleInvalidPosition(Beg, I - Beg, p);
143    return OptionalAmount(false);
144  }
145
146  return ParseAmount(Beg, E);
147}
148
149static bool ParsePrecision(FormatStringHandler &H, FormatSpecifier &FS,
150                           const char *Start, const char *&Beg, const char *E,
151                           unsigned *argIndex) {
152  if (argIndex) {
153    FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
154  }
155  else {
156    const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
157                                                  analyze_printf::PrecisionPos);
158    if (Amt.isInvalid())
159      return true;
160    FS.setPrecision(Amt);
161  }
162  return false;
163}
164
165static bool ParseFieldWidth(FormatStringHandler &H, FormatSpecifier &FS,
166                            const char *Start, const char *&Beg, const char *E,
167                            unsigned *argIndex) {
168  // FIXME: Support negative field widths.
169  if (argIndex) {
170    FS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
171  }
172  else {
173    const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
174                                                 analyze_printf::FieldWidthPos);
175    if (Amt.isInvalid())
176      return true;
177    FS.setFieldWidth(Amt);
178  }
179  return false;
180}
181
182
183static bool ParseArgPosition(FormatStringHandler &H,
184                             FormatSpecifier &FS, const char *Start,
185                             const char *&Beg, const char *E) {
186
187  using namespace clang::analyze_printf;
188  const char *I = Beg;
189
190  const OptionalAmount &Amt = ParseAmount(I, E);
191
192  if (I == E) {
193    // No more characters left?
194    H.HandleIncompleteFormatSpecifier(Start, E - Start);
195    return true;
196  }
197
198  if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
199    // Special case: '%0$', since this is an easy mistake.
200    if (Amt.getConstantAmount() == 0) {
201      H.HandleZeroPosition(Start, I - Start);
202      return true;
203    }
204
205    FS.setArgIndex(Amt.getConstantAmount() - 1);
206    FS.setUsesPositionalArg();
207    // Update the caller's pointer if we decided to consume
208    // these characters.
209    Beg = I;
210    return false;
211  }
212
213  return false;
214}
215
216static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
217                                                  const char *&Beg,
218                                                  const char *E,
219                                                  unsigned &argIndex) {
220
221  using namespace clang::analyze_printf;
222
223  const char *I = Beg;
224  const char *Start = 0;
225  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
226
227  // Look for a '%' character that indicates the start of a format specifier.
228  for ( ; I != E ; ++I) {
229    char c = *I;
230    if (c == '\0') {
231      // Detect spurious null characters, which are likely errors.
232      H.HandleNullChar(I);
233      return true;
234    }
235    if (c == '%') {
236      Start = I++;  // Record the start of the format specifier.
237      break;
238    }
239  }
240
241  // No format specifier found?
242  if (!Start)
243    return false;
244
245  if (I == E) {
246    // No more characters left?
247    H.HandleIncompleteFormatSpecifier(Start, E - Start);
248    return true;
249  }
250
251  FormatSpecifier FS;
252  if (ParseArgPosition(H, FS, Start, I, E))
253    return true;
254
255  if (I == E) {
256    // No more characters left?
257    H.HandleIncompleteFormatSpecifier(Start, E - Start);
258    return true;
259  }
260
261  // Look for flags (if any).
262  bool hasMore = true;
263  for ( ; I != E; ++I) {
264    switch (*I) {
265      default: hasMore = false; break;
266      case '-': FS.setIsLeftJustified(); break;
267      case '+': FS.setHasPlusPrefix(); break;
268      case ' ': FS.setHasSpacePrefix(); break;
269      case '#': FS.setHasAlternativeForm(); break;
270      case '0': FS.setHasLeadingZeros(); break;
271    }
272    if (!hasMore)
273      break;
274  }
275
276  if (I == E) {
277    // No more characters left?
278    H.HandleIncompleteFormatSpecifier(Start, E - Start);
279    return true;
280  }
281
282  // Look for the field width (if any).
283  if (ParseFieldWidth(H, FS, Start, I, E,
284                      FS.usesPositionalArg() ? 0 : &argIndex))
285    return true;
286
287  if (I == E) {
288    // No more characters left?
289    H.HandleIncompleteFormatSpecifier(Start, E - Start);
290    return true;
291  }
292
293  // Look for the precision (if any).
294  if (*I == '.') {
295    ++I;
296    if (I == E) {
297      H.HandleIncompleteFormatSpecifier(Start, E - Start);
298      return true;
299    }
300
301    if (ParsePrecision(H, FS, Start, I, E,
302                       FS.usesPositionalArg() ? 0 : &argIndex))
303      return true;
304
305    if (I == E) {
306      // No more characters left?
307      H.HandleIncompleteFormatSpecifier(Start, E - Start);
308      return true;
309    }
310  }
311
312  // Look for the length modifier.
313  LengthModifier::Kind lmKind = LengthModifier::None;
314  const char *lmPosition = I;
315  switch (*I) {
316    default:
317      break;
318    case 'h':
319      ++I;
320      lmKind = (I != E && *I == 'h') ?
321          ++I, LengthModifier::AsChar : LengthModifier::AsShort;
322      break;
323    case 'l':
324      ++I;
325      lmKind = (I != E && *I == 'l') ?
326          ++I, LengthModifier::AsLongLong : LengthModifier::AsLong;
327      break;
328    case 'j': lmKind = LengthModifier::AsIntMax;     ++I; break;
329    case 'z': lmKind = LengthModifier::AsSizeT;      ++I; break;
330    case 't': lmKind = LengthModifier::AsPtrDiff;    ++I; break;
331    case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
332    case 'q': lmKind = LengthModifier::AsLongLong;   ++I; break;
333  }
334  LengthModifier lm(lmPosition, lmKind);
335  FS.setLengthModifier(lm);
336
337  if (I == E) {
338    // No more characters left?
339    H.HandleIncompleteFormatSpecifier(Start, E - Start);
340    return true;
341  }
342
343  if (*I == '\0') {
344    // Detect spurious null characters, which are likely errors.
345    H.HandleNullChar(I);
346    return true;
347  }
348
349  // Finally, look for the conversion specifier.
350  const char *conversionPosition = I++;
351  ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
352  switch (*conversionPosition) {
353    default:
354      break;
355    // C99: 7.19.6.1 (section 8).
356    case '%': k = ConversionSpecifier::PercentArg;   break;
357    case 'A': k = ConversionSpecifier::AArg; break;
358    case 'E': k = ConversionSpecifier::EArg; break;
359    case 'F': k = ConversionSpecifier::FArg; break;
360    case 'G': k = ConversionSpecifier::GArg; break;
361    case 'X': k = ConversionSpecifier::XArg; break;
362    case 'a': k = ConversionSpecifier::aArg; break;
363    case 'c': k = ConversionSpecifier::IntAsCharArg; break;
364    case 'd': k = ConversionSpecifier::dArg; break;
365    case 'e': k = ConversionSpecifier::eArg; break;
366    case 'f': k = ConversionSpecifier::fArg; break;
367    case 'g': k = ConversionSpecifier::gArg; break;
368    case 'i': k = ConversionSpecifier::iArg; break;
369    case 'n': k = ConversionSpecifier::OutIntPtrArg; break;
370    case 'o': k = ConversionSpecifier::oArg; break;
371    case 'p': k = ConversionSpecifier::VoidPtrArg;   break;
372    case 's': k = ConversionSpecifier::CStrArg;      break;
373    case 'u': k = ConversionSpecifier::uArg; break;
374    case 'x': k = ConversionSpecifier::xArg; break;
375    // Mac OS X (unicode) specific
376    case 'C': k = ConversionSpecifier::CArg; break;
377    case 'S': k = ConversionSpecifier::UnicodeStrArg; break;
378    // Objective-C.
379    case '@': k = ConversionSpecifier::ObjCObjArg; break;
380    // Glibc specific.
381    case 'm': k = ConversionSpecifier::PrintErrno; break;
382  }
383  ConversionSpecifier CS(conversionPosition, k);
384  FS.setConversionSpecifier(CS);
385  if (CS.consumesDataArgument() && !FS.usesPositionalArg())
386    FS.setArgIndex(argIndex++);
387
388  if (k == ConversionSpecifier::InvalidSpecifier) {
389    // Assume the conversion takes one argument.
390    return !H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg);
391  }
392  return FormatSpecifierResult(Start, FS);
393}
394
395bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H,
396                       const char *I, const char *E) {
397
398  unsigned argIndex = 0;
399
400  // Keep looking for a format specifier until we have exhausted the string.
401  while (I != E) {
402    const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E, argIndex);
403    // Did a fail-stop error of any kind occur when parsing the specifier?
404    // If so, don't do any more processing.
405    if (FSR.shouldStop())
406      return true;;
407    // Did we exhaust the string or encounter an error that
408    // we can recover from?
409    if (!FSR.hasValue())
410      continue;
411    // We have a format specifier.  Pass it to the callback.
412    if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(),
413                                 I - FSR.getStart()))
414      return true;
415  }
416  assert(I == E && "Format string not exhausted");
417  return false;
418}
419
420FormatStringHandler::~FormatStringHandler() {}
421
422//===----------------------------------------------------------------------===//
423// Methods on ArgTypeResult.
424//===----------------------------------------------------------------------===//
425
426bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
427  assert(isValid());
428
429  if (K == UnknownTy)
430    return true;
431
432  if (K == SpecificTy) {
433    argTy = C.getCanonicalType(argTy).getUnqualifiedType();
434
435    if (T == argTy)
436      return true;
437
438    if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
439      switch (BT->getKind()) {
440        default:
441          break;
442        case BuiltinType::Char_S:
443        case BuiltinType::SChar:
444          return T == C.UnsignedCharTy;
445        case BuiltinType::Char_U:
446        case BuiltinType::UChar:
447          return T == C.SignedCharTy;
448        case BuiltinType::Short:
449          return T == C.UnsignedShortTy;
450        case BuiltinType::UShort:
451          return T == C.ShortTy;
452        case BuiltinType::Int:
453          return T == C.UnsignedIntTy;
454        case BuiltinType::UInt:
455          return T == C.IntTy;
456        case BuiltinType::Long:
457          return T == C.UnsignedLongTy;
458        case BuiltinType::ULong:
459          return T == C.LongTy;
460        case BuiltinType::LongLong:
461          return T == C.UnsignedLongLongTy;
462        case BuiltinType::ULongLong:
463          return T == C.LongLongTy;
464      }
465
466    return false;
467  }
468
469  if (K == CStrTy) {
470    const PointerType *PT = argTy->getAs<PointerType>();
471    if (!PT)
472      return false;
473
474    QualType pointeeTy = PT->getPointeeType();
475
476    if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
477      switch (BT->getKind()) {
478        case BuiltinType::Void:
479        case BuiltinType::Char_U:
480        case BuiltinType::UChar:
481        case BuiltinType::Char_S:
482        case BuiltinType::SChar:
483          return true;
484        default:
485          break;
486      }
487
488    return false;
489  }
490
491  if (K == WCStrTy) {
492    const PointerType *PT = argTy->getAs<PointerType>();
493    if (!PT)
494      return false;
495
496    QualType pointeeTy =
497      C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
498
499    return pointeeTy == C.getWCharType();
500  }
501
502  return false;
503}
504
505QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
506  assert(isValid());
507  if (K == SpecificTy)
508    return T;
509  if (K == CStrTy)
510    return C.getPointerType(C.CharTy);
511  if (K == WCStrTy)
512    return C.getPointerType(C.getWCharType());
513  if (K == ObjCPointerTy)
514    return C.ObjCBuiltinIdTy;
515
516  return QualType();
517}
518
519//===----------------------------------------------------------------------===//
520// Methods on OptionalAmount.
521//===----------------------------------------------------------------------===//
522
523ArgTypeResult OptionalAmount::getArgType(ASTContext &Ctx) const {
524  return Ctx.IntTy;
525}
526
527//===----------------------------------------------------------------------===//
528// Methods on ConversionSpecifier.
529//===----------------------------------------------------------------------===//
530const char *ConversionSpecifier::toString() const {
531  switch (kind) {
532  case dArg: return "d";
533  case iArg: return "i";
534  case oArg: return "o";
535  case uArg: return "u";
536  case xArg: return "x";
537  case XArg: return "X";
538  case fArg: return "f";
539  case FArg: return "F";
540  case eArg: return "e";
541  case EArg: return "E";
542  case gArg: return "g";
543  case GArg: return "G";
544  case aArg: return "a";
545  case AArg: return "A";
546  case IntAsCharArg:     return "c";
547  case CStrArg:          return "s";
548  case VoidPtrArg:       return "p";
549  case OutIntPtrArg:     return "n";
550  case PercentArg:       return "%";
551  case InvalidSpecifier: return NULL;
552
553  // MacOS X unicode extensions.
554  case CArg:          return "C";
555  case UnicodeStrArg: return "S";
556
557  // Objective-C specific specifiers.
558  case ObjCObjArg: return "@";
559
560  // GlibC specific specifiers.
561  case PrintErrno: return "m";
562  }
563  return NULL;
564}
565
566//===----------------------------------------------------------------------===//
567// Methods on LengthModifier.
568//===----------------------------------------------------------------------===//
569
570const char *LengthModifier::toString() const {
571  switch (kind) {
572  case AsChar:
573    return "hh";
574  case AsShort:
575    return "h";
576  case AsLong: // or AsWideChar
577    return "l";
578  case AsLongLong:
579    return "ll";
580  case AsIntMax:
581    return "j";
582  case AsSizeT:
583    return "z";
584  case AsPtrDiff:
585    return "t";
586  case AsLongDouble:
587    return "L";
588  case None:
589    return "";
590  }
591  return NULL;
592}
593
594//===----------------------------------------------------------------------===//
595// Methods on OptionalAmount.
596//===----------------------------------------------------------------------===//
597
598void OptionalAmount::toString(llvm::raw_ostream &os) const {
599  switch (hs) {
600  case Invalid:
601  case NotSpecified:
602    return;
603  case Arg:
604    if (usesPositionalArg())
605      os << ".*" << getPositionalArgIndex() << "$";
606    else
607      os << ".*";
608    break;
609  case Constant:
610    os << "." << amt;
611    break;
612  }
613}
614
615//===----------------------------------------------------------------------===//
616// Methods on FormatSpecifier.
617//===----------------------------------------------------------------------===//
618
619ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const {
620  if (!CS.consumesDataArgument())
621    return ArgTypeResult::Invalid();
622
623  if (CS.isIntArg())
624    switch (LM.getKind()) {
625      case LengthModifier::AsLongDouble:
626        return ArgTypeResult::Invalid();
627      case LengthModifier::None: return Ctx.IntTy;
628      case LengthModifier::AsChar: return Ctx.SignedCharTy;
629      case LengthModifier::AsShort: return Ctx.ShortTy;
630      case LengthModifier::AsLong: return Ctx.LongTy;
631      case LengthModifier::AsLongLong: return Ctx.LongLongTy;
632      case LengthModifier::AsIntMax:
633        // FIXME: Return unknown for now.
634        return ArgTypeResult();
635      case LengthModifier::AsSizeT: return Ctx.getSizeType();
636      case LengthModifier::AsPtrDiff: return Ctx.getPointerDiffType();
637    }
638
639  if (CS.isUIntArg())
640    switch (LM.getKind()) {
641      case LengthModifier::AsLongDouble:
642        return ArgTypeResult::Invalid();
643      case LengthModifier::None: return Ctx.UnsignedIntTy;
644      case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
645      case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
646      case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
647      case LengthModifier::AsLongLong: return Ctx.UnsignedLongLongTy;
648      case LengthModifier::AsIntMax:
649        // FIXME: Return unknown for now.
650        return ArgTypeResult();
651      case LengthModifier::AsSizeT:
652        // FIXME: How to get the corresponding unsigned
653        // version of size_t?
654        return ArgTypeResult();
655      case LengthModifier::AsPtrDiff:
656        // FIXME: How to get the corresponding unsigned
657        // version of ptrdiff_t?
658        return ArgTypeResult();
659    }
660
661  if (CS.isDoubleArg()) {
662    if (LM.getKind() == LengthModifier::AsLongDouble)
663      return Ctx.LongDoubleTy;
664    return Ctx.DoubleTy;
665  }
666
667  switch (CS.getKind()) {
668    case ConversionSpecifier::CStrArg:
669      return ArgTypeResult(LM.getKind() == LengthModifier::AsWideChar ?
670          ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy);
671    case ConversionSpecifier::UnicodeStrArg:
672      // FIXME: This appears to be Mac OS X specific.
673      return ArgTypeResult::WCStrTy;
674    case ConversionSpecifier::CArg:
675      return Ctx.WCharTy;
676    default:
677      break;
678  }
679
680  // FIXME: Handle other cases.
681  return ArgTypeResult();
682}
683
684bool FormatSpecifier::fixType(QualType QT) {
685  // Handle strings first (char *, wchar_t *)
686  if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
687    CS.setKind(ConversionSpecifier::CStrArg);
688
689    // Disable irrelevant flags
690    HasAlternativeForm = 0;
691    HasLeadingZeroes = 0;
692
693    // Set the long length modifier for wide characters
694    if (QT->getPointeeType()->isWideCharType())
695      LM.setKind(LengthModifier::AsWideChar);
696
697    return true;
698  }
699
700  // We can only work with builtin types.
701  if (!QT->isBuiltinType())
702    return false;
703
704  // Everything else should be a base type
705  const BuiltinType *BT = QT->getAs<BuiltinType>();
706
707  // Set length modifier
708  switch (BT->getKind()) {
709  default:
710    // The rest of the conversions are either optional or for non-builtin types
711    LM.setKind(LengthModifier::None);
712    break;
713
714  case BuiltinType::WChar:
715  case BuiltinType::Long:
716  case BuiltinType::ULong:
717    LM.setKind(LengthModifier::AsLong);
718    break;
719
720  case BuiltinType::LongLong:
721  case BuiltinType::ULongLong:
722    LM.setKind(LengthModifier::AsLongLong);
723    break;
724
725  case BuiltinType::LongDouble:
726    LM.setKind(LengthModifier::AsLongDouble);
727    break;
728  }
729
730  // Set conversion specifier and disable any flags which do not apply to it.
731  if (QT->isAnyCharacterType()) {
732    CS.setKind(ConversionSpecifier::IntAsCharArg);
733    Precision.setHowSpecified(OptionalAmount::NotSpecified);
734    HasAlternativeForm = 0;
735    HasLeadingZeroes = 0;
736  }
737  // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
738  else if (QT->isFloatingType()) {
739    CS.setKind(ConversionSpecifier::fArg);
740  }
741  else if (QT->isPointerType()) {
742    CS.setKind(ConversionSpecifier::VoidPtrArg);
743    Precision.setHowSpecified(OptionalAmount::NotSpecified);
744    HasAlternativeForm = 0;
745    HasLeadingZeroes = 0;
746  }
747  else if (QT->isSignedIntegerType()) {
748    CS.setKind(ConversionSpecifier::dArg);
749    HasAlternativeForm = 0;
750  }
751  else if (QT->isUnsignedIntegerType()) {
752    CS.setKind(ConversionSpecifier::uArg);
753    HasAlternativeForm = 0;
754  }
755  else {
756    return false;
757  }
758
759  return true;
760}
761
762void FormatSpecifier::toString(llvm::raw_ostream &os) const {
763  // Whilst some features have no defined order, we are using the order
764  // appearing in the C99 standard (ISO/IEC 9899:1999 (E) �7.19.6.1)
765  os << "%";
766
767  // Positional args
768  if (usesPositionalArg()) {
769    os << getPositionalArgIndex() << "$";
770  }
771
772  // Conversion flags
773  if (IsLeftJustified)    os << "-";
774  if (HasPlusPrefix)      os << "+";
775  if (HasSpacePrefix)     os << " ";
776  if (HasAlternativeForm) os << "#";
777  if (HasLeadingZeroes)   os << "0";
778
779  // Minimum field width
780  FieldWidth.toString(os);
781  // Precision
782  Precision.toString(os);
783  // Length modifier
784  os << LM.toString();
785  // Conversion specifier
786  os << CS.toString();
787}
788