PrintfFormatString.cpp revision 234353
1212904Sdim//== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==//
2203955Srdivacky//
3203955Srdivacky//                     The LLVM Compiler Infrastructure
4203955Srdivacky//
5203955Srdivacky// This file is distributed under the University of Illinois Open Source
6203955Srdivacky// License. See LICENSE.TXT for details.
7203955Srdivacky//
8203955Srdivacky//===----------------------------------------------------------------------===//
9203955Srdivacky//
10203955Srdivacky// Handling of format string in printf and friends.  The structure of format
11203955Srdivacky// strings for fprintf() are described in C99 7.19.6.1.
12203955Srdivacky//
13203955Srdivacky//===----------------------------------------------------------------------===//
14203955Srdivacky
15212904Sdim#include "clang/Analysis/Analyses/FormatString.h"
16212904Sdim#include "FormatStringParsing.h"
17203955Srdivacky
18212904Sdimusing clang::analyze_format_string::ArgTypeResult;
19212904Sdimusing clang::analyze_format_string::FormatStringHandler;
20212904Sdimusing clang::analyze_format_string::LengthModifier;
21212904Sdimusing clang::analyze_format_string::OptionalAmount;
22212904Sdimusing clang::analyze_format_string::ConversionSpecifier;
23212904Sdimusing clang::analyze_printf::PrintfSpecifier;
24204643Srdivacky
25203955Srdivackyusing namespace clang;
26203955Srdivacky
27212904Sdimtypedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
28212904Sdim        PrintfSpecifierResult;
29203955Srdivacky
30203955Srdivacky//===----------------------------------------------------------------------===//
31203955Srdivacky// Methods for parsing format strings.
32203955Srdivacky//===----------------------------------------------------------------------===//
33203955Srdivacky
34212904Sdimusing analyze_format_string::ParseNonPositionAmount;
35203955Srdivacky
36212904Sdimstatic bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
37204643Srdivacky                           const char *Start, const char *&Beg, const char *E,
38204643Srdivacky                           unsigned *argIndex) {
39204643Srdivacky  if (argIndex) {
40204643Srdivacky    FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
41226633Sdim  } else {
42204643Srdivacky    const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
43212904Sdim                                           analyze_format_string::PrecisionPos);
44204643Srdivacky    if (Amt.isInvalid())
45204643Srdivacky      return true;
46204643Srdivacky    FS.setPrecision(Amt);
47204643Srdivacky  }
48204643Srdivacky  return false;
49204643Srdivacky}
50204643Srdivacky
51212904Sdimstatic PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
52203955Srdivacky                                                  const char *&Beg,
53204643Srdivacky                                                  const char *E,
54208987Srdivacky                                                  unsigned &argIndex,
55212904Sdim                                                  const LangOptions &LO) {
56203955Srdivacky
57212904Sdim  using namespace clang::analyze_format_string;
58203955Srdivacky  using namespace clang::analyze_printf;
59203955Srdivacky
60203955Srdivacky  const char *I = Beg;
61203955Srdivacky  const char *Start = 0;
62203955Srdivacky  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
63203955Srdivacky
64203955Srdivacky  // Look for a '%' character that indicates the start of a format specifier.
65203955Srdivacky  for ( ; I != E ; ++I) {
66203955Srdivacky    char c = *I;
67203955Srdivacky    if (c == '\0') {
68203955Srdivacky      // Detect spurious null characters, which are likely errors.
69203955Srdivacky      H.HandleNullChar(I);
70203955Srdivacky      return true;
71203955Srdivacky    }
72203955Srdivacky    if (c == '%') {
73203955Srdivacky      Start = I++;  // Record the start of the format specifier.
74203955Srdivacky      break;
75203955Srdivacky    }
76203955Srdivacky  }
77203955Srdivacky
78203955Srdivacky  // No format specifier found?
79203955Srdivacky  if (!Start)
80203955Srdivacky    return false;
81203955Srdivacky
82203955Srdivacky  if (I == E) {
83203955Srdivacky    // No more characters left?
84212904Sdim    H.HandleIncompleteSpecifier(Start, E - Start);
85203955Srdivacky    return true;
86203955Srdivacky  }
87203955Srdivacky
88212904Sdim  PrintfSpecifier FS;
89204643Srdivacky  if (ParseArgPosition(H, FS, Start, I, E))
90204643Srdivacky    return true;
91203955Srdivacky
92204643Srdivacky  if (I == E) {
93204643Srdivacky    // No more characters left?
94212904Sdim    H.HandleIncompleteSpecifier(Start, E - Start);
95204643Srdivacky    return true;
96204643Srdivacky  }
97204643Srdivacky
98203955Srdivacky  // Look for flags (if any).
99203955Srdivacky  bool hasMore = true;
100203955Srdivacky  for ( ; I != E; ++I) {
101203955Srdivacky    switch (*I) {
102203955Srdivacky      default: hasMore = false; break;
103218893Sdim      case '\'':
104218893Sdim        // FIXME: POSIX specific.  Always accept?
105218893Sdim        FS.setHasThousandsGrouping(I);
106218893Sdim        break;
107210299Sed      case '-': FS.setIsLeftJustified(I); break;
108210299Sed      case '+': FS.setHasPlusPrefix(I); break;
109210299Sed      case ' ': FS.setHasSpacePrefix(I); break;
110210299Sed      case '#': FS.setHasAlternativeForm(I); break;
111210299Sed      case '0': FS.setHasLeadingZeros(I); break;
112203955Srdivacky    }
113203955Srdivacky    if (!hasMore)
114203955Srdivacky      break;
115203955Srdivacky  }
116203955Srdivacky
117203955Srdivacky  if (I == E) {
118203955Srdivacky    // No more characters left?
119212904Sdim    H.HandleIncompleteSpecifier(Start, E - Start);
120203955Srdivacky    return true;
121203955Srdivacky  }
122203955Srdivacky
123203955Srdivacky  // Look for the field width (if any).
124204643Srdivacky  if (ParseFieldWidth(H, FS, Start, I, E,
125204643Srdivacky                      FS.usesPositionalArg() ? 0 : &argIndex))
126204643Srdivacky    return true;
127203955Srdivacky
128203955Srdivacky  if (I == E) {
129203955Srdivacky    // No more characters left?
130212904Sdim    H.HandleIncompleteSpecifier(Start, E - Start);
131203955Srdivacky    return true;
132203955Srdivacky  }
133203955Srdivacky
134203955Srdivacky  // Look for the precision (if any).
135203955Srdivacky  if (*I == '.') {
136203955Srdivacky    ++I;
137203955Srdivacky    if (I == E) {
138212904Sdim      H.HandleIncompleteSpecifier(Start, E - Start);
139203955Srdivacky      return true;
140203955Srdivacky    }
141203955Srdivacky
142204643Srdivacky    if (ParsePrecision(H, FS, Start, I, E,
143204643Srdivacky                       FS.usesPositionalArg() ? 0 : &argIndex))
144204643Srdivacky      return true;
145203955Srdivacky
146203955Srdivacky    if (I == E) {
147203955Srdivacky      // No more characters left?
148212904Sdim      H.HandleIncompleteSpecifier(Start, E - Start);
149203955Srdivacky      return true;
150203955Srdivacky    }
151203955Srdivacky  }
152203955Srdivacky
153203955Srdivacky  // Look for the length modifier.
154212904Sdim  if (ParseLengthModifier(FS, I, E, LO) && I == E) {
155203955Srdivacky    // No more characters left?
156212904Sdim    H.HandleIncompleteSpecifier(Start, E - Start);
157203955Srdivacky    return true;
158203955Srdivacky  }
159203955Srdivacky
160203955Srdivacky  if (*I == '\0') {
161203955Srdivacky    // Detect spurious null characters, which are likely errors.
162203955Srdivacky    H.HandleNullChar(I);
163203955Srdivacky    return true;
164203955Srdivacky  }
165203955Srdivacky
166203955Srdivacky  // Finally, look for the conversion specifier.
167203955Srdivacky  const char *conversionPosition = I++;
168203955Srdivacky  ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
169203955Srdivacky  switch (*conversionPosition) {
170203955Srdivacky    default:
171203955Srdivacky      break;
172203955Srdivacky    // C99: 7.19.6.1 (section 8).
173204643Srdivacky    case '%': k = ConversionSpecifier::PercentArg;   break;
174204643Srdivacky    case 'A': k = ConversionSpecifier::AArg; break;
175204643Srdivacky    case 'E': k = ConversionSpecifier::EArg; break;
176204643Srdivacky    case 'F': k = ConversionSpecifier::FArg; break;
177204643Srdivacky    case 'G': k = ConversionSpecifier::GArg; break;
178204643Srdivacky    case 'X': k = ConversionSpecifier::XArg; break;
179204643Srdivacky    case 'a': k = ConversionSpecifier::aArg; break;
180212904Sdim    case 'c': k = ConversionSpecifier::cArg; break;
181203955Srdivacky    case 'd': k = ConversionSpecifier::dArg; break;
182204643Srdivacky    case 'e': k = ConversionSpecifier::eArg; break;
183204643Srdivacky    case 'f': k = ConversionSpecifier::fArg; break;
184204643Srdivacky    case 'g': k = ConversionSpecifier::gArg; break;
185203955Srdivacky    case 'i': k = ConversionSpecifier::iArg; break;
186212904Sdim    case 'n': k = ConversionSpecifier::nArg; break;
187203955Srdivacky    case 'o': k = ConversionSpecifier::oArg; break;
188212904Sdim    case 'p': k = ConversionSpecifier::pArg;   break;
189212904Sdim    case 's': k = ConversionSpecifier::sArg;      break;
190203955Srdivacky    case 'u': k = ConversionSpecifier::uArg; break;
191203955Srdivacky    case 'x': k = ConversionSpecifier::xArg; break;
192218893Sdim    // POSIX specific.
193204643Srdivacky    case 'C': k = ConversionSpecifier::CArg; break;
194212904Sdim    case 'S': k = ConversionSpecifier::SArg; break;
195203955Srdivacky    // Objective-C.
196203955Srdivacky    case '@': k = ConversionSpecifier::ObjCObjArg; break;
197203955Srdivacky    // Glibc specific.
198203955Srdivacky    case 'm': k = ConversionSpecifier::PrintErrno; break;
199208987Srdivacky    // FreeBSD format extensions
200208987Srdivacky    case 'b': if (LO.FormatExtensions) k = ConversionSpecifier::bArg; break; /* check for int and then char * */
201213694Srpaulo    case 'r': if (LO.FormatExtensions) k = ConversionSpecifier::rArg; break;
202213681Srpaulo    case 'y': if (LO.FormatExtensions) k = ConversionSpecifier::iArg; break;
203208987Srdivacky    case 'D': if (LO.FormatExtensions) k = ConversionSpecifier::DArg; break; /* check for u_char * pointer and a char * string */
204203955Srdivacky  }
205212904Sdim  PrintfConversionSpecifier CS(conversionPosition, k);
206204643Srdivacky  FS.setConversionSpecifier(CS);
207204643Srdivacky  if (CS.consumesDataArgument() && !FS.usesPositionalArg())
208204643Srdivacky    FS.setArgIndex(argIndex++);
209208987Srdivacky  // FreeBSD extension
210208987Srdivacky  if (k == ConversionSpecifier::bArg || k == ConversionSpecifier::DArg)
211208987Srdivacky    argIndex++;
212203955Srdivacky
213203955Srdivacky  if (k == ConversionSpecifier::InvalidSpecifier) {
214204643Srdivacky    // Assume the conversion takes one argument.
215218893Sdim    return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, I - Start);
216203955Srdivacky  }
217212904Sdim  return PrintfSpecifierResult(Start, FS);
218203955Srdivacky}
219203955Srdivacky
220212904Sdimbool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
221212904Sdim                                                     const char *I,
222212904Sdim                                                     const char *E,
223212904Sdim                                                     const LangOptions &LO) {
224204643Srdivacky
225204643Srdivacky  unsigned argIndex = 0;
226204643Srdivacky
227203955Srdivacky  // Keep looking for a format specifier until we have exhausted the string.
228203955Srdivacky  while (I != E) {
229212904Sdim    const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
230212904Sdim                                                            LO);
231203955Srdivacky    // Did a fail-stop error of any kind occur when parsing the specifier?
232203955Srdivacky    // If so, don't do any more processing.
233203955Srdivacky    if (FSR.shouldStop())
234203955Srdivacky      return true;;
235203955Srdivacky    // Did we exhaust the string or encounter an error that
236203955Srdivacky    // we can recover from?
237203955Srdivacky    if (!FSR.hasValue())
238203955Srdivacky      continue;
239203955Srdivacky    // We have a format specifier.  Pass it to the callback.
240212904Sdim    if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
241203955Srdivacky                                 I - FSR.getStart()))
242203955Srdivacky      return true;
243203955Srdivacky  }
244203955Srdivacky  assert(I == E && "Format string not exhausted");
245203955Srdivacky  return false;
246203955Srdivacky}
247203955Srdivacky
248203955Srdivacky//===----------------------------------------------------------------------===//
249210299Sed// Methods on PrintfSpecifier.
250210299Sed//===----------------------------------------------------------------------===//
251210299Sed
252210299SedArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx,
253210299Sed                                          bool IsObjCLiteral) const {
254210299Sed  const PrintfConversionSpecifier &CS = getConversionSpecifier();
255210299Sed
256210299Sed  if (!CS.consumesDataArgument())
257210299Sed    return ArgTypeResult::Invalid();
258210299Sed
259210299Sed  if (CS.getKind() == ConversionSpecifier::cArg)
260210299Sed    switch (LM.getKind()) {
261210299Sed      case LengthModifier::None: return Ctx.IntTy;
262210299Sed      case LengthModifier::AsLong:
263210299Sed        return ArgTypeResult(ArgTypeResult::WIntTy, "wint_t");
264210299Sed      default:
265210299Sed        return ArgTypeResult::Invalid();
266210299Sed    }
267212904Sdim
268212904Sdim  if (CS.isIntArg())
269212904Sdim    switch (LM.getKind()) {
270212904Sdim      case LengthModifier::AsLongDouble:
271212904Sdim        // GNU extension.
272212904Sdim        return Ctx.LongLongTy;
273210299Sed      case LengthModifier::None: return Ctx.IntTy;
274210299Sed      case LengthModifier::AsChar: return ArgTypeResult::AnyCharTy;
275210299Sed      case LengthModifier::AsShort: return Ctx.ShortTy;
276212904Sdim      case LengthModifier::AsLong: return Ctx.LongTy;
277212904Sdim      case LengthModifier::AsLongLong:
278210299Sed      case LengthModifier::AsQuad:
279210299Sed        return Ctx.LongLongTy;
280210299Sed      case LengthModifier::AsIntMax:
281210299Sed        return ArgTypeResult(Ctx.getIntMaxType(), "intmax_t");
282212904Sdim      case LengthModifier::AsSizeT:
283212904Sdim        // FIXME: How to get the corresponding signed version of size_t?
284212904Sdim        return ArgTypeResult();
285213694Srpaulo      case LengthModifier::AsPtrDiff:
286212904Sdim        return ArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t");
287210299Sed      case LengthModifier::AsAllocate:
288210299Sed      case LengthModifier::AsMAllocate:
289210299Sed        return ArgTypeResult::Invalid();
290210299Sed    }
291210299Sed
292210299Sed  if (CS.isUIntArg())
293210299Sed    switch (LM.getKind()) {
294212904Sdim      case LengthModifier::AsLongDouble:
295210299Sed        // GNU extension.
296210299Sed        return Ctx.UnsignedLongLongTy;
297212904Sdim      case LengthModifier::None: return Ctx.UnsignedIntTy;
298212904Sdim      case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
299218893Sdim      case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
300203955Srdivacky      case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
301203955Srdivacky      case LengthModifier::AsLongLong:
302203955Srdivacky      case LengthModifier::AsQuad:
303212904Sdim        return Ctx.UnsignedLongLongTy;
304212904Sdim      case LengthModifier::AsIntMax:
305212904Sdim        return ArgTypeResult(Ctx.getUIntMaxType(), "uintmax_t");
306212904Sdim      case LengthModifier::AsSizeT:
307212904Sdim        return ArgTypeResult(Ctx.getSizeType(), "size_t");
308212904Sdim      case LengthModifier::AsPtrDiff:
309212904Sdim        // FIXME: How to get the corresponding unsigned
310218893Sdim        // version of ptrdiff_t?
311203955Srdivacky        return ArgTypeResult();
312210299Sed      case LengthModifier::AsAllocate:
313210299Sed      case LengthModifier::AsMAllocate:
314203955Srdivacky        return ArgTypeResult::Invalid();
315210299Sed    }
316210299Sed
317210299Sed  if (CS.isDoubleArg()) {
318210299Sed    if (LM.getKind() == LengthModifier::AsLongDouble)
319210299Sed      return Ctx.LongDoubleTy;
320210299Sed    return Ctx.DoubleTy;
321203955Srdivacky  }
322203955Srdivacky
323210299Sed  switch (CS.getKind()) {
324210299Sed    case ConversionSpecifier::sArg:
325203955Srdivacky      if (LM.getKind() == LengthModifier::AsWideChar) {
326203955Srdivacky        if (IsObjCLiteral)
327203955Srdivacky          return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst());
328210299Sed        return ArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t *");
329210299Sed      }
330203955Srdivacky      return ArgTypeResult::CStrTy;
331210299Sed    case ConversionSpecifier::SArg:
332210299Sed      if (IsObjCLiteral)
333210299Sed        return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst());
334210299Sed      return ArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t *");
335210299Sed    case ConversionSpecifier::CArg:
336210299Sed      if (IsObjCLiteral)
337203955Srdivacky        return Ctx.UnsignedShortTy;
338203955Srdivacky      return ArgTypeResult(Ctx.WCharTy, "wchar_t");
339210299Sed    case ConversionSpecifier::pArg:
340203955Srdivacky      return ArgTypeResult::CPointerTy;
341203955Srdivacky    case ConversionSpecifier::ObjCObjArg:
342203955Srdivacky      return ArgTypeResult::ObjCPointerTy;
343210299Sed    default:
344203955Srdivacky      break;
345203955Srdivacky  }
346203955Srdivacky
347203955Srdivacky  // FIXME: Handle other cases.
348203955Srdivacky  return ArgTypeResult();
349203955Srdivacky}
350210299Sed
351203955Srdivackybool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
352203955Srdivacky                              ASTContext &Ctx, bool IsObjCLiteral) {
353203955Srdivacky  // Handle strings first (char *, wchar_t *)
354203955Srdivacky  if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
355204643Srdivacky    CS.setKind(ConversionSpecifier::sArg);
356212904Sdim
357210299Sed    // Disable irrelevant flags
358210299Sed    HasAlternativeForm = 0;
359212904Sdim    HasLeadingZeroes = 0;
360204643Srdivacky
361204643Srdivacky    // Set the long length modifier for wide characters
362204643Srdivacky    if (QT->getPointeeType()->isWideCharType())
363204643Srdivacky      LM.setKind(LengthModifier::AsWideChar);
364212904Sdim    else
365210299Sed      LM.setKind(LengthModifier::None);
366204643Srdivacky
367204643Srdivacky    return true;
368204643Srdivacky  }
369203955Srdivacky
370203955Srdivacky  // We can only work with builtin types.
371203955Srdivacky  const BuiltinType *BT = QT->getAs<BuiltinType>();
372203955Srdivacky  if (!BT)
373203955Srdivacky    return false;
374212904Sdim
375210299Sed  // Set length modifier
376210299Sed  switch (BT->getKind()) {
377212904Sdim  case BuiltinType::Bool:
378210299Sed  case BuiltinType::WChar_U:
379210299Sed  case BuiltinType::WChar_S:
380210299Sed  case BuiltinType::Char16:
381210299Sed  case BuiltinType::Char32:
382210299Sed  case BuiltinType::UInt128:
383210299Sed  case BuiltinType::Int128:
384210299Sed  case BuiltinType::Half:
385210299Sed    // Various types which are non-trivial to correct.
386210299Sed    return false;
387210299Sed
388210299Sed#define SIGNED_TYPE(Id, SingletonId)
389210299Sed#define UNSIGNED_TYPE(Id, SingletonId)
390210299Sed#define FLOATING_TYPE(Id, SingletonId)
391210299Sed#define BUILTIN_TYPE(Id, SingletonId) \
392210299Sed  case BuiltinType::Id:
393210299Sed#include "clang/AST/BuiltinTypes.def"
394210299Sed    // Misc other stuff which doesn't make sense here.
395210299Sed    return false;
396210299Sed
397210299Sed  case BuiltinType::UInt:
398210299Sed  case BuiltinType::Int:
399221345Sdim  case BuiltinType::Float:
400221345Sdim  case BuiltinType::Double:
401221345Sdim    LM.setKind(LengthModifier::None);
402221345Sdim    break;
403221345Sdim
404221345Sdim  case BuiltinType::Char_U:
405221345Sdim  case BuiltinType::UChar:
406226633Sdim  case BuiltinType::Char_S:
407221345Sdim  case BuiltinType::SChar:
408221345Sdim    LM.setKind(LengthModifier::AsChar);
409221345Sdim    break;
410221345Sdim
411221345Sdim  case BuiltinType::Short:
412221345Sdim  case BuiltinType::UShort:
413221345Sdim    LM.setKind(LengthModifier::AsShort);
414221345Sdim    break;
415221345Sdim
416221345Sdim  case BuiltinType::Long:
417221345Sdim  case BuiltinType::ULong:
418221345Sdim    LM.setKind(LengthModifier::AsLong);
419221345Sdim    break;
420221345Sdim
421221345Sdim  case BuiltinType::LongLong:
422221345Sdim  case BuiltinType::ULongLong:
423221345Sdim    LM.setKind(LengthModifier::AsLongLong);
424221345Sdim    break;
425221345Sdim
426210299Sed  case BuiltinType::LongDouble:
427210299Sed    LM.setKind(LengthModifier::AsLongDouble);
428210299Sed    break;
429218893Sdim  }
430218893Sdim
431218893Sdim  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
432218893Sdim  if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus0x)) {
433218893Sdim    const IdentifierInfo *Identifier = QT.getBaseTypeIdentifier();
434218893Sdim    if (Identifier->getName() == "size_t") {
435218893Sdim      LM.setKind(LengthModifier::AsSizeT);
436218893Sdim    } else if (Identifier->getName() == "ssize_t") {
437218893Sdim      // Not C99, but common in Unix.
438218893Sdim      LM.setKind(LengthModifier::AsSizeT);
439218893Sdim    } else if (Identifier->getName() == "intmax_t") {
440218893Sdim      LM.setKind(LengthModifier::AsIntMax);
441210299Sed    } else if (Identifier->getName() == "uintmax_t") {
442210299Sed      LM.setKind(LengthModifier::AsIntMax);
443210299Sed    } else if (Identifier->getName() == "ptrdiff_t") {
444210299Sed      LM.setKind(LengthModifier::AsPtrDiff);
445210299Sed    }
446210299Sed  }
447210299Sed
448210299Sed  // If fixing the length modifier was enough, we are done.
449210299Sed  const analyze_printf::ArgTypeResult &ATR = getArgType(Ctx, IsObjCLiteral);
450210299Sed  if (hasValidLengthModifier() && ATR.isValid() && ATR.matchesType(Ctx, QT))
451210299Sed    return true;
452210299Sed
453210299Sed  // Set conversion specifier and disable any flags which do not apply to it.
454210299Sed  // Let typedefs to char fall through to int, as %c is silly for uint8_t.
455210299Sed  if (isa<TypedefType>(QT) && QT->isAnyCharacterType()) {
456210299Sed    CS.setKind(ConversionSpecifier::cArg);
457218893Sdim    LM.setKind(LengthModifier::None);
458218893Sdim    Precision.setHowSpecified(OptionalAmount::NotSpecified);
459212904Sdim    HasAlternativeForm = 0;
460218893Sdim    HasLeadingZeroes = 0;
461210299Sed    HasPlusPrefix = 0;
462210299Sed  }
463210299Sed  // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
464210299Sed  else if (QT->isRealFloatingType()) {
465210299Sed    CS.setKind(ConversionSpecifier::fArg);
466210299Sed  }
467210299Sed  else if (QT->isSignedIntegerType()) {
468210299Sed    CS.setKind(ConversionSpecifier::dArg);
469210299Sed    HasAlternativeForm = 0;
470210299Sed  }
471210299Sed  else if (QT->isUnsignedIntegerType()) {
472210299Sed    CS.setKind(ConversionSpecifier::uArg);
473210299Sed    HasAlternativeForm = 0;
474210299Sed    HasPlusPrefix = 0;
475221345Sdim  } else {
476221345Sdim    llvm_unreachable("Unexpected type");
477221345Sdim  }
478210299Sed
479210299Sed  return true;
480226633Sdim}
481226633Sdim
482210299Sedvoid PrintfSpecifier::toString(raw_ostream &os) const {
483210299Sed  // Whilst some features have no defined order, we are using the order
484210299Sed  // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
485210299Sed  os << "%";
486210299Sed
487226633Sdim  // Positional args
488210299Sed  if (usesPositionalArg()) {
489218893Sdim    os << getPositionalArgIndex() << "$";
490210299Sed  }
491210299Sed
492210299Sed  // Conversion flags
493210299Sed  if (IsLeftJustified)    os << "-";
494210299Sed  if (HasPlusPrefix)      os << "+";
495210299Sed  if (HasSpacePrefix)     os << " ";
496210299Sed  if (HasAlternativeForm) os << "#";
497210299Sed  if (HasLeadingZeroes)   os << "0";
498210299Sed
499210299Sed  // Minimum field width
500210299Sed  FieldWidth.toString(os);
501210299Sed  // Precision
502210299Sed  Precision.toString(os);
503210299Sed  // Length modifier
504210299Sed  os << LM.toString();
505210299Sed  // Conversion specifier
506210299Sed  os << CS.toString();
507210299Sed}
508210299Sed
509210299Sedbool PrintfSpecifier::hasValidPlusPrefix() const {
510210299Sed  if (!HasPlusPrefix)
511210299Sed    return true;
512210299Sed
513210299Sed  // The plus prefix only makes sense for signed conversions
514212904Sdim  switch (CS.getKind()) {
515210299Sed  case ConversionSpecifier::dArg:
516210299Sed  case ConversionSpecifier::iArg:
517210299Sed  case ConversionSpecifier::fArg:
518210299Sed  case ConversionSpecifier::FArg:
519210299Sed  case ConversionSpecifier::eArg:
520210299Sed  case ConversionSpecifier::EArg:
521210299Sed  case ConversionSpecifier::gArg:
522210299Sed  case ConversionSpecifier::GArg:
523210299Sed  case ConversionSpecifier::aArg:
524210299Sed  case ConversionSpecifier::AArg:
525210299Sed  case ConversionSpecifier::rArg:
526210299Sed    return true;
527210299Sed
528210299Sed  default:
529210299Sed    return false;
530213694Srpaulo  }
531210299Sed}
532210299Sed
533210299Sedbool PrintfSpecifier::hasValidAlternativeForm() const {
534210299Sed  if (!HasAlternativeForm)
535210299Sed    return true;
536210299Sed
537210299Sed  // Alternate form flag only valid with the oxXaAeEfFgG conversions
538212904Sdim  switch (CS.getKind()) {
539210299Sed  case ConversionSpecifier::oArg:
540210299Sed  case ConversionSpecifier::xArg:
541210299Sed  case ConversionSpecifier::XArg:
542218893Sdim  case ConversionSpecifier::aArg:
543210299Sed  case ConversionSpecifier::AArg:
544210299Sed  case ConversionSpecifier::eArg:
545210299Sed  case ConversionSpecifier::EArg:
546218893Sdim  case ConversionSpecifier::fArg:
547210299Sed  case ConversionSpecifier::FArg:
548210299Sed  case ConversionSpecifier::gArg:
549210299Sed  case ConversionSpecifier::GArg:
550210299Sed  case ConversionSpecifier::rArg:
551210299Sed    return true;
552210299Sed
553210299Sed  default:
554210299Sed    return false;
555213694Srpaulo  }
556210299Sed}
557210299Sed
558210299Sedbool PrintfSpecifier::hasValidLeadingZeros() const {
559210299Sed  if (!HasLeadingZeroes)
560210299Sed    return true;
561210299Sed
562210299Sed  // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
563212904Sdim  switch (CS.getKind()) {
564210299Sed  case ConversionSpecifier::dArg:
565210299Sed  case ConversionSpecifier::iArg:
566210299Sed  case ConversionSpecifier::oArg:
567210299Sed  case ConversionSpecifier::uArg:
568210299Sed  case ConversionSpecifier::xArg:
569210299Sed  case ConversionSpecifier::XArg:
570210299Sed  case ConversionSpecifier::aArg:
571210299Sed  case ConversionSpecifier::AArg:
572210299Sed  case ConversionSpecifier::eArg:
573210299Sed  case ConversionSpecifier::EArg:
574210299Sed  case ConversionSpecifier::fArg:
575210299Sed  case ConversionSpecifier::FArg:
576210299Sed  case ConversionSpecifier::gArg:
577210299Sed  case ConversionSpecifier::GArg:
578210299Sed    return true;
579210299Sed
580210299Sed  default:
581210299Sed    return false;
582210299Sed  }
583210299Sed}
584210299Sed
585210299Sedbool PrintfSpecifier::hasValidSpacePrefix() const {
586210299Sed  if (!HasSpacePrefix)
587210299Sed    return true;
588210299Sed
589210299Sed  // The space prefix only makes sense for signed conversions
590212904Sdim  switch (CS.getKind()) {
591210299Sed  case ConversionSpecifier::dArg:
592210299Sed  case ConversionSpecifier::iArg:
593210299Sed  case ConversionSpecifier::fArg:
594210299Sed  case ConversionSpecifier::FArg:
595210299Sed  case ConversionSpecifier::eArg:
596210299Sed  case ConversionSpecifier::EArg:
597210299Sed  case ConversionSpecifier::gArg:
598210299Sed  case ConversionSpecifier::GArg:
599210299Sed  case ConversionSpecifier::aArg:
600210299Sed  case ConversionSpecifier::AArg:
601210299Sed    return true;
602210299Sed
603210299Sed  default:
604210299Sed    return false;
605210299Sed  }
606210299Sed}
607210299Sed
608210299Sedbool PrintfSpecifier::hasValidLeftJustified() const {
609210299Sed  if (!IsLeftJustified)
610210299Sed    return true;
611210299Sed
612210299Sed  // The left justified flag is valid for all conversions except n
613212904Sdim  switch (CS.getKind()) {
614210299Sed  case ConversionSpecifier::nArg:
615210299Sed    return false;
616210299Sed
617210299Sed  default:
618210299Sed    return true;
619212904Sdim  }
620210299Sed}
621210299Sed
622210299Sedbool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
623210299Sed  if (!HasThousandsGrouping)
624210299Sed    return true;
625210299Sed
626210299Sed  switch (CS.getKind()) {
627218893Sdim    case ConversionSpecifier::dArg:
628218893Sdim    case ConversionSpecifier::iArg:
629218893Sdim    case ConversionSpecifier::uArg:
630218893Sdim    case ConversionSpecifier::fArg:
631218893Sdim    case ConversionSpecifier::FArg:
632218893Sdim    case ConversionSpecifier::gArg:
633218893Sdim    case ConversionSpecifier::GArg:
634218893Sdim      return true;
635218893Sdim    default:
636218893Sdim      return false;
637218893Sdim  }
638218893Sdim}
639218893Sdim
640218893Sdimbool PrintfSpecifier::hasValidPrecision() const {
641218893Sdim  if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
642218893Sdim    return true;
643218893Sdim
644218893Sdim  // Precision is only valid with the diouxXaAeEfFgGs conversions
645212904Sdim  switch (CS.getKind()) {
646210299Sed  case ConversionSpecifier::dArg:
647210299Sed  case ConversionSpecifier::iArg:
648210299Sed  case ConversionSpecifier::oArg:
649210299Sed  case ConversionSpecifier::uArg:
650210299Sed  case ConversionSpecifier::xArg:
651210299Sed  case ConversionSpecifier::XArg:
652210299Sed  case ConversionSpecifier::aArg:
653210299Sed  case ConversionSpecifier::AArg:
654210299Sed  case ConversionSpecifier::eArg:
655210299Sed  case ConversionSpecifier::EArg:
656210299Sed  case ConversionSpecifier::fArg:
657210299Sed  case ConversionSpecifier::FArg:
658210299Sed  case ConversionSpecifier::gArg:
659210299Sed  case ConversionSpecifier::GArg:
660210299Sed  case ConversionSpecifier::sArg:
661210299Sed    return true;
662210299Sed
663210299Sed  default:
664210299Sed    return false;
665212904Sdim  }
666210299Sed}
667210299Sedbool PrintfSpecifier::hasValidFieldWidth() const {
668210299Sed  if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
669210299Sed      return true;
670210299Sed
671210299Sed  // The field width is valid for all conversions except n
672212904Sdim  switch (CS.getKind()) {
673210299Sed  case ConversionSpecifier::nArg:
674210299Sed    return false;
675210299Sed
676210299Sed  default:
677210299Sed    return true;
678212904Sdim  }
679210299Sed}
680210299Sed