1 //= FormatString.h - Analysis of printf/fprintf 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 // This file defines APIs for analyzing the format strings of printf, fscanf, 11 // and friends. 12 // 13 // The structure of format strings for fprintf are described in C99 7.19.6.1. 14 // 15 // The structure of format strings for fscanf are described in C99 7.19.6.2. 16 // 17 //===----------------------------------------------------------------------===// 18 19 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H 20 #define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H 21 22 #include "clang/AST/CanonicalType.h" 23 24 namespace clang { 25 26 class TargetInfo; 27 28 //===----------------------------------------------------------------------===// 29 /// Common components of both fprintf and fscanf format strings. 30 namespace analyze_format_string { 31 32 /// Class representing optional flags with location and representation 33 /// information. 34 class OptionalFlag { 35 public: OptionalFlag(const char * Representation)36 OptionalFlag(const char *Representation) 37 : representation(Representation), flag(false) {} isSet()38 bool isSet() { return flag; } set()39 void set() { flag = true; } clear()40 void clear() { flag = false; } setPosition(const char * position)41 void setPosition(const char *position) { 42 assert(position); 43 this->position = position; 44 } getPosition()45 const char *getPosition() const { 46 assert(position); 47 return position; 48 } toString()49 const char *toString() const { return representation; } 50 51 // Overloaded operators for bool like qualities 52 LLVM_EXPLICIT operator bool() const { return flag; } 53 OptionalFlag& operator=(const bool &rhs) { 54 flag = rhs; 55 return *this; // Return a reference to myself. 56 } 57 private: 58 const char *representation; 59 const char *position; 60 bool flag; 61 }; 62 63 /// Represents the length modifier in a format string in scanf/printf. 64 class LengthModifier { 65 public: 66 enum Kind { 67 None, 68 AsChar, // 'hh' 69 AsShort, // 'h' 70 AsLong, // 'l' 71 AsLongLong, // 'll' 72 AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types) 73 AsIntMax, // 'j' 74 AsSizeT, // 'z' 75 AsPtrDiff, // 't' 76 AsInt32, // 'I32' (MSVCRT, like __int32) 77 AsInt3264, // 'I' (MSVCRT, like __int3264 from MIDL) 78 AsInt64, // 'I64' (MSVCRT, like __int64) 79 AsLongDouble, // 'L' 80 AsAllocate, // for '%as', GNU extension to C90 scanf 81 AsMAllocate, // for '%ms', GNU extension to scanf 82 AsWide, // 'w' (MSVCRT, like l but only for c, C, s, S, or Z 83 AsWideChar = AsLong // for '%ls', only makes sense for printf 84 }; 85 LengthModifier()86 LengthModifier() 87 : Position(nullptr), kind(None) {} LengthModifier(const char * pos,Kind k)88 LengthModifier(const char *pos, Kind k) 89 : Position(pos), kind(k) {} 90 getStart()91 const char *getStart() const { 92 return Position; 93 } 94 getLength()95 unsigned getLength() const { 96 switch (kind) { 97 default: 98 return 1; 99 case AsLongLong: 100 case AsChar: 101 return 2; 102 case AsInt32: 103 case AsInt64: 104 return 3; 105 case None: 106 return 0; 107 } 108 } 109 getKind()110 Kind getKind() const { return kind; } setKind(Kind k)111 void setKind(Kind k) { kind = k; } 112 113 const char *toString() const; 114 115 private: 116 const char *Position; 117 Kind kind; 118 }; 119 120 class ConversionSpecifier { 121 public: 122 enum Kind { 123 InvalidSpecifier = 0, 124 // C99 conversion specifiers. 125 cArg, 126 dArg, 127 DArg, // Apple extension 128 iArg, 129 IntArgBeg = dArg, IntArgEnd = iArg, 130 131 oArg, 132 OArg, // Apple extension 133 uArg, 134 UArg, // Apple extension 135 xArg, 136 XArg, 137 UIntArgBeg = oArg, UIntArgEnd = XArg, 138 139 fArg, 140 FArg, 141 eArg, 142 EArg, 143 gArg, 144 GArg, 145 aArg, 146 AArg, 147 DoubleArgBeg = fArg, DoubleArgEnd = AArg, 148 149 sArg, 150 pArg, 151 nArg, 152 PercentArg, 153 CArg, 154 SArg, 155 156 // ** Printf-specific ** 157 158 ZArg, // MS extension 159 160 // Objective-C specific specifiers. 161 ObjCObjArg, // '@' 162 ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg, 163 164 // GlibC specific specifiers. 165 PrintErrno, // 'm' 166 167 PrintfConvBeg = ObjCObjArg, PrintfConvEnd = PrintErrno, 168 169 // ** Scanf-specific ** 170 ScanListArg, // '[' 171 ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg 172 }; 173 174 ConversionSpecifier(bool isPrintf = true) IsPrintf(isPrintf)175 : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr), 176 kind(InvalidSpecifier) {} 177 ConversionSpecifier(bool isPrintf,const char * pos,Kind k)178 ConversionSpecifier(bool isPrintf, const char *pos, Kind k) 179 : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {} 180 getStart()181 const char *getStart() const { 182 return Position; 183 } 184 getCharacters()185 StringRef getCharacters() const { 186 return StringRef(getStart(), getLength()); 187 } 188 consumesDataArgument()189 bool consumesDataArgument() const { 190 switch (kind) { 191 case PrintErrno: 192 assert(IsPrintf); 193 return false; 194 case PercentArg: 195 return false; 196 default: 197 return true; 198 } 199 } 200 getKind()201 Kind getKind() const { return kind; } setKind(Kind k)202 void setKind(Kind k) { kind = k; } getLength()203 unsigned getLength() const { 204 return EndScanList ? EndScanList - Position : 1; 205 } 206 isIntArg()207 bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; } isUIntArg()208 bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; } isAnyIntArg()209 bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; } 210 const char *toString() const; 211 isPrintfKind()212 bool isPrintfKind() const { return IsPrintf; } 213 214 Optional<ConversionSpecifier> getStandardSpecifier() const; 215 216 protected: 217 bool IsPrintf; 218 const char *Position; 219 const char *EndScanList; 220 Kind kind; 221 }; 222 223 class ArgType { 224 public: 225 enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy, 226 AnyCharTy, CStrTy, WCStrTy, WIntTy }; 227 private: 228 const Kind K; 229 QualType T; 230 const char *Name; 231 bool Ptr; 232 public: 233 ArgType(Kind k = UnknownTy, const char *n = nullptr) K(k)234 : K(k), Name(n), Ptr(false) {} 235 ArgType(QualType t, const char *n = nullptr) K(SpecificTy)236 : K(SpecificTy), T(t), Name(n), Ptr(false) {} ArgType(CanQualType t)237 ArgType(CanQualType t) : K(SpecificTy), T(t), Name(nullptr), Ptr(false) {} 238 Invalid()239 static ArgType Invalid() { return ArgType(InvalidTy); } isValid()240 bool isValid() const { return K != InvalidTy; } 241 242 /// Create an ArgType which corresponds to the type pointer to A. PtrTo(const ArgType & A)243 static ArgType PtrTo(const ArgType& A) { 244 assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown"); 245 ArgType Res = A; 246 Res.Ptr = true; 247 return Res; 248 } 249 250 bool matchesType(ASTContext &C, QualType argTy) const; 251 252 QualType getRepresentativeType(ASTContext &C) const; 253 254 std::string getRepresentativeTypeName(ASTContext &C) const; 255 }; 256 257 class OptionalAmount { 258 public: 259 enum HowSpecified { NotSpecified, Constant, Arg, Invalid }; 260 OptionalAmount(HowSpecified howSpecified,unsigned amount,const char * amountStart,unsigned amountLength,bool usesPositionalArg)261 OptionalAmount(HowSpecified howSpecified, 262 unsigned amount, 263 const char *amountStart, 264 unsigned amountLength, 265 bool usesPositionalArg) 266 : start(amountStart), length(amountLength), hs(howSpecified), amt(amount), 267 UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {} 268 269 OptionalAmount(bool valid = true) start(nullptr)270 : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0), 271 UsesPositionalArg(0), UsesDotPrefix(0) {} 272 isInvalid()273 bool isInvalid() const { 274 return hs == Invalid; 275 } 276 getHowSpecified()277 HowSpecified getHowSpecified() const { return hs; } setHowSpecified(HowSpecified h)278 void setHowSpecified(HowSpecified h) { hs = h; } 279 hasDataArgument()280 bool hasDataArgument() const { return hs == Arg; } 281 getArgIndex()282 unsigned getArgIndex() const { 283 assert(hasDataArgument()); 284 return amt; 285 } 286 getConstantAmount()287 unsigned getConstantAmount() const { 288 assert(hs == Constant); 289 return amt; 290 } 291 getStart()292 const char *getStart() const { 293 // We include the . character if it is given. 294 return start - UsesDotPrefix; 295 } 296 getConstantLength()297 unsigned getConstantLength() const { 298 assert(hs == Constant); 299 return length + UsesDotPrefix; 300 } 301 302 ArgType getArgType(ASTContext &Ctx) const; 303 304 void toString(raw_ostream &os) const; 305 usesPositionalArg()306 bool usesPositionalArg() const { return (bool) UsesPositionalArg; } getPositionalArgIndex()307 unsigned getPositionalArgIndex() const { 308 assert(hasDataArgument()); 309 return amt + 1; 310 } 311 usesDotPrefix()312 bool usesDotPrefix() const { return UsesDotPrefix; } setUsesDotPrefix()313 void setUsesDotPrefix() { UsesDotPrefix = true; } 314 315 private: 316 const char *start; 317 unsigned length; 318 HowSpecified hs; 319 unsigned amt; 320 bool UsesPositionalArg : 1; 321 bool UsesDotPrefix; 322 }; 323 324 325 class FormatSpecifier { 326 protected: 327 LengthModifier LM; 328 OptionalAmount FieldWidth; 329 ConversionSpecifier CS; 330 /// Positional arguments, an IEEE extension: 331 /// IEEE Std 1003.1, 2004 Edition 332 /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html 333 bool UsesPositionalArg; 334 unsigned argIndex; 335 public: FormatSpecifier(bool isPrintf)336 FormatSpecifier(bool isPrintf) 337 : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {} 338 setLengthModifier(LengthModifier lm)339 void setLengthModifier(LengthModifier lm) { 340 LM = lm; 341 } 342 setUsesPositionalArg()343 void setUsesPositionalArg() { UsesPositionalArg = true; } 344 setArgIndex(unsigned i)345 void setArgIndex(unsigned i) { 346 argIndex = i; 347 } 348 getArgIndex()349 unsigned getArgIndex() const { 350 return argIndex; 351 } 352 getPositionalArgIndex()353 unsigned getPositionalArgIndex() const { 354 return argIndex + 1; 355 } 356 getLengthModifier()357 const LengthModifier &getLengthModifier() const { 358 return LM; 359 } 360 getFieldWidth()361 const OptionalAmount &getFieldWidth() const { 362 return FieldWidth; 363 } 364 setFieldWidth(const OptionalAmount & Amt)365 void setFieldWidth(const OptionalAmount &Amt) { 366 FieldWidth = Amt; 367 } 368 usesPositionalArg()369 bool usesPositionalArg() const { return UsesPositionalArg; } 370 371 bool hasValidLengthModifier(const TargetInfo &Target) const; 372 373 bool hasStandardLengthModifier() const; 374 375 Optional<LengthModifier> getCorrectedLengthModifier() const; 376 377 bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const; 378 379 bool hasStandardLengthConversionCombination() const; 380 381 /// For a TypedefType QT, if it is a named integer type such as size_t, 382 /// assign the appropriate value to LM and return true. 383 static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM); 384 }; 385 386 } // end analyze_format_string namespace 387 388 //===----------------------------------------------------------------------===// 389 /// Pieces specific to fprintf format strings. 390 391 namespace analyze_printf { 392 393 class PrintfConversionSpecifier : 394 public analyze_format_string::ConversionSpecifier { 395 public: PrintfConversionSpecifier()396 PrintfConversionSpecifier() 397 : ConversionSpecifier(true, nullptr, InvalidSpecifier) {} 398 PrintfConversionSpecifier(const char * pos,Kind k)399 PrintfConversionSpecifier(const char *pos, Kind k) 400 : ConversionSpecifier(true, pos, k) {} 401 isObjCArg()402 bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; } isDoubleArg()403 bool isDoubleArg() const { return kind >= DoubleArgBeg && 404 kind <= DoubleArgEnd; } getLength()405 unsigned getLength() const { 406 // Conversion specifiers currently only are represented by 407 // single characters, but we be flexible. 408 return 1; 409 } 410 classof(const analyze_format_string::ConversionSpecifier * CS)411 static bool classof(const analyze_format_string::ConversionSpecifier *CS) { 412 return CS->isPrintfKind(); 413 } 414 }; 415 416 using analyze_format_string::ArgType; 417 using analyze_format_string::LengthModifier; 418 using analyze_format_string::OptionalAmount; 419 using analyze_format_string::OptionalFlag; 420 421 class PrintfSpecifier : public analyze_format_string::FormatSpecifier { 422 OptionalFlag HasThousandsGrouping; // ''', POSIX extension. 423 OptionalFlag IsLeftJustified; // '-' 424 OptionalFlag HasPlusPrefix; // '+' 425 OptionalFlag HasSpacePrefix; // ' ' 426 OptionalFlag HasAlternativeForm; // '#' 427 OptionalFlag HasLeadingZeroes; // '0' 428 OptionalAmount Precision; 429 public: PrintfSpecifier()430 PrintfSpecifier() : 431 FormatSpecifier(/* isPrintf = */ true), 432 HasThousandsGrouping("'"), IsLeftJustified("-"), HasPlusPrefix("+"), 433 HasSpacePrefix(" "), HasAlternativeForm("#"), HasLeadingZeroes("0") {} 434 435 static PrintfSpecifier Parse(const char *beg, const char *end); 436 437 // Methods for incrementally constructing the PrintfSpecifier. setConversionSpecifier(const PrintfConversionSpecifier & cs)438 void setConversionSpecifier(const PrintfConversionSpecifier &cs) { 439 CS = cs; 440 } setHasThousandsGrouping(const char * position)441 void setHasThousandsGrouping(const char *position) { 442 HasThousandsGrouping = true; 443 HasThousandsGrouping.setPosition(position); 444 } setIsLeftJustified(const char * position)445 void setIsLeftJustified(const char *position) { 446 IsLeftJustified = true; 447 IsLeftJustified.setPosition(position); 448 } setHasPlusPrefix(const char * position)449 void setHasPlusPrefix(const char *position) { 450 HasPlusPrefix = true; 451 HasPlusPrefix.setPosition(position); 452 } setHasSpacePrefix(const char * position)453 void setHasSpacePrefix(const char *position) { 454 HasSpacePrefix = true; 455 HasSpacePrefix.setPosition(position); 456 } setHasAlternativeForm(const char * position)457 void setHasAlternativeForm(const char *position) { 458 HasAlternativeForm = true; 459 HasAlternativeForm.setPosition(position); 460 } setHasLeadingZeros(const char * position)461 void setHasLeadingZeros(const char *position) { 462 HasLeadingZeroes = true; 463 HasLeadingZeroes.setPosition(position); 464 } setUsesPositionalArg()465 void setUsesPositionalArg() { UsesPositionalArg = true; } 466 467 // Methods for querying the format specifier. 468 getConversionSpecifier()469 const PrintfConversionSpecifier &getConversionSpecifier() const { 470 return cast<PrintfConversionSpecifier>(CS); 471 } 472 setPrecision(const OptionalAmount & Amt)473 void setPrecision(const OptionalAmount &Amt) { 474 Precision = Amt; 475 Precision.setUsesDotPrefix(); 476 } 477 getPrecision()478 const OptionalAmount &getPrecision() const { 479 return Precision; 480 } 481 consumesDataArgument()482 bool consumesDataArgument() const { 483 return getConversionSpecifier().consumesDataArgument(); 484 } 485 486 /// \brief Returns the builtin type that a data argument 487 /// paired with this format specifier should have. This method 488 /// will return null if the format specifier does not have 489 /// a matching data argument or the matching argument matches 490 /// more than one type. 491 ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const; 492 hasThousandsGrouping()493 const OptionalFlag &hasThousandsGrouping() const { 494 return HasThousandsGrouping; 495 } isLeftJustified()496 const OptionalFlag &isLeftJustified() const { return IsLeftJustified; } hasPlusPrefix()497 const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; } hasAlternativeForm()498 const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; } hasLeadingZeros()499 const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; } hasSpacePrefix()500 const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; } usesPositionalArg()501 bool usesPositionalArg() const { return UsesPositionalArg; } 502 503 /// Changes the specifier and length according to a QualType, retaining any 504 /// flags or options. Returns true on success, or false when a conversion 505 /// was not successful. 506 bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx, 507 bool IsObjCLiteral); 508 509 void toString(raw_ostream &os) const; 510 511 // Validation methods - to check if any element results in undefined behavior 512 bool hasValidPlusPrefix() const; 513 bool hasValidAlternativeForm() const; 514 bool hasValidLeadingZeros() const; 515 bool hasValidSpacePrefix() const; 516 bool hasValidLeftJustified() const; 517 bool hasValidThousandsGroupingPrefix() const; 518 519 bool hasValidPrecision() const; 520 bool hasValidFieldWidth() const; 521 }; 522 } // end analyze_printf namespace 523 524 //===----------------------------------------------------------------------===// 525 /// Pieces specific to fscanf format strings. 526 527 namespace analyze_scanf { 528 529 class ScanfConversionSpecifier : 530 public analyze_format_string::ConversionSpecifier { 531 public: ScanfConversionSpecifier()532 ScanfConversionSpecifier() 533 : ConversionSpecifier(false, nullptr, InvalidSpecifier) {} 534 ScanfConversionSpecifier(const char * pos,Kind k)535 ScanfConversionSpecifier(const char *pos, Kind k) 536 : ConversionSpecifier(false, pos, k) {} 537 setEndScanList(const char * pos)538 void setEndScanList(const char *pos) { EndScanList = pos; } 539 classof(const analyze_format_string::ConversionSpecifier * CS)540 static bool classof(const analyze_format_string::ConversionSpecifier *CS) { 541 return !CS->isPrintfKind(); 542 } 543 }; 544 545 using analyze_format_string::ArgType; 546 using analyze_format_string::LengthModifier; 547 using analyze_format_string::OptionalAmount; 548 using analyze_format_string::OptionalFlag; 549 550 class ScanfSpecifier : public analyze_format_string::FormatSpecifier { 551 OptionalFlag SuppressAssignment; // '*' 552 public: ScanfSpecifier()553 ScanfSpecifier() : 554 FormatSpecifier(/* isPrintf = */ false), 555 SuppressAssignment("*") {} 556 setSuppressAssignment(const char * position)557 void setSuppressAssignment(const char *position) { 558 SuppressAssignment = true; 559 SuppressAssignment.setPosition(position); 560 } 561 getSuppressAssignment()562 const OptionalFlag &getSuppressAssignment() const { 563 return SuppressAssignment; 564 } 565 setConversionSpecifier(const ScanfConversionSpecifier & cs)566 void setConversionSpecifier(const ScanfConversionSpecifier &cs) { 567 CS = cs; 568 } 569 getConversionSpecifier()570 const ScanfConversionSpecifier &getConversionSpecifier() const { 571 return cast<ScanfConversionSpecifier>(CS); 572 } 573 consumesDataArgument()574 bool consumesDataArgument() const { 575 return CS.consumesDataArgument() && !SuppressAssignment; 576 } 577 578 ArgType getArgType(ASTContext &Ctx) const; 579 580 bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt, 581 ASTContext &Ctx); 582 583 void toString(raw_ostream &os) const; 584 585 static ScanfSpecifier Parse(const char *beg, const char *end); 586 }; 587 588 } // end analyze_scanf namespace 589 590 //===----------------------------------------------------------------------===// 591 // Parsing and processing of format strings (both fprintf and fscanf). 592 593 namespace analyze_format_string { 594 595 enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 }; 596 597 class FormatStringHandler { 598 public: FormatStringHandler()599 FormatStringHandler() {} 600 virtual ~FormatStringHandler(); 601 HandleNullChar(const char * nullCharacter)602 virtual void HandleNullChar(const char *nullCharacter) {} 603 HandlePosition(const char * startPos,unsigned posLen)604 virtual void HandlePosition(const char *startPos, unsigned posLen) {} 605 HandleInvalidPosition(const char * startPos,unsigned posLen,PositionContext p)606 virtual void HandleInvalidPosition(const char *startPos, unsigned posLen, 607 PositionContext p) {} 608 HandleZeroPosition(const char * startPos,unsigned posLen)609 virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {} 610 HandleIncompleteSpecifier(const char * startSpecifier,unsigned specifierLen)611 virtual void HandleIncompleteSpecifier(const char *startSpecifier, 612 unsigned specifierLen) {} 613 614 // Printf-specific handlers. 615 HandleInvalidPrintfConversionSpecifier(const analyze_printf::PrintfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)616 virtual bool HandleInvalidPrintfConversionSpecifier( 617 const analyze_printf::PrintfSpecifier &FS, 618 const char *startSpecifier, 619 unsigned specifierLen) { 620 return true; 621 } 622 HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)623 virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, 624 const char *startSpecifier, 625 unsigned specifierLen) { 626 return true; 627 } 628 629 // Scanf-specific handlers. 630 HandleInvalidScanfConversionSpecifier(const analyze_scanf::ScanfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)631 virtual bool HandleInvalidScanfConversionSpecifier( 632 const analyze_scanf::ScanfSpecifier &FS, 633 const char *startSpecifier, 634 unsigned specifierLen) { 635 return true; 636 } 637 HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)638 virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, 639 const char *startSpecifier, 640 unsigned specifierLen) { 641 return true; 642 } 643 HandleIncompleteScanList(const char * start,const char * end)644 virtual void HandleIncompleteScanList(const char *start, const char *end) {} 645 }; 646 647 bool ParsePrintfString(FormatStringHandler &H, 648 const char *beg, const char *end, const LangOptions &LO, 649 const TargetInfo &Target); 650 651 bool ParseFormatStringHasSArg(const char *beg, const char *end, const LangOptions &LO, 652 const TargetInfo &Target); 653 654 bool ParseScanfString(FormatStringHandler &H, 655 const char *beg, const char *end, const LangOptions &LO, 656 const TargetInfo &Target); 657 658 } // end analyze_format_string namespace 659 } // end clang namespace 660 #endif 661