clang API Documentation
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 }