FormatString.cpp revision 826a3457f737f1fc45a22954fd1bfde38160c165
1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*-
2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//
3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//                     The LLVM Compiler Infrastructure
4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//
5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// This file is distributed under the University of Illinois Open Source
6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// License. See LICENSE.TXT for details.
7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//
8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//===----------------------------------------------------------------------===//
9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//
10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Shared details for processing format strings of printf and scanf
11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// (and friends).
12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//
13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//===----------------------------------------------------------------------===//
14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "FormatStringParsing.h"
16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgusing clang::analyze_format_string::ArgTypeResult;
18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgusing clang::analyze_format_string::FormatStringHandler;
19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgusing clang::analyze_format_string::FormatSpecifier;
20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgusing clang::analyze_format_string::LengthModifier;
21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgusing clang::analyze_format_string::OptionalAmount;
22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgusing clang::analyze_format_string::PositionContext;
23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgusing namespace clang;
24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Key function to FormatStringHandler.
26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgFormatStringHandler::~FormatStringHandler() {}
27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//===----------------------------------------------------------------------===//
29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Functions for parsing format strings components in both printf and
30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// scanf format strings.
31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//===----------------------------------------------------------------------===//
32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgOptionalAmount
34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclang::analyze_format_string::ParseAmount(const char *&Beg, const char *E) {
35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  const char *I = Beg;
36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  unsigned accumulator = 0;
39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  bool hasDigits = false;
40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  for ( ; I != E; ++I) {
42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    char c = *I;
43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    if (c >= '0' && c <= '9') {
44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      hasDigits = true;
45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      accumulator = (accumulator * 10) + (c - '0');
46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      continue;
47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    }
48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    if (hasDigits)
50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg,
51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org          false);
52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    break;
54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  }
55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  return OptionalAmount();
57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgOptionalAmount
60f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclang::analyze_format_string::ParseNonPositionAmount(const char *&Beg,
61f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                                     const char *E,
62f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                                     unsigned &argIndex) {
63f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  if (*Beg == '*') {
64f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    ++Beg;
65f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
66f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  }
67f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
68f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  return ParseAmount(Beg, E);
69f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
70f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
71f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgOptionalAmount
72f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H,
73f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                                  const char *Start,
74f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                                  const char *&Beg,
75f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                                  const char *E,
76f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                                  PositionContext p) {
77f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  if (*Beg == '*') {
78f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    const char *I = Beg + 1;
79f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    const OptionalAmount &Amt = ParseAmount(I, E);
80f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
81f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
82f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      H.HandleInvalidPosition(Beg, I - Beg, p);
83f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return OptionalAmount(false);
84f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    }
85f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
86f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    if (I == E) {
87f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      // No more characters left?
88f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      H.HandleIncompleteSpecifier(Start, E - Start);
89f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return OptionalAmount(false);
90f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    }
91f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
92f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    assert(Amt.getHowSpecified() == OptionalAmount::Constant);
93f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
94f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    if (*I == '$') {
95f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      // Handle positional arguments
96f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
97f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      // Special case: '*0$', since this is an easy mistake.
98f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (Amt.getConstantAmount() == 0) {
99f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        H.HandleZeroPosition(Beg, I - Beg + 1);
100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return OptionalAmount(false);
101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      }
102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      const char *Tmp = Beg;
104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      Beg = ++I;
105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,
107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                            Tmp, 0, true);
108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    }
109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    H.HandleInvalidPosition(Beg, I - Beg, p);
111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    return OptionalAmount(false);
112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  }
113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  return ParseAmount(Beg, E);
115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgbool
119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H,
120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                              FormatSpecifier &CS,
121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                              const char *Start,
122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                              const char *&Beg, const char *E,
123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                              unsigned *argIndex) {
124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // FIXME: Support negative field widths.
125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  if (argIndex) {
126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  }
128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  else {
129f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    const OptionalAmount Amt =
130f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      ParsePositionAmount(H, Start, Beg, E,
131f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                          analyze_format_string::FieldWidthPos);
132f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
133f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    if (Amt.isInvalid())
134f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return true;
135f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    CS.setFieldWidth(Amt);
136f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  }
137f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  return false;
138f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
139f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
140f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgbool
141f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
142f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                               FormatSpecifier &FS,
143f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                               const char *Start,
144f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                               const char *&Beg,
145f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                               const char *E) {
146f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  const char *I = Beg;
147f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
148f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  const OptionalAmount &Amt = ParseAmount(I, E);
149f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
150f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  if (I == E) {
151f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    // No more characters left?
152f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    H.HandleIncompleteSpecifier(Start, E - Start);
153f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    return true;
154f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  }
155f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
156f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
157f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    // Special case: '%0$', since this is an easy mistake.
158f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    if (Amt.getConstantAmount() == 0) {
159f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      H.HandleZeroPosition(Start, I - Start);
160f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return true;
161f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    }
162f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
163f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    FS.setArgIndex(Amt.getConstantAmount() - 1);
164f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    FS.setUsesPositionalArg();
165f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    // Update the caller's pointer if we decided to consume
166f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    // these characters.
167f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    Beg = I;
168f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    return false;
169f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  }
170f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
171  return false;
172}
173
174bool
175clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
176                                                  const char *&I,
177                                                  const char *E) {
178  LengthModifier::Kind lmKind = LengthModifier::None;
179  const char *lmPosition = I;
180  switch (*I) {
181    default:
182      return false;
183    case 'h':
184      ++I;
185      lmKind = (I != E && *I == 'h') ?
186      ++I, LengthModifier::AsChar : LengthModifier::AsShort;
187      break;
188    case 'l':
189      ++I;
190      lmKind = (I != E && *I == 'l') ?
191      ++I, LengthModifier::AsLongLong : LengthModifier::AsLong;
192      break;
193    case 'j': lmKind = LengthModifier::AsIntMax;     ++I; break;
194    case 'z': lmKind = LengthModifier::AsSizeT;      ++I; break;
195    case 't': lmKind = LengthModifier::AsPtrDiff;    ++I; break;
196    case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
197    case 'q': lmKind = LengthModifier::AsLongLong;   ++I; break;
198  }
199  LengthModifier lm(lmPosition, lmKind);
200  FS.setLengthModifier(lm);
201  return true;
202}
203
204//===----------------------------------------------------------------------===//
205// Methods on ArgTypeResult.
206//===----------------------------------------------------------------------===//
207
208bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
209  switch (K) {
210    case InvalidTy:
211      assert(false && "ArgTypeResult must be valid");
212      return true;
213
214    case UnknownTy:
215      return true;
216
217    case SpecificTy: {
218      argTy = C.getCanonicalType(argTy).getUnqualifiedType();
219      if (T == argTy)
220        return true;
221      if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
222        switch (BT->getKind()) {
223          default:
224            break;
225          case BuiltinType::Char_S:
226          case BuiltinType::SChar:
227            return T == C.UnsignedCharTy;
228          case BuiltinType::Char_U:
229          case BuiltinType::UChar:
230            return T == C.SignedCharTy;
231          case BuiltinType::Short:
232            return T == C.UnsignedShortTy;
233          case BuiltinType::UShort:
234            return T == C.ShortTy;
235          case BuiltinType::Int:
236            return T == C.UnsignedIntTy;
237          case BuiltinType::UInt:
238            return T == C.IntTy;
239          case BuiltinType::Long:
240            return T == C.UnsignedLongTy;
241          case BuiltinType::ULong:
242            return T == C.LongTy;
243          case BuiltinType::LongLong:
244            return T == C.UnsignedLongLongTy;
245          case BuiltinType::ULongLong:
246            return T == C.LongLongTy;
247        }
248      return false;
249    }
250
251    case CStrTy: {
252      const PointerType *PT = argTy->getAs<PointerType>();
253      if (!PT)
254        return false;
255      QualType pointeeTy = PT->getPointeeType();
256      if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
257        switch (BT->getKind()) {
258          case BuiltinType::Void:
259          case BuiltinType::Char_U:
260          case BuiltinType::UChar:
261          case BuiltinType::Char_S:
262          case BuiltinType::SChar:
263            return true;
264          default:
265            break;
266        }
267
268      return false;
269    }
270
271    case WCStrTy: {
272      const PointerType *PT = argTy->getAs<PointerType>();
273      if (!PT)
274        return false;
275      QualType pointeeTy =
276        C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
277      return pointeeTy == C.getWCharType();
278    }
279
280    case CPointerTy:
281      return argTy->getAs<PointerType>() != NULL ||
282      	     argTy->getAs<ObjCObjectPointerType>() != NULL;
283
284    case ObjCPointerTy:
285      return argTy->getAs<ObjCObjectPointerType>() != NULL;
286  }
287
288  // FIXME: Should be unreachable, but Clang is currently emitting
289  // a warning.
290  return false;
291}
292
293QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
294  switch (K) {
295    case InvalidTy:
296      assert(false && "No representative type for Invalid ArgTypeResult");
297      // Fall-through.
298    case UnknownTy:
299      return QualType();
300    case SpecificTy:
301      return T;
302    case CStrTy:
303      return C.getPointerType(C.CharTy);
304    case WCStrTy:
305      return C.getPointerType(C.getWCharType());
306    case ObjCPointerTy:
307      return C.ObjCBuiltinIdTy;
308    case CPointerTy:
309      return C.VoidPtrTy;
310  }
311
312  // FIXME: Should be unreachable, but Clang is currently emitting
313  // a warning.
314  return QualType();
315}
316
317//===----------------------------------------------------------------------===//
318// Methods on OptionalAmount.
319//===----------------------------------------------------------------------===//
320
321ArgTypeResult
322analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {
323  return Ctx.IntTy;
324}
325
326//===----------------------------------------------------------------------===//
327// Methods on LengthModifier.
328//===----------------------------------------------------------------------===//
329
330const char *
331analyze_format_string::LengthModifier::toString() const {
332  switch (kind) {
333  case AsChar:
334    return "hh";
335  case AsShort:
336    return "h";
337  case AsLong: // or AsWideChar
338    return "l";
339  case AsLongLong:
340    return "ll";
341  case AsIntMax:
342    return "j";
343  case AsSizeT:
344    return "z";
345  case AsPtrDiff:
346    return "t";
347  case AsLongDouble:
348    return "L";
349  case None:
350    return "";
351  }
352  return NULL;
353}
354
355//===----------------------------------------------------------------------===//
356// Methods on OptionalAmount.
357//===----------------------------------------------------------------------===//
358
359void
360analyze_format_string::OptionalAmount::toString(llvm::raw_ostream &os) const {
361  switch (hs) {
362  case Invalid:
363  case NotSpecified:
364    return;
365  case Arg:
366    if (UsesDotPrefix)
367        os << ".";
368    if (usesPositionalArg())
369      os << "*" << getPositionalArgIndex() << "$";
370    else
371      os << "*";
372    break;
373  case Constant:
374    if (UsesDotPrefix)
375        os << ".";
376    os << amt;
377    break;
378  }
379}
380
381