PrintfFormatString.cpp revision 2cd3440369d9241173e994485ddf2589a50a7d80
1//== PrintfFormatString.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/FormatString.h"
16#include "FormatStringParsing.h"
17#include "clang/Basic/TargetInfo.h"
18
19using clang::analyze_format_string::ArgType;
20using clang::analyze_format_string::FormatStringHandler;
21using clang::analyze_format_string::LengthModifier;
22using clang::analyze_format_string::OptionalAmount;
23using clang::analyze_format_string::ConversionSpecifier;
24using clang::analyze_printf::PrintfSpecifier;
25
26using namespace clang;
27
28typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
29        PrintfSpecifierResult;
30
31//===----------------------------------------------------------------------===//
32// Methods for parsing format strings.
33//===----------------------------------------------------------------------===//
34
35using analyze_format_string::ParseNonPositionAmount;
36
37static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
38                           const char *Start, const char *&Beg, const char *E,
39                           unsigned *argIndex) {
40  if (argIndex) {
41    FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
42  } else {
43    const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
44                                           analyze_format_string::PrecisionPos);
45    if (Amt.isInvalid())
46      return true;
47    FS.setPrecision(Amt);
48  }
49  return false;
50}
51
52static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
53                                                  const char *&Beg,
54                                                  const char *E,
55                                                  unsigned &argIndex,
56                                                  const LangOptions &LO,
57                                                  const TargetInfo &Target) {
58
59  using namespace clang::analyze_format_string;
60  using namespace clang::analyze_printf;
61
62  const char *I = Beg;
63  const char *Start = 0;
64  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
65
66  // Look for a '%' character that indicates the start of a format specifier.
67  for ( ; I != E ; ++I) {
68    char c = *I;
69    if (c == '\0') {
70      // Detect spurious null characters, which are likely errors.
71      H.HandleNullChar(I);
72      return true;
73    }
74    if (c == '%') {
75      Start = I++;  // Record the start of the format specifier.
76      break;
77    }
78  }
79
80  // No format specifier found?
81  if (!Start)
82    return false;
83
84  if (I == E) {
85    // No more characters left?
86    H.HandleIncompleteSpecifier(Start, E - Start);
87    return true;
88  }
89
90  PrintfSpecifier FS;
91  if (ParseArgPosition(H, FS, Start, I, E))
92    return true;
93
94  if (I == E) {
95    // No more characters left?
96    H.HandleIncompleteSpecifier(Start, E - Start);
97    return true;
98  }
99
100  // Look for flags (if any).
101  bool hasMore = true;
102  for ( ; I != E; ++I) {
103    switch (*I) {
104      default: hasMore = false; break;
105      case '\'':
106        // FIXME: POSIX specific.  Always accept?
107        FS.setHasThousandsGrouping(I);
108        break;
109      case '-': FS.setIsLeftJustified(I); break;
110      case '+': FS.setHasPlusPrefix(I); break;
111      case ' ': FS.setHasSpacePrefix(I); break;
112      case '#': FS.setHasAlternativeForm(I); break;
113      case '0': FS.setHasLeadingZeros(I); break;
114    }
115    if (!hasMore)
116      break;
117  }
118
119  if (I == E) {
120    // No more characters left?
121    H.HandleIncompleteSpecifier(Start, E - Start);
122    return true;
123  }
124
125  // Look for the field width (if any).
126  if (ParseFieldWidth(H, FS, Start, I, E,
127                      FS.usesPositionalArg() ? 0 : &argIndex))
128    return true;
129
130  if (I == E) {
131    // No more characters left?
132    H.HandleIncompleteSpecifier(Start, E - Start);
133    return true;
134  }
135
136  // Look for the precision (if any).
137  if (*I == '.') {
138    ++I;
139    if (I == E) {
140      H.HandleIncompleteSpecifier(Start, E - Start);
141      return true;
142    }
143
144    if (ParsePrecision(H, FS, Start, I, E,
145                       FS.usesPositionalArg() ? 0 : &argIndex))
146      return true;
147
148    if (I == E) {
149      // No more characters left?
150      H.HandleIncompleteSpecifier(Start, E - Start);
151      return true;
152    }
153  }
154
155  // Look for the length modifier.
156  if (ParseLengthModifier(FS, I, E, LO) && I == E) {
157    // No more characters left?
158    H.HandleIncompleteSpecifier(Start, E - Start);
159    return true;
160  }
161
162  if (*I == '\0') {
163    // Detect spurious null characters, which are likely errors.
164    H.HandleNullChar(I);
165    return true;
166  }
167
168  // Finally, look for the conversion specifier.
169  const char *conversionPosition = I++;
170  ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
171  switch (*conversionPosition) {
172    default:
173      break;
174    // C99: 7.19.6.1 (section 8).
175    case '%': k = ConversionSpecifier::PercentArg;   break;
176    case 'A': k = ConversionSpecifier::AArg; break;
177    case 'E': k = ConversionSpecifier::EArg; break;
178    case 'F': k = ConversionSpecifier::FArg; break;
179    case 'G': k = ConversionSpecifier::GArg; break;
180    case 'X': k = ConversionSpecifier::XArg; break;
181    case 'a': k = ConversionSpecifier::aArg; break;
182    case 'c': k = ConversionSpecifier::cArg; break;
183    case 'd': k = ConversionSpecifier::dArg; break;
184    case 'e': k = ConversionSpecifier::eArg; break;
185    case 'f': k = ConversionSpecifier::fArg; break;
186    case 'g': k = ConversionSpecifier::gArg; break;
187    case 'i': k = ConversionSpecifier::iArg; break;
188    case 'n': k = ConversionSpecifier::nArg; break;
189    case 'o': k = ConversionSpecifier::oArg; break;
190    case 'p': k = ConversionSpecifier::pArg;   break;
191    case 's': k = ConversionSpecifier::sArg;      break;
192    case 'u': k = ConversionSpecifier::uArg; break;
193    case 'x': k = ConversionSpecifier::xArg; break;
194    // POSIX specific.
195    case 'C': k = ConversionSpecifier::CArg; break;
196    case 'S': k = ConversionSpecifier::SArg; break;
197    // Objective-C.
198    case '@': k = ConversionSpecifier::ObjCObjArg; break;
199    // Glibc specific.
200    case 'm': k = ConversionSpecifier::PrintErrno; break;
201    // Apple-specific
202    case 'D':
203      if (Target.getTriple().isOSDarwin())
204        k = ConversionSpecifier::DArg;
205      break;
206    case 'O':
207      if (Target.getTriple().isOSDarwin())
208        k = ConversionSpecifier::OArg;
209      break;
210    case 'U':
211      if (Target.getTriple().isOSDarwin())
212        k = ConversionSpecifier::UArg;
213      break;
214  }
215  PrintfConversionSpecifier CS(conversionPosition, k);
216  FS.setConversionSpecifier(CS);
217  if (CS.consumesDataArgument() && !FS.usesPositionalArg())
218    FS.setArgIndex(argIndex++);
219
220  if (k == ConversionSpecifier::InvalidSpecifier) {
221    // Assume the conversion takes one argument.
222    return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, I - Start);
223  }
224  return PrintfSpecifierResult(Start, FS);
225}
226
227bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
228                                                     const char *I,
229                                                     const char *E,
230                                                     const LangOptions &LO,
231                                                     const TargetInfo &Target) {
232
233  unsigned argIndex = 0;
234
235  // Keep looking for a format specifier until we have exhausted the string.
236  while (I != E) {
237    const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
238                                                            LO, Target);
239    // Did a fail-stop error of any kind occur when parsing the specifier?
240    // If so, don't do any more processing.
241    if (FSR.shouldStop())
242      return true;
243    // Did we exhaust the string or encounter an error that
244    // we can recover from?
245    if (!FSR.hasValue())
246      continue;
247    // We have a format specifier.  Pass it to the callback.
248    if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
249                                 I - FSR.getStart()))
250      return true;
251  }
252  assert(I == E && "Format string not exhausted");
253  return false;
254}
255
256//===----------------------------------------------------------------------===//
257// Methods on PrintfSpecifier.
258//===----------------------------------------------------------------------===//
259
260ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
261                                    bool IsObjCLiteral) const {
262  const PrintfConversionSpecifier &CS = getConversionSpecifier();
263
264  if (!CS.consumesDataArgument())
265    return ArgType::Invalid();
266
267  if (CS.getKind() == ConversionSpecifier::cArg)
268    switch (LM.getKind()) {
269      case LengthModifier::None: return Ctx.IntTy;
270      case LengthModifier::AsLong:
271        return ArgType(ArgType::WIntTy, "wint_t");
272      default:
273        return ArgType::Invalid();
274    }
275
276  if (CS.isIntArg())
277    switch (LM.getKind()) {
278      case LengthModifier::AsLongDouble:
279        // GNU extension.
280        return Ctx.LongLongTy;
281      case LengthModifier::None: return Ctx.IntTy;
282      case LengthModifier::AsChar: return ArgType::AnyCharTy;
283      case LengthModifier::AsShort: return Ctx.ShortTy;
284      case LengthModifier::AsLong: return Ctx.LongTy;
285      case LengthModifier::AsLongLong:
286      case LengthModifier::AsQuad:
287        return Ctx.LongLongTy;
288      case LengthModifier::AsIntMax:
289        return ArgType(Ctx.getIntMaxType(), "intmax_t");
290      case LengthModifier::AsSizeT:
291        // FIXME: How to get the corresponding signed version of size_t?
292        return ArgType();
293      case LengthModifier::AsPtrDiff:
294        return ArgType(Ctx.getPointerDiffType(), "ptrdiff_t");
295      case LengthModifier::AsAllocate:
296      case LengthModifier::AsMAllocate:
297        return ArgType::Invalid();
298    }
299
300  if (CS.isUIntArg())
301    switch (LM.getKind()) {
302      case LengthModifier::AsLongDouble:
303        // GNU extension.
304        return Ctx.UnsignedLongLongTy;
305      case LengthModifier::None: return Ctx.UnsignedIntTy;
306      case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
307      case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
308      case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
309      case LengthModifier::AsLongLong:
310      case LengthModifier::AsQuad:
311        return Ctx.UnsignedLongLongTy;
312      case LengthModifier::AsIntMax:
313        return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
314      case LengthModifier::AsSizeT:
315        return ArgType(Ctx.getSizeType(), "size_t");
316      case LengthModifier::AsPtrDiff:
317        // FIXME: How to get the corresponding unsigned
318        // version of ptrdiff_t?
319        return ArgType();
320      case LengthModifier::AsAllocate:
321      case LengthModifier::AsMAllocate:
322        return ArgType::Invalid();
323    }
324
325  if (CS.isDoubleArg()) {
326    if (LM.getKind() == LengthModifier::AsLongDouble)
327      return Ctx.LongDoubleTy;
328    return Ctx.DoubleTy;
329  }
330
331  if (CS.getKind() == ConversionSpecifier::nArg) {
332    switch (LM.getKind()) {
333      case LengthModifier::None:
334        return ArgType::PtrTo(Ctx.IntTy);
335      case LengthModifier::AsChar:
336        return ArgType::PtrTo(Ctx.SignedCharTy);
337      case LengthModifier::AsShort:
338        return ArgType::PtrTo(Ctx.ShortTy);
339      case LengthModifier::AsLong:
340        return ArgType::PtrTo(Ctx.LongTy);
341      case LengthModifier::AsLongLong:
342      case LengthModifier::AsQuad:
343        return ArgType::PtrTo(Ctx.LongLongTy);
344      case LengthModifier::AsIntMax:
345        return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
346      case LengthModifier::AsSizeT:
347        return ArgType(); // FIXME: ssize_t
348      case LengthModifier::AsPtrDiff:
349        return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
350      case LengthModifier::AsLongDouble:
351        return ArgType(); // FIXME: Is this a known extension?
352      case LengthModifier::AsAllocate:
353      case LengthModifier::AsMAllocate:
354        return ArgType::Invalid();
355    }
356  }
357
358  switch (CS.getKind()) {
359    case ConversionSpecifier::sArg:
360      if (LM.getKind() == LengthModifier::AsWideChar) {
361        if (IsObjCLiteral)
362          return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
363                         "const unichar *");
364        return ArgType(ArgType::WCStrTy, "wchar_t *");
365      }
366      return ArgType::CStrTy;
367    case ConversionSpecifier::SArg:
368      if (IsObjCLiteral)
369        return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
370                       "const unichar *");
371      return ArgType(ArgType::WCStrTy, "wchar_t *");
372    case ConversionSpecifier::CArg:
373      if (IsObjCLiteral)
374        return ArgType(Ctx.UnsignedShortTy, "unichar");
375      return ArgType(Ctx.WCharTy, "wchar_t");
376    case ConversionSpecifier::pArg:
377      return ArgType::CPointerTy;
378    case ConversionSpecifier::ObjCObjArg:
379      return ArgType::ObjCPointerTy;
380    default:
381      break;
382  }
383
384  // FIXME: Handle other cases.
385  return ArgType();
386}
387
388bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
389                              ASTContext &Ctx, bool IsObjCLiteral) {
390  // %n is different from other conversion specifiers; don't try to fix it.
391  if (CS.getKind() == ConversionSpecifier::nArg)
392    return false;
393
394  // Handle Objective-C objects first. Note that while the '%@' specifier will
395  // not warn for structure pointer or void pointer arguments (because that's
396  // how CoreFoundation objects are implemented), we only show a fixit for '%@'
397  // if we know it's an object (block, id, class, or __attribute__((NSObject))).
398  if (QT->isObjCRetainableType()) {
399    if (!IsObjCLiteral)
400      return false;
401
402    CS.setKind(ConversionSpecifier::ObjCObjArg);
403
404    // Disable irrelevant flags
405    HasThousandsGrouping = false;
406    HasPlusPrefix = false;
407    HasSpacePrefix = false;
408    HasAlternativeForm = false;
409    HasLeadingZeroes = false;
410    Precision.setHowSpecified(OptionalAmount::NotSpecified);
411    LM.setKind(LengthModifier::None);
412
413    return true;
414  }
415
416  // Handle strings next (char *, wchar_t *)
417  if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
418    CS.setKind(ConversionSpecifier::sArg);
419
420    // Disable irrelevant flags
421    HasAlternativeForm = 0;
422    HasLeadingZeroes = 0;
423
424    // Set the long length modifier for wide characters
425    if (QT->getPointeeType()->isWideCharType())
426      LM.setKind(LengthModifier::AsWideChar);
427    else
428      LM.setKind(LengthModifier::None);
429
430    return true;
431  }
432
433  // If it's an enum, get its underlying type.
434  if (const EnumType *ETy = QT->getAs<EnumType>())
435    QT = ETy->getDecl()->getIntegerType();
436
437  // We can only work with builtin types.
438  const BuiltinType *BT = QT->getAs<BuiltinType>();
439  if (!BT)
440    return false;
441
442  // Set length modifier
443  switch (BT->getKind()) {
444  case BuiltinType::Bool:
445  case BuiltinType::WChar_U:
446  case BuiltinType::WChar_S:
447  case BuiltinType::Char16:
448  case BuiltinType::Char32:
449  case BuiltinType::UInt128:
450  case BuiltinType::Int128:
451  case BuiltinType::Half:
452    // Various types which are non-trivial to correct.
453    return false;
454
455#define SIGNED_TYPE(Id, SingletonId)
456#define UNSIGNED_TYPE(Id, SingletonId)
457#define FLOATING_TYPE(Id, SingletonId)
458#define BUILTIN_TYPE(Id, SingletonId) \
459  case BuiltinType::Id:
460#include "clang/AST/BuiltinTypes.def"
461    // Misc other stuff which doesn't make sense here.
462    return false;
463
464  case BuiltinType::UInt:
465  case BuiltinType::Int:
466  case BuiltinType::Float:
467  case BuiltinType::Double:
468    LM.setKind(LengthModifier::None);
469    break;
470
471  case BuiltinType::Char_U:
472  case BuiltinType::UChar:
473  case BuiltinType::Char_S:
474  case BuiltinType::SChar:
475    LM.setKind(LengthModifier::AsChar);
476    break;
477
478  case BuiltinType::Short:
479  case BuiltinType::UShort:
480    LM.setKind(LengthModifier::AsShort);
481    break;
482
483  case BuiltinType::Long:
484  case BuiltinType::ULong:
485    LM.setKind(LengthModifier::AsLong);
486    break;
487
488  case BuiltinType::LongLong:
489  case BuiltinType::ULongLong:
490    LM.setKind(LengthModifier::AsLongLong);
491    break;
492
493  case BuiltinType::LongDouble:
494    LM.setKind(LengthModifier::AsLongDouble);
495    break;
496  }
497
498  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
499  if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus0x))
500    namedTypeToLengthModifier(QT, LM);
501
502  // If fixing the length modifier was enough, we are done.
503  if (hasValidLengthModifier(Ctx.getTargetInfo())) {
504    const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
505    if (ATR.isValid() && ATR.matchesType(Ctx, QT))
506      return true;
507  }
508
509  // Set conversion specifier and disable any flags which do not apply to it.
510  // Let typedefs to char fall through to int, as %c is silly for uint8_t.
511  if (!isa<TypedefType>(QT) && QT->isCharType()) {
512    CS.setKind(ConversionSpecifier::cArg);
513    LM.setKind(LengthModifier::None);
514    Precision.setHowSpecified(OptionalAmount::NotSpecified);
515    HasAlternativeForm = 0;
516    HasLeadingZeroes = 0;
517    HasPlusPrefix = 0;
518  }
519  // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
520  else if (QT->isRealFloatingType()) {
521    CS.setKind(ConversionSpecifier::fArg);
522  }
523  else if (QT->isSignedIntegerType()) {
524    CS.setKind(ConversionSpecifier::dArg);
525    HasAlternativeForm = 0;
526  }
527  else if (QT->isUnsignedIntegerType()) {
528    CS.setKind(ConversionSpecifier::uArg);
529    HasAlternativeForm = 0;
530    HasPlusPrefix = 0;
531  } else {
532    llvm_unreachable("Unexpected type");
533  }
534
535  return true;
536}
537
538void PrintfSpecifier::toString(raw_ostream &os) const {
539  // Whilst some features have no defined order, we are using the order
540  // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
541  os << "%";
542
543  // Positional args
544  if (usesPositionalArg()) {
545    os << getPositionalArgIndex() << "$";
546  }
547
548  // Conversion flags
549  if (IsLeftJustified)    os << "-";
550  if (HasPlusPrefix)      os << "+";
551  if (HasSpacePrefix)     os << " ";
552  if (HasAlternativeForm) os << "#";
553  if (HasLeadingZeroes)   os << "0";
554
555  // Minimum field width
556  FieldWidth.toString(os);
557  // Precision
558  Precision.toString(os);
559  // Length modifier
560  os << LM.toString();
561  // Conversion specifier
562  os << CS.toString();
563}
564
565bool PrintfSpecifier::hasValidPlusPrefix() const {
566  if (!HasPlusPrefix)
567    return true;
568
569  // The plus prefix only makes sense for signed conversions
570  switch (CS.getKind()) {
571  case ConversionSpecifier::dArg:
572  case ConversionSpecifier::DArg:
573  case ConversionSpecifier::iArg:
574  case ConversionSpecifier::fArg:
575  case ConversionSpecifier::FArg:
576  case ConversionSpecifier::eArg:
577  case ConversionSpecifier::EArg:
578  case ConversionSpecifier::gArg:
579  case ConversionSpecifier::GArg:
580  case ConversionSpecifier::aArg:
581  case ConversionSpecifier::AArg:
582    return true;
583
584  default:
585    return false;
586  }
587}
588
589bool PrintfSpecifier::hasValidAlternativeForm() const {
590  if (!HasAlternativeForm)
591    return true;
592
593  // Alternate form flag only valid with the oxXaAeEfFgG conversions
594  switch (CS.getKind()) {
595  case ConversionSpecifier::oArg:
596  case ConversionSpecifier::OArg:
597  case ConversionSpecifier::xArg:
598  case ConversionSpecifier::XArg:
599  case ConversionSpecifier::aArg:
600  case ConversionSpecifier::AArg:
601  case ConversionSpecifier::eArg:
602  case ConversionSpecifier::EArg:
603  case ConversionSpecifier::fArg:
604  case ConversionSpecifier::FArg:
605  case ConversionSpecifier::gArg:
606  case ConversionSpecifier::GArg:
607    return true;
608
609  default:
610    return false;
611  }
612}
613
614bool PrintfSpecifier::hasValidLeadingZeros() const {
615  if (!HasLeadingZeroes)
616    return true;
617
618  // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
619  switch (CS.getKind()) {
620  case ConversionSpecifier::dArg:
621  case ConversionSpecifier::DArg:
622  case ConversionSpecifier::iArg:
623  case ConversionSpecifier::oArg:
624  case ConversionSpecifier::OArg:
625  case ConversionSpecifier::uArg:
626  case ConversionSpecifier::UArg:
627  case ConversionSpecifier::xArg:
628  case ConversionSpecifier::XArg:
629  case ConversionSpecifier::aArg:
630  case ConversionSpecifier::AArg:
631  case ConversionSpecifier::eArg:
632  case ConversionSpecifier::EArg:
633  case ConversionSpecifier::fArg:
634  case ConversionSpecifier::FArg:
635  case ConversionSpecifier::gArg:
636  case ConversionSpecifier::GArg:
637    return true;
638
639  default:
640    return false;
641  }
642}
643
644bool PrintfSpecifier::hasValidSpacePrefix() const {
645  if (!HasSpacePrefix)
646    return true;
647
648  // The space prefix only makes sense for signed conversions
649  switch (CS.getKind()) {
650  case ConversionSpecifier::dArg:
651  case ConversionSpecifier::DArg:
652  case ConversionSpecifier::iArg:
653  case ConversionSpecifier::fArg:
654  case ConversionSpecifier::FArg:
655  case ConversionSpecifier::eArg:
656  case ConversionSpecifier::EArg:
657  case ConversionSpecifier::gArg:
658  case ConversionSpecifier::GArg:
659  case ConversionSpecifier::aArg:
660  case ConversionSpecifier::AArg:
661    return true;
662
663  default:
664    return false;
665  }
666}
667
668bool PrintfSpecifier::hasValidLeftJustified() const {
669  if (!IsLeftJustified)
670    return true;
671
672  // The left justified flag is valid for all conversions except n
673  switch (CS.getKind()) {
674  case ConversionSpecifier::nArg:
675    return false;
676
677  default:
678    return true;
679  }
680}
681
682bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
683  if (!HasThousandsGrouping)
684    return true;
685
686  switch (CS.getKind()) {
687    case ConversionSpecifier::dArg:
688    case ConversionSpecifier::DArg:
689    case ConversionSpecifier::iArg:
690    case ConversionSpecifier::uArg:
691    case ConversionSpecifier::UArg:
692    case ConversionSpecifier::fArg:
693    case ConversionSpecifier::FArg:
694    case ConversionSpecifier::gArg:
695    case ConversionSpecifier::GArg:
696      return true;
697    default:
698      return false;
699  }
700}
701
702bool PrintfSpecifier::hasValidPrecision() const {
703  if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
704    return true;
705
706  // Precision is only valid with the diouxXaAeEfFgGs conversions
707  switch (CS.getKind()) {
708  case ConversionSpecifier::dArg:
709  case ConversionSpecifier::DArg:
710  case ConversionSpecifier::iArg:
711  case ConversionSpecifier::oArg:
712  case ConversionSpecifier::OArg:
713  case ConversionSpecifier::uArg:
714  case ConversionSpecifier::UArg:
715  case ConversionSpecifier::xArg:
716  case ConversionSpecifier::XArg:
717  case ConversionSpecifier::aArg:
718  case ConversionSpecifier::AArg:
719  case ConversionSpecifier::eArg:
720  case ConversionSpecifier::EArg:
721  case ConversionSpecifier::fArg:
722  case ConversionSpecifier::FArg:
723  case ConversionSpecifier::gArg:
724  case ConversionSpecifier::GArg:
725  case ConversionSpecifier::sArg:
726    return true;
727
728  default:
729    return false;
730  }
731}
732bool PrintfSpecifier::hasValidFieldWidth() const {
733  if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
734      return true;
735
736  // The field width is valid for all conversions except n
737  switch (CS.getKind()) {
738  case ConversionSpecifier::nArg:
739    return false;
740
741  default:
742    return true;
743  }
744}
745