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