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"
16249423Sdim#include "FormatStringParsing.h"
17243830Sdim#include "clang/Basic/TargetInfo.h"
18203955Srdivacky
19239462Sdimusing clang::analyze_format_string::ArgType;
20212904Sdimusing clang::analyze_format_string::FormatStringHandler;
21212904Sdimusing clang::analyze_format_string::LengthModifier;
22212904Sdimusing clang::analyze_format_string::OptionalAmount;
23212904Sdimusing clang::analyze_format_string::ConversionSpecifier;
24212904Sdimusing clang::analyze_printf::PrintfSpecifier;
25204643Srdivacky
26203955Srdivackyusing namespace clang;
27203955Srdivacky
28212904Sdimtypedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
29212904Sdim        PrintfSpecifierResult;
30203955Srdivacky
31203955Srdivacky//===----------------------------------------------------------------------===//
32203955Srdivacky// Methods for parsing format strings.
33203955Srdivacky//===----------------------------------------------------------------------===//
34203955Srdivacky
35212904Sdimusing analyze_format_string::ParseNonPositionAmount;
36203955Srdivacky
37212904Sdimstatic bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
38204643Srdivacky                           const char *Start, const char *&Beg, const char *E,
39204643Srdivacky                           unsigned *argIndex) {
40204643Srdivacky  if (argIndex) {
41204643Srdivacky    FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
42226633Sdim  } else {
43204643Srdivacky    const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
44212904Sdim                                           analyze_format_string::PrecisionPos);
45204643Srdivacky    if (Amt.isInvalid())
46204643Srdivacky      return true;
47204643Srdivacky    FS.setPrecision(Amt);
48204643Srdivacky  }
49204643Srdivacky  return false;
50204643Srdivacky}
51204643Srdivacky
52212904Sdimstatic PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
53203955Srdivacky                                                  const char *&Beg,
54204643Srdivacky                                                  const char *E,
55208987Srdivacky                                                  unsigned &argIndex,
56243830Sdim                                                  const LangOptions &LO,
57243830Sdim                                                  const TargetInfo &Target) {
58203955Srdivacky
59212904Sdim  using namespace clang::analyze_format_string;
60203955Srdivacky  using namespace clang::analyze_printf;
61203955Srdivacky
62203955Srdivacky  const char *I = Beg;
63203955Srdivacky  const char *Start = 0;
64203955Srdivacky  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
65203955Srdivacky
66203955Srdivacky  // Look for a '%' character that indicates the start of a format specifier.
67203955Srdivacky  for ( ; I != E ; ++I) {
68203955Srdivacky    char c = *I;
69203955Srdivacky    if (c == '\0') {
70203955Srdivacky      // Detect spurious null characters, which are likely errors.
71203955Srdivacky      H.HandleNullChar(I);
72203955Srdivacky      return true;
73203955Srdivacky    }
74203955Srdivacky    if (c == '%') {
75203955Srdivacky      Start = I++;  // Record the start of the format specifier.
76203955Srdivacky      break;
77203955Srdivacky    }
78203955Srdivacky  }
79203955Srdivacky
80203955Srdivacky  // No format specifier found?
81203955Srdivacky  if (!Start)
82203955Srdivacky    return false;
83203955Srdivacky
84203955Srdivacky  if (I == E) {
85203955Srdivacky    // No more characters left?
86212904Sdim    H.HandleIncompleteSpecifier(Start, E - Start);
87203955Srdivacky    return true;
88203955Srdivacky  }
89203955Srdivacky
90212904Sdim  PrintfSpecifier FS;
91204643Srdivacky  if (ParseArgPosition(H, FS, Start, I, E))
92204643Srdivacky    return true;
93203955Srdivacky
94204643Srdivacky  if (I == E) {
95204643Srdivacky    // No more characters left?
96212904Sdim    H.HandleIncompleteSpecifier(Start, E - Start);
97204643Srdivacky    return true;
98204643Srdivacky  }
99204643Srdivacky
100203955Srdivacky  // Look for flags (if any).
101203955Srdivacky  bool hasMore = true;
102203955Srdivacky  for ( ; I != E; ++I) {
103203955Srdivacky    switch (*I) {
104203955Srdivacky      default: hasMore = false; break;
105218893Sdim      case '\'':
106218893Sdim        // FIXME: POSIX specific.  Always accept?
107218893Sdim        FS.setHasThousandsGrouping(I);
108218893Sdim        break;
109210299Sed      case '-': FS.setIsLeftJustified(I); break;
110210299Sed      case '+': FS.setHasPlusPrefix(I); break;
111210299Sed      case ' ': FS.setHasSpacePrefix(I); break;
112210299Sed      case '#': FS.setHasAlternativeForm(I); break;
113210299Sed      case '0': FS.setHasLeadingZeros(I); break;
114203955Srdivacky    }
115203955Srdivacky    if (!hasMore)
116203955Srdivacky      break;
117203955Srdivacky  }
118203955Srdivacky
119203955Srdivacky  if (I == E) {
120203955Srdivacky    // No more characters left?
121212904Sdim    H.HandleIncompleteSpecifier(Start, E - Start);
122203955Srdivacky    return true;
123203955Srdivacky  }
124203955Srdivacky
125203955Srdivacky  // Look for the field width (if any).
126204643Srdivacky  if (ParseFieldWidth(H, FS, Start, I, E,
127204643Srdivacky                      FS.usesPositionalArg() ? 0 : &argIndex))
128204643Srdivacky    return true;
129203955Srdivacky
130203955Srdivacky  if (I == E) {
131203955Srdivacky    // No more characters left?
132212904Sdim    H.HandleIncompleteSpecifier(Start, E - Start);
133203955Srdivacky    return true;
134203955Srdivacky  }
135203955Srdivacky
136203955Srdivacky  // Look for the precision (if any).
137203955Srdivacky  if (*I == '.') {
138203955Srdivacky    ++I;
139203955Srdivacky    if (I == E) {
140212904Sdim      H.HandleIncompleteSpecifier(Start, E - Start);
141203955Srdivacky      return true;
142203955Srdivacky    }
143203955Srdivacky
144204643Srdivacky    if (ParsePrecision(H, FS, Start, I, E,
145204643Srdivacky                       FS.usesPositionalArg() ? 0 : &argIndex))
146204643Srdivacky      return true;
147203955Srdivacky
148203955Srdivacky    if (I == E) {
149203955Srdivacky      // No more characters left?
150212904Sdim      H.HandleIncompleteSpecifier(Start, E - Start);
151203955Srdivacky      return true;
152203955Srdivacky    }
153203955Srdivacky  }
154203955Srdivacky
155203955Srdivacky  // Look for the length modifier.
156234353Sdim  if (ParseLengthModifier(FS, I, E, LO) && I == E) {
157203955Srdivacky    // No more characters left?
158212904Sdim    H.HandleIncompleteSpecifier(Start, E - Start);
159203955Srdivacky    return true;
160203955Srdivacky  }
161203955Srdivacky
162203955Srdivacky  if (*I == '\0') {
163203955Srdivacky    // Detect spurious null characters, which are likely errors.
164203955Srdivacky    H.HandleNullChar(I);
165203955Srdivacky    return true;
166203955Srdivacky  }
167203955Srdivacky
168203955Srdivacky  // Finally, look for the conversion specifier.
169203955Srdivacky  const char *conversionPosition = I++;
170203955Srdivacky  ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
171203955Srdivacky  switch (*conversionPosition) {
172203955Srdivacky    default:
173203955Srdivacky      break;
174203955Srdivacky    // C99: 7.19.6.1 (section 8).
175204643Srdivacky    case '%': k = ConversionSpecifier::PercentArg;   break;
176204643Srdivacky    case 'A': k = ConversionSpecifier::AArg; break;
177204643Srdivacky    case 'E': k = ConversionSpecifier::EArg; break;
178204643Srdivacky    case 'F': k = ConversionSpecifier::FArg; break;
179204643Srdivacky    case 'G': k = ConversionSpecifier::GArg; break;
180204643Srdivacky    case 'X': k = ConversionSpecifier::XArg; break;
181204643Srdivacky    case 'a': k = ConversionSpecifier::aArg; break;
182212904Sdim    case 'c': k = ConversionSpecifier::cArg; break;
183203955Srdivacky    case 'd': k = ConversionSpecifier::dArg; break;
184204643Srdivacky    case 'e': k = ConversionSpecifier::eArg; break;
185204643Srdivacky    case 'f': k = ConversionSpecifier::fArg; break;
186204643Srdivacky    case 'g': k = ConversionSpecifier::gArg; break;
187203955Srdivacky    case 'i': k = ConversionSpecifier::iArg; break;
188212904Sdim    case 'n': k = ConversionSpecifier::nArg; break;
189203955Srdivacky    case 'o': k = ConversionSpecifier::oArg; break;
190212904Sdim    case 'p': k = ConversionSpecifier::pArg;   break;
191212904Sdim    case 's': k = ConversionSpecifier::sArg;      break;
192203955Srdivacky    case 'u': k = ConversionSpecifier::uArg; break;
193203955Srdivacky    case 'x': k = ConversionSpecifier::xArg; break;
194218893Sdim    // POSIX specific.
195204643Srdivacky    case 'C': k = ConversionSpecifier::CArg; break;
196212904Sdim    case 'S': k = ConversionSpecifier::SArg; break;
197203955Srdivacky    // Objective-C.
198203955Srdivacky    case '@': k = ConversionSpecifier::ObjCObjArg; break;
199203955Srdivacky    // Glibc specific.
200203955Srdivacky    case 'm': k = ConversionSpecifier::PrintErrno; break;
201208987Srdivacky    // FreeBSD format extensions
202243830Sdim    case 'b':
203243830Sdim      if (LO.FormatExtensions)
204243830Sdim        k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
205243830Sdim      break;
206243830Sdim    case 'r':
207243830Sdim      if (LO.FormatExtensions)
208243830Sdim        k = ConversionSpecifier::FreeBSDrArg;
209243830Sdim      break;
210243830Sdim    case 'y':
211243830Sdim      if (LO.FormatExtensions)
212243830Sdim        k = ConversionSpecifier::iArg;
213243830Sdim      break;
214243830Sdim    // Apple-specific
215243830Sdim    case 'D':
216243830Sdim      if (Target.getTriple().isOSDarwin())
217243830Sdim        k = ConversionSpecifier::DArg;
218243830Sdim      else if (LO.FormatExtensions)
219243830Sdim        k = ConversionSpecifier::FreeBSDDArg; // u_char * followed by char *
220243830Sdim      break;
221243830Sdim    case 'O':
222243830Sdim      if (Target.getTriple().isOSDarwin())
223243830Sdim        k = ConversionSpecifier::OArg;
224243830Sdim      break;
225243830Sdim    case 'U':
226243830Sdim      if (Target.getTriple().isOSDarwin())
227243830Sdim        k = ConversionSpecifier::UArg;
228243830Sdim      break;
229203955Srdivacky  }
230212904Sdim  PrintfConversionSpecifier CS(conversionPosition, k);
231204643Srdivacky  FS.setConversionSpecifier(CS);
232204643Srdivacky  if (CS.consumesDataArgument() && !FS.usesPositionalArg())
233204643Srdivacky    FS.setArgIndex(argIndex++);
234208987Srdivacky  // FreeBSD extension
235243830Sdim  if (k == ConversionSpecifier::FreeBSDbArg ||
236243830Sdim      k == ConversionSpecifier::FreeBSDDArg)
237208987Srdivacky    argIndex++;
238203955Srdivacky
239203955Srdivacky  if (k == ConversionSpecifier::InvalidSpecifier) {
240204643Srdivacky    // Assume the conversion takes one argument.
241218893Sdim    return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, I - Start);
242203955Srdivacky  }
243212904Sdim  return PrintfSpecifierResult(Start, FS);
244203955Srdivacky}
245203955Srdivacky
246212904Sdimbool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
247212904Sdim                                                     const char *I,
248212904Sdim                                                     const char *E,
249243830Sdim                                                     const LangOptions &LO,
250243830Sdim                                                     const TargetInfo &Target) {
251204643Srdivacky
252204643Srdivacky  unsigned argIndex = 0;
253204643Srdivacky
254203955Srdivacky  // Keep looking for a format specifier until we have exhausted the string.
255203955Srdivacky  while (I != E) {
256212904Sdim    const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
257243830Sdim                                                            LO, Target);
258203955Srdivacky    // Did a fail-stop error of any kind occur when parsing the specifier?
259203955Srdivacky    // If so, don't do any more processing.
260203955Srdivacky    if (FSR.shouldStop())
261243830Sdim      return true;
262203955Srdivacky    // Did we exhaust the string or encounter an error that
263203955Srdivacky    // we can recover from?
264203955Srdivacky    if (!FSR.hasValue())
265203955Srdivacky      continue;
266203955Srdivacky    // We have a format specifier.  Pass it to the callback.
267212904Sdim    if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
268203955Srdivacky                                 I - FSR.getStart()))
269203955Srdivacky      return true;
270203955Srdivacky  }
271203955Srdivacky  assert(I == E && "Format string not exhausted");
272203955Srdivacky  return false;
273203955Srdivacky}
274203955Srdivacky
275203955Srdivacky//===----------------------------------------------------------------------===//
276212904Sdim// Methods on PrintfSpecifier.
277210299Sed//===----------------------------------------------------------------------===//
278210299Sed
279239462SdimArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
280239462Sdim                                    bool IsObjCLiteral) const {
281212904Sdim  const PrintfConversionSpecifier &CS = getConversionSpecifier();
282218893Sdim
283203955Srdivacky  if (!CS.consumesDataArgument())
284239462Sdim    return ArgType::Invalid();
285203955Srdivacky
286212904Sdim  if (CS.getKind() == ConversionSpecifier::cArg)
287212904Sdim    switch (LM.getKind()) {
288212904Sdim      case LengthModifier::None: return Ctx.IntTy;
289234353Sdim      case LengthModifier::AsLong:
290239462Sdim        return ArgType(ArgType::WIntTy, "wint_t");
291212904Sdim      default:
292239462Sdim        return ArgType::Invalid();
293212904Sdim    }
294218893Sdim
295203955Srdivacky  if (CS.isIntArg())
296210299Sed    switch (LM.getKind()) {
297210299Sed      case LengthModifier::AsLongDouble:
298234353Sdim        // GNU extension.
299234353Sdim        return Ctx.LongLongTy;
300210299Sed      case LengthModifier::None: return Ctx.IntTy;
301239462Sdim      case LengthModifier::AsChar: return ArgType::AnyCharTy;
302210299Sed      case LengthModifier::AsShort: return Ctx.ShortTy;
303210299Sed      case LengthModifier::AsLong: return Ctx.LongTy;
304234353Sdim      case LengthModifier::AsLongLong:
305234353Sdim      case LengthModifier::AsQuad:
306234353Sdim        return Ctx.LongLongTy;
307210299Sed      case LengthModifier::AsIntMax:
308239462Sdim        return ArgType(Ctx.getIntMaxType(), "intmax_t");
309234353Sdim      case LengthModifier::AsSizeT:
310234353Sdim        // FIXME: How to get the corresponding signed version of size_t?
311239462Sdim        return ArgType();
312234353Sdim      case LengthModifier::AsPtrDiff:
313239462Sdim        return ArgType(Ctx.getPointerDiffType(), "ptrdiff_t");
314234353Sdim      case LengthModifier::AsAllocate:
315234353Sdim      case LengthModifier::AsMAllocate:
316239462Sdim        return ArgType::Invalid();
317203955Srdivacky    }
318203955Srdivacky
319203955Srdivacky  if (CS.isUIntArg())
320210299Sed    switch (LM.getKind()) {
321210299Sed      case LengthModifier::AsLongDouble:
322234353Sdim        // GNU extension.
323234353Sdim        return Ctx.UnsignedLongLongTy;
324210299Sed      case LengthModifier::None: return Ctx.UnsignedIntTy;
325210299Sed      case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
326210299Sed      case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
327210299Sed      case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
328234353Sdim      case LengthModifier::AsLongLong:
329234353Sdim      case LengthModifier::AsQuad:
330234353Sdim        return Ctx.UnsignedLongLongTy;
331210299Sed      case LengthModifier::AsIntMax:
332239462Sdim        return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
333210299Sed      case LengthModifier::AsSizeT:
334239462Sdim        return ArgType(Ctx.getSizeType(), "size_t");
335210299Sed      case LengthModifier::AsPtrDiff:
336203955Srdivacky        // FIXME: How to get the corresponding unsigned
337203955Srdivacky        // version of ptrdiff_t?
338239462Sdim        return ArgType();
339234353Sdim      case LengthModifier::AsAllocate:
340234353Sdim      case LengthModifier::AsMAllocate:
341239462Sdim        return ArgType::Invalid();
342203955Srdivacky    }
343203955Srdivacky
344203955Srdivacky  if (CS.isDoubleArg()) {
345210299Sed    if (LM.getKind() == LengthModifier::AsLongDouble)
346203955Srdivacky      return Ctx.LongDoubleTy;
347203955Srdivacky    return Ctx.DoubleTy;
348203955Srdivacky  }
349203955Srdivacky
350239462Sdim  if (CS.getKind() == ConversionSpecifier::nArg) {
351239462Sdim    switch (LM.getKind()) {
352239462Sdim      case LengthModifier::None:
353239462Sdim        return ArgType::PtrTo(Ctx.IntTy);
354239462Sdim      case LengthModifier::AsChar:
355239462Sdim        return ArgType::PtrTo(Ctx.SignedCharTy);
356239462Sdim      case LengthModifier::AsShort:
357239462Sdim        return ArgType::PtrTo(Ctx.ShortTy);
358239462Sdim      case LengthModifier::AsLong:
359239462Sdim        return ArgType::PtrTo(Ctx.LongTy);
360239462Sdim      case LengthModifier::AsLongLong:
361239462Sdim      case LengthModifier::AsQuad:
362239462Sdim        return ArgType::PtrTo(Ctx.LongLongTy);
363239462Sdim      case LengthModifier::AsIntMax:
364239462Sdim        return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
365239462Sdim      case LengthModifier::AsSizeT:
366239462Sdim        return ArgType(); // FIXME: ssize_t
367239462Sdim      case LengthModifier::AsPtrDiff:
368239462Sdim        return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
369239462Sdim      case LengthModifier::AsLongDouble:
370239462Sdim        return ArgType(); // FIXME: Is this a known extension?
371239462Sdim      case LengthModifier::AsAllocate:
372239462Sdim      case LengthModifier::AsMAllocate:
373239462Sdim        return ArgType::Invalid();
374239462Sdim    }
375239462Sdim  }
376239462Sdim
377204643Srdivacky  switch (CS.getKind()) {
378212904Sdim    case ConversionSpecifier::sArg:
379234353Sdim      if (LM.getKind() == LengthModifier::AsWideChar) {
380234353Sdim        if (IsObjCLiteral)
381249423Sdim          return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
382249423Sdim                         "const unichar *");
383239462Sdim        return ArgType(ArgType::WCStrTy, "wchar_t *");
384234353Sdim      }
385239462Sdim      return ArgType::CStrTy;
386212904Sdim    case ConversionSpecifier::SArg:
387234353Sdim      if (IsObjCLiteral)
388249423Sdim        return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
389249423Sdim                       "const unichar *");
390239462Sdim      return ArgType(ArgType::WCStrTy, "wchar_t *");
391204643Srdivacky    case ConversionSpecifier::CArg:
392234353Sdim      if (IsObjCLiteral)
393249423Sdim        return ArgType(Ctx.UnsignedShortTy, "unichar");
394239462Sdim      return ArgType(Ctx.WCharTy, "wchar_t");
395212904Sdim    case ConversionSpecifier::pArg:
396239462Sdim      return ArgType::CPointerTy;
397234353Sdim    case ConversionSpecifier::ObjCObjArg:
398239462Sdim      return ArgType::ObjCPointerTy;
399204643Srdivacky    default:
400204643Srdivacky      break;
401204643Srdivacky  }
402203955Srdivacky
403203955Srdivacky  // FIXME: Handle other cases.
404239462Sdim  return ArgType();
405203955Srdivacky}
406203955Srdivacky
407234353Sdimbool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
408234353Sdim                              ASTContext &Ctx, bool IsObjCLiteral) {
409239462Sdim  // %n is different from other conversion specifiers; don't try to fix it.
410239462Sdim  if (CS.getKind() == ConversionSpecifier::nArg)
411239462Sdim    return false;
412239462Sdim
413239462Sdim  // Handle Objective-C objects first. Note that while the '%@' specifier will
414239462Sdim  // not warn for structure pointer or void pointer arguments (because that's
415239462Sdim  // how CoreFoundation objects are implemented), we only show a fixit for '%@'
416239462Sdim  // if we know it's an object (block, id, class, or __attribute__((NSObject))).
417239462Sdim  if (QT->isObjCRetainableType()) {
418239462Sdim    if (!IsObjCLiteral)
419239462Sdim      return false;
420239462Sdim
421239462Sdim    CS.setKind(ConversionSpecifier::ObjCObjArg);
422239462Sdim
423239462Sdim    // Disable irrelevant flags
424239462Sdim    HasThousandsGrouping = false;
425239462Sdim    HasPlusPrefix = false;
426239462Sdim    HasSpacePrefix = false;
427239462Sdim    HasAlternativeForm = false;
428239462Sdim    HasLeadingZeroes = false;
429239462Sdim    Precision.setHowSpecified(OptionalAmount::NotSpecified);
430239462Sdim    LM.setKind(LengthModifier::None);
431239462Sdim
432239462Sdim    return true;
433239462Sdim  }
434239462Sdim
435239462Sdim  // Handle strings next (char *, wchar_t *)
436210299Sed  if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
437212904Sdim    CS.setKind(ConversionSpecifier::sArg);
438210299Sed
439210299Sed    // Disable irrelevant flags
440210299Sed    HasAlternativeForm = 0;
441210299Sed    HasLeadingZeroes = 0;
442210299Sed
443210299Sed    // Set the long length modifier for wide characters
444210299Sed    if (QT->getPointeeType()->isWideCharType())
445210299Sed      LM.setKind(LengthModifier::AsWideChar);
446234353Sdim    else
447234353Sdim      LM.setKind(LengthModifier::None);
448210299Sed
449210299Sed    return true;
450210299Sed  }
451210299Sed
452239462Sdim  // If it's an enum, get its underlying type.
453239462Sdim  if (const EnumType *ETy = QT->getAs<EnumType>())
454239462Sdim    QT = ETy->getDecl()->getIntegerType();
455239462Sdim
456210299Sed  // We can only work with builtin types.
457234353Sdim  const BuiltinType *BT = QT->getAs<BuiltinType>();
458234353Sdim  if (!BT)
459210299Sed    return false;
460210299Sed
461210299Sed  // Set length modifier
462210299Sed  switch (BT->getKind()) {
463221345Sdim  case BuiltinType::Bool:
464221345Sdim  case BuiltinType::WChar_U:
465221345Sdim  case BuiltinType::WChar_S:
466221345Sdim  case BuiltinType::Char16:
467221345Sdim  case BuiltinType::Char32:
468221345Sdim  case BuiltinType::UInt128:
469221345Sdim  case BuiltinType::Int128:
470226633Sdim  case BuiltinType::Half:
471234353Sdim    // Various types which are non-trivial to correct.
472221345Sdim    return false;
473221345Sdim
474234353Sdim#define SIGNED_TYPE(Id, SingletonId)
475234353Sdim#define UNSIGNED_TYPE(Id, SingletonId)
476234353Sdim#define FLOATING_TYPE(Id, SingletonId)
477234353Sdim#define BUILTIN_TYPE(Id, SingletonId) \
478234353Sdim  case BuiltinType::Id:
479234353Sdim#include "clang/AST/BuiltinTypes.def"
480221345Sdim    // Misc other stuff which doesn't make sense here.
481221345Sdim    return false;
482221345Sdim
483221345Sdim  case BuiltinType::UInt:
484221345Sdim  case BuiltinType::Int:
485221345Sdim  case BuiltinType::Float:
486221345Sdim  case BuiltinType::Double:
487210299Sed    LM.setKind(LengthModifier::None);
488210299Sed    break;
489210299Sed
490218893Sdim  case BuiltinType::Char_U:
491218893Sdim  case BuiltinType::UChar:
492218893Sdim  case BuiltinType::Char_S:
493218893Sdim  case BuiltinType::SChar:
494218893Sdim    LM.setKind(LengthModifier::AsChar);
495218893Sdim    break;
496218893Sdim
497218893Sdim  case BuiltinType::Short:
498218893Sdim  case BuiltinType::UShort:
499218893Sdim    LM.setKind(LengthModifier::AsShort);
500218893Sdim    break;
501218893Sdim
502210299Sed  case BuiltinType::Long:
503210299Sed  case BuiltinType::ULong:
504210299Sed    LM.setKind(LengthModifier::AsLong);
505210299Sed    break;
506210299Sed
507210299Sed  case BuiltinType::LongLong:
508210299Sed  case BuiltinType::ULongLong:
509210299Sed    LM.setKind(LengthModifier::AsLongLong);
510210299Sed    break;
511210299Sed
512210299Sed  case BuiltinType::LongDouble:
513210299Sed    LM.setKind(LengthModifier::AsLongDouble);
514210299Sed    break;
515210299Sed  }
516210299Sed
517234353Sdim  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
518249423Sdim  if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
519239462Sdim    namedTypeToLengthModifier(QT, LM);
520234353Sdim
521249423Sdim  // If fixing the length modifier was enough, we might be done.
522243830Sdim  if (hasValidLengthModifier(Ctx.getTargetInfo())) {
523249423Sdim    // If we're going to offer a fix anyway, make sure the sign matches.
524249423Sdim    switch (CS.getKind()) {
525249423Sdim    case ConversionSpecifier::uArg:
526249423Sdim    case ConversionSpecifier::UArg:
527249423Sdim      if (QT->isSignedIntegerType())
528249423Sdim        CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
529249423Sdim      break;
530249423Sdim    case ConversionSpecifier::dArg:
531249423Sdim    case ConversionSpecifier::DArg:
532249423Sdim    case ConversionSpecifier::iArg:
533249423Sdim      if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
534249423Sdim        CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
535249423Sdim      break;
536249423Sdim    default:
537249423Sdim      // Other specifiers do not have signed/unsigned variants.
538249423Sdim      break;
539249423Sdim    }
540249423Sdim
541243830Sdim    const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
542243830Sdim    if (ATR.isValid() && ATR.matchesType(Ctx, QT))
543243830Sdim      return true;
544243830Sdim  }
545234353Sdim
546210299Sed  // Set conversion specifier and disable any flags which do not apply to it.
547218893Sdim  // Let typedefs to char fall through to int, as %c is silly for uint8_t.
548249423Sdim  if (!isa<TypedefType>(QT) && QT->isCharType()) {
549212904Sdim    CS.setKind(ConversionSpecifier::cArg);
550218893Sdim    LM.setKind(LengthModifier::None);
551210299Sed    Precision.setHowSpecified(OptionalAmount::NotSpecified);
552210299Sed    HasAlternativeForm = 0;
553210299Sed    HasLeadingZeroes = 0;
554210299Sed    HasPlusPrefix = 0;
555210299Sed  }
556210299Sed  // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
557210299Sed  else if (QT->isRealFloatingType()) {
558210299Sed    CS.setKind(ConversionSpecifier::fArg);
559210299Sed  }
560210299Sed  else if (QT->isSignedIntegerType()) {
561210299Sed    CS.setKind(ConversionSpecifier::dArg);
562210299Sed    HasAlternativeForm = 0;
563210299Sed  }
564210299Sed  else if (QT->isUnsignedIntegerType()) {
565234353Sdim    CS.setKind(ConversionSpecifier::uArg);
566210299Sed    HasAlternativeForm = 0;
567210299Sed    HasPlusPrefix = 0;
568226633Sdim  } else {
569226633Sdim    llvm_unreachable("Unexpected type");
570210299Sed  }
571210299Sed
572210299Sed  return true;
573210299Sed}
574210299Sed
575226633Sdimvoid PrintfSpecifier::toString(raw_ostream &os) const {
576210299Sed  // Whilst some features have no defined order, we are using the order
577218893Sdim  // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
578210299Sed  os << "%";
579210299Sed
580210299Sed  // Positional args
581210299Sed  if (usesPositionalArg()) {
582210299Sed    os << getPositionalArgIndex() << "$";
583210299Sed  }
584210299Sed
585210299Sed  // Conversion flags
586210299Sed  if (IsLeftJustified)    os << "-";
587210299Sed  if (HasPlusPrefix)      os << "+";
588210299Sed  if (HasSpacePrefix)     os << " ";
589210299Sed  if (HasAlternativeForm) os << "#";
590210299Sed  if (HasLeadingZeroes)   os << "0";
591210299Sed
592210299Sed  // Minimum field width
593210299Sed  FieldWidth.toString(os);
594210299Sed  // Precision
595210299Sed  Precision.toString(os);
596210299Sed  // Length modifier
597210299Sed  os << LM.toString();
598210299Sed  // Conversion specifier
599210299Sed  os << CS.toString();
600210299Sed}
601210299Sed
602212904Sdimbool PrintfSpecifier::hasValidPlusPrefix() const {
603210299Sed  if (!HasPlusPrefix)
604210299Sed    return true;
605210299Sed
606210299Sed  // The plus prefix only makes sense for signed conversions
607210299Sed  switch (CS.getKind()) {
608210299Sed  case ConversionSpecifier::dArg:
609243830Sdim  case ConversionSpecifier::DArg:
610210299Sed  case ConversionSpecifier::iArg:
611210299Sed  case ConversionSpecifier::fArg:
612210299Sed  case ConversionSpecifier::FArg:
613210299Sed  case ConversionSpecifier::eArg:
614210299Sed  case ConversionSpecifier::EArg:
615210299Sed  case ConversionSpecifier::gArg:
616210299Sed  case ConversionSpecifier::GArg:
617210299Sed  case ConversionSpecifier::aArg:
618210299Sed  case ConversionSpecifier::AArg:
619243830Sdim  case ConversionSpecifier::FreeBSDrArg:
620210299Sed    return true;
621210299Sed
622210299Sed  default:
623210299Sed    return false;
624210299Sed  }
625210299Sed}
626210299Sed
627212904Sdimbool PrintfSpecifier::hasValidAlternativeForm() const {
628210299Sed  if (!HasAlternativeForm)
629210299Sed    return true;
630210299Sed
631218893Sdim  // Alternate form flag only valid with the oxXaAeEfFgG conversions
632210299Sed  switch (CS.getKind()) {
633210299Sed  case ConversionSpecifier::oArg:
634243830Sdim  case ConversionSpecifier::OArg:
635210299Sed  case ConversionSpecifier::xArg:
636218893Sdim  case ConversionSpecifier::XArg:
637210299Sed  case ConversionSpecifier::aArg:
638210299Sed  case ConversionSpecifier::AArg:
639210299Sed  case ConversionSpecifier::eArg:
640210299Sed  case ConversionSpecifier::EArg:
641210299Sed  case ConversionSpecifier::fArg:
642210299Sed  case ConversionSpecifier::FArg:
643210299Sed  case ConversionSpecifier::gArg:
644210299Sed  case ConversionSpecifier::GArg:
645243830Sdim  case ConversionSpecifier::FreeBSDrArg:
646210299Sed    return true;
647210299Sed
648210299Sed  default:
649210299Sed    return false;
650210299Sed  }
651210299Sed}
652210299Sed
653212904Sdimbool PrintfSpecifier::hasValidLeadingZeros() const {
654210299Sed  if (!HasLeadingZeroes)
655210299Sed    return true;
656210299Sed
657210299Sed  // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
658210299Sed  switch (CS.getKind()) {
659210299Sed  case ConversionSpecifier::dArg:
660243830Sdim  case ConversionSpecifier::DArg:
661210299Sed  case ConversionSpecifier::iArg:
662210299Sed  case ConversionSpecifier::oArg:
663243830Sdim  case ConversionSpecifier::OArg:
664210299Sed  case ConversionSpecifier::uArg:
665243830Sdim  case ConversionSpecifier::UArg:
666210299Sed  case ConversionSpecifier::xArg:
667210299Sed  case ConversionSpecifier::XArg:
668210299Sed  case ConversionSpecifier::aArg:
669210299Sed  case ConversionSpecifier::AArg:
670210299Sed  case ConversionSpecifier::eArg:
671210299Sed  case ConversionSpecifier::EArg:
672210299Sed  case ConversionSpecifier::fArg:
673210299Sed  case ConversionSpecifier::FArg:
674210299Sed  case ConversionSpecifier::gArg:
675210299Sed  case ConversionSpecifier::GArg:
676210299Sed    return true;
677210299Sed
678210299Sed  default:
679210299Sed    return false;
680210299Sed  }
681210299Sed}
682210299Sed
683212904Sdimbool PrintfSpecifier::hasValidSpacePrefix() const {
684210299Sed  if (!HasSpacePrefix)
685210299Sed    return true;
686210299Sed
687210299Sed  // The space prefix only makes sense for signed conversions
688210299Sed  switch (CS.getKind()) {
689210299Sed  case ConversionSpecifier::dArg:
690243830Sdim  case ConversionSpecifier::DArg:
691210299Sed  case ConversionSpecifier::iArg:
692210299Sed  case ConversionSpecifier::fArg:
693210299Sed  case ConversionSpecifier::FArg:
694210299Sed  case ConversionSpecifier::eArg:
695210299Sed  case ConversionSpecifier::EArg:
696210299Sed  case ConversionSpecifier::gArg:
697210299Sed  case ConversionSpecifier::GArg:
698210299Sed  case ConversionSpecifier::aArg:
699210299Sed  case ConversionSpecifier::AArg:
700210299Sed    return true;
701210299Sed
702210299Sed  default:
703210299Sed    return false;
704210299Sed  }
705210299Sed}
706210299Sed
707212904Sdimbool PrintfSpecifier::hasValidLeftJustified() const {
708210299Sed  if (!IsLeftJustified)
709210299Sed    return true;
710210299Sed
711210299Sed  // The left justified flag is valid for all conversions except n
712210299Sed  switch (CS.getKind()) {
713212904Sdim  case ConversionSpecifier::nArg:
714210299Sed    return false;
715210299Sed
716210299Sed  default:
717210299Sed    return true;
718210299Sed  }
719210299Sed}
720210299Sed
721218893Sdimbool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
722218893Sdim  if (!HasThousandsGrouping)
723218893Sdim    return true;
724218893Sdim
725218893Sdim  switch (CS.getKind()) {
726218893Sdim    case ConversionSpecifier::dArg:
727243830Sdim    case ConversionSpecifier::DArg:
728218893Sdim    case ConversionSpecifier::iArg:
729218893Sdim    case ConversionSpecifier::uArg:
730243830Sdim    case ConversionSpecifier::UArg:
731218893Sdim    case ConversionSpecifier::fArg:
732218893Sdim    case ConversionSpecifier::FArg:
733218893Sdim    case ConversionSpecifier::gArg:
734218893Sdim    case ConversionSpecifier::GArg:
735218893Sdim      return true;
736218893Sdim    default:
737218893Sdim      return false;
738218893Sdim  }
739218893Sdim}
740218893Sdim
741212904Sdimbool PrintfSpecifier::hasValidPrecision() const {
742210299Sed  if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
743210299Sed    return true;
744210299Sed
745210299Sed  // Precision is only valid with the diouxXaAeEfFgGs conversions
746210299Sed  switch (CS.getKind()) {
747210299Sed  case ConversionSpecifier::dArg:
748243830Sdim  case ConversionSpecifier::DArg:
749210299Sed  case ConversionSpecifier::iArg:
750210299Sed  case ConversionSpecifier::oArg:
751243830Sdim  case ConversionSpecifier::OArg:
752210299Sed  case ConversionSpecifier::uArg:
753243830Sdim  case ConversionSpecifier::UArg:
754210299Sed  case ConversionSpecifier::xArg:
755210299Sed  case ConversionSpecifier::XArg:
756210299Sed  case ConversionSpecifier::aArg:
757210299Sed  case ConversionSpecifier::AArg:
758210299Sed  case ConversionSpecifier::eArg:
759210299Sed  case ConversionSpecifier::EArg:
760210299Sed  case ConversionSpecifier::fArg:
761210299Sed  case ConversionSpecifier::FArg:
762210299Sed  case ConversionSpecifier::gArg:
763210299Sed  case ConversionSpecifier::GArg:
764212904Sdim  case ConversionSpecifier::sArg:
765210299Sed    return true;
766210299Sed
767210299Sed  default:
768210299Sed    return false;
769210299Sed  }
770210299Sed}
771212904Sdimbool PrintfSpecifier::hasValidFieldWidth() const {
772210299Sed  if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
773210299Sed      return true;
774210299Sed
775210299Sed  // The field width is valid for all conversions except n
776210299Sed  switch (CS.getKind()) {
777212904Sdim  case ConversionSpecifier::nArg:
778210299Sed    return false;
779210299Sed
780210299Sed  default:
781210299Sed    return true;
782210299Sed  }
783210299Sed}
784