clang API Documentation

PrintfFormatString.cpp
Go to the documentation of this file.
00001 //== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // Handling of format string in printf and friends.  The structure of format
00011 // strings for fprintf() are described in C99 7.19.6.1.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "clang/Analysis/Analyses/FormatString.h"
00016 #include "FormatStringParsing.h"
00017 
00018 using clang::analyze_format_string::ArgTypeResult;
00019 using clang::analyze_format_string::FormatStringHandler;
00020 using clang::analyze_format_string::LengthModifier;
00021 using clang::analyze_format_string::OptionalAmount;
00022 using clang::analyze_format_string::ConversionSpecifier;
00023 using clang::analyze_printf::PrintfSpecifier;
00024 
00025 using namespace clang;
00026 
00027 typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
00028         PrintfSpecifierResult;
00029 
00030 //===----------------------------------------------------------------------===//
00031 // Methods for parsing format strings.
00032 //===----------------------------------------------------------------------===//
00033 
00034 using analyze_format_string::ParseNonPositionAmount;
00035 
00036 static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
00037                            const char *Start, const char *&Beg, const char *E,
00038                            unsigned *argIndex) {
00039   if (argIndex) {
00040     FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
00041   } else {
00042     const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
00043                                            analyze_format_string::PrecisionPos);
00044     if (Amt.isInvalid())
00045       return true;
00046     FS.setPrecision(Amt);
00047   }
00048   return false;
00049 }
00050 
00051 static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
00052                                                   const char *&Beg,
00053                                                   const char *E,
00054                                                   unsigned &argIndex,
00055                                                   const LangOptions &LO) {
00056 
00057   using namespace clang::analyze_format_string;
00058   using namespace clang::analyze_printf;
00059 
00060   const char *I = Beg;
00061   const char *Start = 0;
00062   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
00063 
00064   // Look for a '%' character that indicates the start of a format specifier.
00065   for ( ; I != E ; ++I) {
00066     char c = *I;
00067     if (c == '\0') {
00068       // Detect spurious null characters, which are likely errors.
00069       H.HandleNullChar(I);
00070       return true;
00071     }
00072     if (c == '%') {
00073       Start = I++;  // Record the start of the format specifier.
00074       break;
00075     }
00076   }
00077 
00078   // No format specifier found?
00079   if (!Start)
00080     return false;
00081 
00082   if (I == E) {
00083     // No more characters left?
00084     H.HandleIncompleteSpecifier(Start, E - Start);
00085     return true;
00086   }
00087 
00088   PrintfSpecifier FS;
00089   if (ParseArgPosition(H, FS, Start, I, E))
00090     return true;
00091 
00092   if (I == E) {
00093     // No more characters left?
00094     H.HandleIncompleteSpecifier(Start, E - Start);
00095     return true;
00096   }
00097 
00098   // Look for flags (if any).
00099   bool hasMore = true;
00100   for ( ; I != E; ++I) {
00101     switch (*I) {
00102       default: hasMore = false; break;
00103       case '\'':
00104         // FIXME: POSIX specific.  Always accept?
00105         FS.setHasThousandsGrouping(I);
00106         break;
00107       case '-': FS.setIsLeftJustified(I); break;
00108       case '+': FS.setHasPlusPrefix(I); break;
00109       case ' ': FS.setHasSpacePrefix(I); break;
00110       case '#': FS.setHasAlternativeForm(I); break;
00111       case '0': FS.setHasLeadingZeros(I); break;
00112     }
00113     if (!hasMore)
00114       break;
00115   }
00116 
00117   if (I == E) {
00118     // No more characters left?
00119     H.HandleIncompleteSpecifier(Start, E - Start);
00120     return true;
00121   }
00122 
00123   // Look for the field width (if any).
00124   if (ParseFieldWidth(H, FS, Start, I, E,
00125                       FS.usesPositionalArg() ? 0 : &argIndex))
00126     return true;
00127 
00128   if (I == E) {
00129     // No more characters left?
00130     H.HandleIncompleteSpecifier(Start, E - Start);
00131     return true;
00132   }
00133 
00134   // Look for the precision (if any).
00135   if (*I == '.') {
00136     ++I;
00137     if (I == E) {
00138       H.HandleIncompleteSpecifier(Start, E - Start);
00139       return true;
00140     }
00141 
00142     if (ParsePrecision(H, FS, Start, I, E,
00143                        FS.usesPositionalArg() ? 0 : &argIndex))
00144       return true;
00145 
00146     if (I == E) {
00147       // No more characters left?
00148       H.HandleIncompleteSpecifier(Start, E - Start);
00149       return true;
00150     }
00151   }
00152 
00153   // Look for the length modifier.
00154   if (ParseLengthModifier(FS, I, E, LO) && I == E) {
00155     // No more characters left?
00156     H.HandleIncompleteSpecifier(Start, E - Start);
00157     return true;
00158   }
00159 
00160   if (*I == '\0') {
00161     // Detect spurious null characters, which are likely errors.
00162     H.HandleNullChar(I);
00163     return true;
00164   }
00165 
00166   // Finally, look for the conversion specifier.
00167   const char *conversionPosition = I++;
00168   ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
00169   switch (*conversionPosition) {
00170     default:
00171       break;
00172     // C99: 7.19.6.1 (section 8).
00173     case '%': k = ConversionSpecifier::PercentArg;   break;
00174     case 'A': k = ConversionSpecifier::AArg; break;
00175     case 'E': k = ConversionSpecifier::EArg; break;
00176     case 'F': k = ConversionSpecifier::FArg; break;
00177     case 'G': k = ConversionSpecifier::GArg; break;
00178     case 'X': k = ConversionSpecifier::XArg; break;
00179     case 'a': k = ConversionSpecifier::aArg; break;
00180     case 'c': k = ConversionSpecifier::cArg; break;
00181     case 'd': k = ConversionSpecifier::dArg; break;
00182     case 'e': k = ConversionSpecifier::eArg; break;
00183     case 'f': k = ConversionSpecifier::fArg; break;
00184     case 'g': k = ConversionSpecifier::gArg; break;
00185     case 'i': k = ConversionSpecifier::iArg; break;
00186     case 'n': k = ConversionSpecifier::nArg; break;
00187     case 'o': k = ConversionSpecifier::oArg; break;
00188     case 'p': k = ConversionSpecifier::pArg;   break;
00189     case 's': k = ConversionSpecifier::sArg;      break;
00190     case 'u': k = ConversionSpecifier::uArg; break;
00191     case 'x': k = ConversionSpecifier::xArg; break;
00192     // POSIX specific.
00193     case 'C': k = ConversionSpecifier::CArg; break;
00194     case 'S': k = ConversionSpecifier::SArg; break;
00195     // Objective-C.
00196     case '@': k = ConversionSpecifier::ObjCObjArg; break;
00197     // Glibc specific.
00198     case 'm': k = ConversionSpecifier::PrintErrno; break;
00199   }
00200   PrintfConversionSpecifier CS(conversionPosition, k);
00201   FS.setConversionSpecifier(CS);
00202   if (CS.consumesDataArgument() && !FS.usesPositionalArg())
00203     FS.setArgIndex(argIndex++);
00204 
00205   if (k == ConversionSpecifier::InvalidSpecifier) {
00206     // Assume the conversion takes one argument.
00207     return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, I - Start);
00208   }
00209   return PrintfSpecifierResult(Start, FS);
00210 }
00211 
00212 bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
00213                                                      const char *I,
00214                                                      const char *E,
00215                                                      const LangOptions &LO) {
00216 
00217   unsigned argIndex = 0;
00218 
00219   // Keep looking for a format specifier until we have exhausted the string.
00220   while (I != E) {
00221     const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
00222                                                             LO);
00223     // Did a fail-stop error of any kind occur when parsing the specifier?
00224     // If so, don't do any more processing.
00225     if (FSR.shouldStop())
00226       return true;;
00227     // Did we exhaust the string or encounter an error that
00228     // we can recover from?
00229     if (!FSR.hasValue())
00230       continue;
00231     // We have a format specifier.  Pass it to the callback.
00232     if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
00233                                  I - FSR.getStart()))
00234       return true;
00235   }
00236   assert(I == E && "Format string not exhausted");
00237   return false;
00238 }
00239 
00240 //===----------------------------------------------------------------------===//
00241 // Methods on PrintfSpecifier.
00242 //===----------------------------------------------------------------------===//
00243 
00244 ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx,
00245                                           bool IsObjCLiteral) const {
00246   const PrintfConversionSpecifier &CS = getConversionSpecifier();
00247 
00248   if (!CS.consumesDataArgument())
00249     return ArgTypeResult::Invalid();
00250 
00251   if (CS.getKind() == ConversionSpecifier::cArg)
00252     switch (LM.getKind()) {
00253       case LengthModifier::None: return Ctx.IntTy;
00254       case LengthModifier::AsLong:
00255         return ArgTypeResult(ArgTypeResult::WIntTy, "wint_t");
00256       default:
00257         return ArgTypeResult::Invalid();
00258     }
00259 
00260   if (CS.isIntArg())
00261     switch (LM.getKind()) {
00262       case LengthModifier::AsLongDouble:
00263         // GNU extension.
00264         return Ctx.LongLongTy;
00265       case LengthModifier::None: return Ctx.IntTy;
00266       case LengthModifier::AsChar: return ArgTypeResult::AnyCharTy;
00267       case LengthModifier::AsShort: return Ctx.ShortTy;
00268       case LengthModifier::AsLong: return Ctx.LongTy;
00269       case LengthModifier::AsLongLong:
00270       case LengthModifier::AsQuad:
00271         return Ctx.LongLongTy;
00272       case LengthModifier::AsIntMax:
00273         return ArgTypeResult(Ctx.getIntMaxType(), "intmax_t");
00274       case LengthModifier::AsSizeT:
00275         // FIXME: How to get the corresponding signed version of size_t?
00276         return ArgTypeResult();
00277       case LengthModifier::AsPtrDiff:
00278         return ArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t");
00279       case LengthModifier::AsAllocate:
00280       case LengthModifier::AsMAllocate:
00281         return ArgTypeResult::Invalid();
00282     }
00283 
00284   if (CS.isUIntArg())
00285     switch (LM.getKind()) {
00286       case LengthModifier::AsLongDouble:
00287         // GNU extension.
00288         return Ctx.UnsignedLongLongTy;
00289       case LengthModifier::None: return Ctx.UnsignedIntTy;
00290       case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
00291       case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
00292       case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
00293       case LengthModifier::AsLongLong:
00294       case LengthModifier::AsQuad:
00295         return Ctx.UnsignedLongLongTy;
00296       case LengthModifier::AsIntMax:
00297         return ArgTypeResult(Ctx.getUIntMaxType(), "uintmax_t");
00298       case LengthModifier::AsSizeT:
00299         return ArgTypeResult(Ctx.getSizeType(), "size_t");
00300       case LengthModifier::AsPtrDiff:
00301         // FIXME: How to get the corresponding unsigned
00302         // version of ptrdiff_t?
00303         return ArgTypeResult();
00304       case LengthModifier::AsAllocate:
00305       case LengthModifier::AsMAllocate:
00306         return ArgTypeResult::Invalid();
00307     }
00308 
00309   if (CS.isDoubleArg()) {
00310     if (LM.getKind() == LengthModifier::AsLongDouble)
00311       return Ctx.LongDoubleTy;
00312     return Ctx.DoubleTy;
00313   }
00314 
00315   switch (CS.getKind()) {
00316     case ConversionSpecifier::sArg:
00317       if (LM.getKind() == LengthModifier::AsWideChar) {
00318         if (IsObjCLiteral)
00319           return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst());
00320         return ArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t *");
00321       }
00322       return ArgTypeResult::CStrTy;
00323     case ConversionSpecifier::SArg:
00324       if (IsObjCLiteral)
00325         return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst());
00326       return ArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t *");
00327     case ConversionSpecifier::CArg:
00328       if (IsObjCLiteral)
00329         return Ctx.UnsignedShortTy;
00330       return ArgTypeResult(Ctx.WCharTy, "wchar_t");
00331     case ConversionSpecifier::pArg:
00332       return ArgTypeResult::CPointerTy;
00333     case ConversionSpecifier::ObjCObjArg:
00334       return ArgTypeResult::ObjCPointerTy;
00335     default:
00336       break;
00337   }
00338 
00339   // FIXME: Handle other cases.
00340   return ArgTypeResult();
00341 }
00342 
00343 bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
00344                               ASTContext &Ctx, bool IsObjCLiteral) {
00345   // Handle strings first (char *, wchar_t *)
00346   if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
00347     CS.setKind(ConversionSpecifier::sArg);
00348 
00349     // Disable irrelevant flags
00350     HasAlternativeForm = 0;
00351     HasLeadingZeroes = 0;
00352 
00353     // Set the long length modifier for wide characters
00354     if (QT->getPointeeType()->isWideCharType())
00355       LM.setKind(LengthModifier::AsWideChar);
00356     else
00357       LM.setKind(LengthModifier::None);
00358 
00359     return true;
00360   }
00361 
00362   // We can only work with builtin types.
00363   const BuiltinType *BT = QT->getAs<BuiltinType>();
00364   if (!BT)
00365     return false;
00366 
00367   // Set length modifier
00368   switch (BT->getKind()) {
00369   case BuiltinType::Bool:
00370   case BuiltinType::WChar_U:
00371   case BuiltinType::WChar_S:
00372   case BuiltinType::Char16:
00373   case BuiltinType::Char32:
00374   case BuiltinType::UInt128:
00375   case BuiltinType::Int128:
00376   case BuiltinType::Half:
00377     // Various types which are non-trivial to correct.
00378     return false;
00379 
00380 #define SIGNED_TYPE(Id, SingletonId)
00381 #define UNSIGNED_TYPE(Id, SingletonId)
00382 #define FLOATING_TYPE(Id, SingletonId)
00383 #define BUILTIN_TYPE(Id, SingletonId) \
00384   case BuiltinType::Id:
00385 #include "clang/AST/BuiltinTypes.def"
00386     // Misc other stuff which doesn't make sense here.
00387     return false;
00388 
00389   case BuiltinType::UInt:
00390   case BuiltinType::Int:
00391   case BuiltinType::Float:
00392   case BuiltinType::Double:
00393     LM.setKind(LengthModifier::None);
00394     break;
00395 
00396   case BuiltinType::Char_U:
00397   case BuiltinType::UChar:
00398   case BuiltinType::Char_S:
00399   case BuiltinType::SChar:
00400     LM.setKind(LengthModifier::AsChar);
00401     break;
00402 
00403   case BuiltinType::Short:
00404   case BuiltinType::UShort:
00405     LM.setKind(LengthModifier::AsShort);
00406     break;
00407 
00408   case BuiltinType::Long:
00409   case BuiltinType::ULong:
00410     LM.setKind(LengthModifier::AsLong);
00411     break;
00412 
00413   case BuiltinType::LongLong:
00414   case BuiltinType::ULongLong:
00415     LM.setKind(LengthModifier::AsLongLong);
00416     break;
00417 
00418   case BuiltinType::LongDouble:
00419     LM.setKind(LengthModifier::AsLongDouble);
00420     break;
00421   }
00422 
00423   // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
00424   if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus0x)) {
00425     const IdentifierInfo *Identifier = QT.getBaseTypeIdentifier();
00426     if (Identifier->getName() == "size_t") {
00427       LM.setKind(LengthModifier::AsSizeT);
00428     } else if (Identifier->getName() == "ssize_t") {
00429       // Not C99, but common in Unix.
00430       LM.setKind(LengthModifier::AsSizeT);
00431     } else if (Identifier->getName() == "intmax_t") {
00432       LM.setKind(LengthModifier::AsIntMax);
00433     } else if (Identifier->getName() == "uintmax_t") {
00434       LM.setKind(LengthModifier::AsIntMax);
00435     } else if (Identifier->getName() == "ptrdiff_t") {
00436       LM.setKind(LengthModifier::AsPtrDiff);
00437     }
00438   }
00439 
00440   // If fixing the length modifier was enough, we are done.
00441   const analyze_printf::ArgTypeResult &ATR = getArgType(Ctx, IsObjCLiteral);
00442   if (hasValidLengthModifier() && ATR.isValid() && ATR.matchesType(Ctx, QT))
00443     return true;
00444 
00445   // Set conversion specifier and disable any flags which do not apply to it.
00446   // Let typedefs to char fall through to int, as %c is silly for uint8_t.
00447   if (isa<TypedefType>(QT) && QT->isAnyCharacterType()) {
00448     CS.setKind(ConversionSpecifier::cArg);
00449     LM.setKind(LengthModifier::None);
00450     Precision.setHowSpecified(OptionalAmount::NotSpecified);
00451     HasAlternativeForm = 0;
00452     HasLeadingZeroes = 0;
00453     HasPlusPrefix = 0;
00454   }
00455   // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
00456   else if (QT->isRealFloatingType()) {
00457     CS.setKind(ConversionSpecifier::fArg);
00458   }
00459   else if (QT->isSignedIntegerType()) {
00460     CS.setKind(ConversionSpecifier::dArg);
00461     HasAlternativeForm = 0;
00462   }
00463   else if (QT->isUnsignedIntegerType()) {
00464     CS.setKind(ConversionSpecifier::uArg);
00465     HasAlternativeForm = 0;
00466     HasPlusPrefix = 0;
00467   } else {
00468     llvm_unreachable("Unexpected type");
00469   }
00470 
00471   return true;
00472 }
00473 
00474 void PrintfSpecifier::toString(raw_ostream &os) const {
00475   // Whilst some features have no defined order, we are using the order
00476   // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
00477   os << "%";
00478 
00479   // Positional args
00480   if (usesPositionalArg()) {
00481     os << getPositionalArgIndex() << "$";
00482   }
00483 
00484   // Conversion flags
00485   if (IsLeftJustified)    os << "-";
00486   if (HasPlusPrefix)      os << "+";
00487   if (HasSpacePrefix)     os << " ";
00488   if (HasAlternativeForm) os << "#";
00489   if (HasLeadingZeroes)   os << "0";
00490 
00491   // Minimum field width
00492   FieldWidth.toString(os);
00493   // Precision
00494   Precision.toString(os);
00495   // Length modifier
00496   os << LM.toString();
00497   // Conversion specifier
00498   os << CS.toString();
00499 }
00500 
00501 bool PrintfSpecifier::hasValidPlusPrefix() const {
00502   if (!HasPlusPrefix)
00503     return true;
00504 
00505   // The plus prefix only makes sense for signed conversions
00506   switch (CS.getKind()) {
00507   case ConversionSpecifier::dArg:
00508   case ConversionSpecifier::iArg:
00509   case ConversionSpecifier::fArg:
00510   case ConversionSpecifier::FArg:
00511   case ConversionSpecifier::eArg:
00512   case ConversionSpecifier::EArg:
00513   case ConversionSpecifier::gArg:
00514   case ConversionSpecifier::GArg:
00515   case ConversionSpecifier::aArg:
00516   case ConversionSpecifier::AArg:
00517     return true;
00518 
00519   default:
00520     return false;
00521   }
00522 }
00523 
00524 bool PrintfSpecifier::hasValidAlternativeForm() const {
00525   if (!HasAlternativeForm)
00526     return true;
00527 
00528   // Alternate form flag only valid with the oxXaAeEfFgG conversions
00529   switch (CS.getKind()) {
00530   case ConversionSpecifier::oArg:
00531   case ConversionSpecifier::xArg:
00532   case ConversionSpecifier::XArg:
00533   case ConversionSpecifier::aArg:
00534   case ConversionSpecifier::AArg:
00535   case ConversionSpecifier::eArg:
00536   case ConversionSpecifier::EArg:
00537   case ConversionSpecifier::fArg:
00538   case ConversionSpecifier::FArg:
00539   case ConversionSpecifier::gArg:
00540   case ConversionSpecifier::GArg:
00541     return true;
00542 
00543   default:
00544     return false;
00545   }
00546 }
00547 
00548 bool PrintfSpecifier::hasValidLeadingZeros() const {
00549   if (!HasLeadingZeroes)
00550     return true;
00551 
00552   // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
00553   switch (CS.getKind()) {
00554   case ConversionSpecifier::dArg:
00555   case ConversionSpecifier::iArg:
00556   case ConversionSpecifier::oArg:
00557   case ConversionSpecifier::uArg:
00558   case ConversionSpecifier::xArg:
00559   case ConversionSpecifier::XArg:
00560   case ConversionSpecifier::aArg:
00561   case ConversionSpecifier::AArg:
00562   case ConversionSpecifier::eArg:
00563   case ConversionSpecifier::EArg:
00564   case ConversionSpecifier::fArg:
00565   case ConversionSpecifier::FArg:
00566   case ConversionSpecifier::gArg:
00567   case ConversionSpecifier::GArg:
00568     return true;
00569 
00570   default:
00571     return false;
00572   }
00573 }
00574 
00575 bool PrintfSpecifier::hasValidSpacePrefix() const {
00576   if (!HasSpacePrefix)
00577     return true;
00578 
00579   // The space prefix only makes sense for signed conversions
00580   switch (CS.getKind()) {
00581   case ConversionSpecifier::dArg:
00582   case ConversionSpecifier::iArg:
00583   case ConversionSpecifier::fArg:
00584   case ConversionSpecifier::FArg:
00585   case ConversionSpecifier::eArg:
00586   case ConversionSpecifier::EArg:
00587   case ConversionSpecifier::gArg:
00588   case ConversionSpecifier::GArg:
00589   case ConversionSpecifier::aArg:
00590   case ConversionSpecifier::AArg:
00591     return true;
00592 
00593   default:
00594     return false;
00595   }
00596 }
00597 
00598 bool PrintfSpecifier::hasValidLeftJustified() const {
00599   if (!IsLeftJustified)
00600     return true;
00601 
00602   // The left justified flag is valid for all conversions except n
00603   switch (CS.getKind()) {
00604   case ConversionSpecifier::nArg:
00605     return false;
00606 
00607   default:
00608     return true;
00609   }
00610 }
00611 
00612 bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
00613   if (!HasThousandsGrouping)
00614     return true;
00615 
00616   switch (CS.getKind()) {
00617     case ConversionSpecifier::dArg:
00618     case ConversionSpecifier::iArg:
00619     case ConversionSpecifier::uArg:
00620     case ConversionSpecifier::fArg:
00621     case ConversionSpecifier::FArg:
00622     case ConversionSpecifier::gArg:
00623     case ConversionSpecifier::GArg:
00624       return true;
00625     default:
00626       return false;
00627   }
00628 }
00629 
00630 bool PrintfSpecifier::hasValidPrecision() const {
00631   if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
00632     return true;
00633 
00634   // Precision is only valid with the diouxXaAeEfFgGs conversions
00635   switch (CS.getKind()) {
00636   case ConversionSpecifier::dArg:
00637   case ConversionSpecifier::iArg:
00638   case ConversionSpecifier::oArg:
00639   case ConversionSpecifier::uArg:
00640   case ConversionSpecifier::xArg:
00641   case ConversionSpecifier::XArg:
00642   case ConversionSpecifier::aArg:
00643   case ConversionSpecifier::AArg:
00644   case ConversionSpecifier::eArg:
00645   case ConversionSpecifier::EArg:
00646   case ConversionSpecifier::fArg:
00647   case ConversionSpecifier::FArg:
00648   case ConversionSpecifier::gArg:
00649   case ConversionSpecifier::GArg:
00650   case ConversionSpecifier::sArg:
00651     return true;
00652 
00653   default:
00654     return false;
00655   }
00656 }
00657 bool PrintfSpecifier::hasValidFieldWidth() const {
00658   if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
00659       return true;
00660 
00661   // The field width is valid for all conversions except n
00662   switch (CS.getKind()) {
00663   case ConversionSpecifier::nArg:
00664     return false;
00665 
00666   default:
00667     return true;
00668   }
00669 }