11541Srgrimes//= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===// 214500Shsu// 31541Srgrimes// The LLVM Compiler Infrastructure 41541Srgrimes// 51541Srgrimes// This file is distributed under the University of Illinois Open Source 61541Srgrimes// License. See LICENSE.TXT for details. 71541Srgrimes// 81541Srgrimes//===----------------------------------------------------------------------===// 91541Srgrimes// 101541Srgrimes// This file defines APIs for analyzing the format strings of printf, fscanf, 111541Srgrimes// and friends. 121541Srgrimes// 131541Srgrimes// The structure of format strings for fprintf are described in C99 7.19.6.1. 141541Srgrimes// 151541Srgrimes// The structure of format strings for fscanf are described in C99 7.19.6.2. 161541Srgrimes// 171541Srgrimes//===----------------------------------------------------------------------===// 181541Srgrimes 191541Srgrimes#ifndef LLVM_CLANG_FORMAT_H 201541Srgrimes#define LLVM_CLANG_FORMAT_H 211541Srgrimes 221541Srgrimes#include "clang/AST/CanonicalType.h" 231541Srgrimes 241541Srgrimesnamespace clang { 251541Srgrimes 261541Srgrimesclass TargetInfo; 271541Srgrimes 281541Srgrimes//===----------------------------------------------------------------------===// 291541Srgrimes/// Common components of both fprintf and fscanf format strings. 301541Srgrimesnamespace analyze_format_string { 311541Srgrimes 321541Srgrimes/// Class representing optional flags with location and representation 331541Srgrimes/// information. 3414500Shsuclass OptionalFlag { 3550477Speterpublic: 361541Srgrimes OptionalFlag(const char *Representation) 371541Srgrimes : representation(Representation), flag(false) {} 381541Srgrimes bool isSet() { return flag; } 391541Srgrimes void set() { flag = true; } 401541Srgrimes void clear() { flag = false; } 4133778Sbde void setPosition(const char *position) { 4233778Sbde assert(position); 431541Srgrimes this->position = position; 4490868Smike } 4593514Smike const char *getPosition() const { 461541Srgrimes assert(position); 47104341Smike return position; 481541Srgrimes } 491541Srgrimes const char *toString() const { return representation; } 501541Srgrimes 511541Srgrimes // Overloaded operators for bool like qualities 52128448Sobrien LLVM_EXPLICIT operator bool() const { return flag; } 531541Srgrimes OptionalFlag& operator=(const bool &rhs) { 541541Srgrimes flag = rhs; 551541Srgrimes return *this; // Return a reference to myself. 56128448Sobrien } 571541Srgrimesprivate: 5893514Smike const char *representation; 5993514Smike const char *position; 6093514Smike bool flag; 6193514Smike}; 6293514Smike 6393514Smike/// Represents the length modifier in a format string in scanf/printf. 6493514Smikeclass LengthModifier { 6593514Smikepublic: 6693514Smike enum Kind { 6793514Smike None, 6893514Smike AsChar, // 'hh' 6993514Smike AsShort, // 'h' 7093514Smike AsLong, // 'l' 7193514Smike AsLongLong, // 'll' 7293514Smike AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types) 7393514Smike AsIntMax, // 'j' 7493514Smike AsSizeT, // 'z' 7593514Smike AsPtrDiff, // 't' 7693514Smike AsInt32, // 'I32' (MSVCRT, like __int32) 7793514Smike AsInt3264, // 'I' (MSVCRT, like __int3264 from MIDL) 7893514Smike AsInt64, // 'I64' (MSVCRT, like __int64) 7993514Smike AsLongDouble, // 'L' 8093514Smike AsAllocate, // for '%as', GNU extension to C90 scanf 8193514Smike AsMAllocate, // for '%ms', GNU extension to scanf 8293514Smike AsWideChar = AsLong // for '%ls', only makes sense for printf 8393514Smike }; 8493514Smike 8593514Smike LengthModifier() 8693514Smike : Position(0), kind(None) {} 8793514Smike LengthModifier(const char *pos, Kind k) 8893514Smike : Position(pos), kind(k) {} 8993514Smike 9093514Smike const char *getStart() const { 9193514Smike return Position; 9293514Smike } 9393514Smike 9493514Smike unsigned getLength() const { 9593514Smike switch (kind) { 9693514Smike default: 9793514Smike return 1; 9893514Smike case AsLongLong: 9993514Smike case AsChar: 10093514Smike return 2; 10193514Smike case AsInt32: 10293514Smike case AsInt64: 10393514Smike return 3; 10493514Smike case None: 10593514Smike return 0; 10693514Smike } 107104341Smike } 10841927Sdt 10941927Sdt Kind getKind() const { return kind; } 11041927Sdt void setKind(Kind k) { kind = k; } 11141927Sdt 112104341Smike const char *toString() const; 113104341Smike 1141541Srgrimesprivate: 1151541Srgrimes const char *Position; 1161541Srgrimes Kind kind; 11751901Smarcel}; 11851901Smarcel 119110051Smikeclass ConversionSpecifier { 120110051Smikepublic: 121110051Smike enum Kind { 122110051Smike InvalidSpecifier = 0, 123110051Smike // C99 conversion specifiers. 124110051Smike cArg, 125110051Smike dArg, 126110051Smike DArg, // Apple extension 127110051Smike iArg, 128110051Smike IntArgBeg = dArg, IntArgEnd = iArg, 129110051Smike 130102227Smike oArg, 131104341Smike OArg, // Apple extension 132110051Smike uArg, 133112745Smike UArg, // Apple extension 134112745Smike xArg, 135112745Smike XArg, 136112745Smike UIntArgBeg = oArg, UIntArgEnd = XArg, 137112745Smike 138110051Smike fArg, 139110051Smike FArg, 140110051Smike eArg, 141110051Smike EArg, 142110051Smike gArg, 143130434Sdas GArg, 14491325Smike aArg, 145110051Smike AArg, 146110051Smike DoubleArgBeg = fArg, DoubleArgEnd = AArg, 147110051Smike 148110051Smike sArg, 149110051Smike pArg, 150110051Smike nArg, 151102227Smike PercentArg, 152102227Smike CArg, 153102227Smike SArg, 15491325Smike 15591325Smike // ** Printf-specific ** 156105683Stjr 157105683Stjr // Objective-C specific specifiers. 158105683Stjr ObjCObjArg, // '@' 159105683Stjr ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg, 160105683Stjr 161105683Stjr // FreeBSD specific specifiers 162105683Stjr FreeBSDbArg, 163105683Stjr FreeBSDDArg, 164105683Stjr FreeBSDrArg, 165105683Stjr 166105650Smike // GlibC specific specifiers. 167105650Smike PrintErrno, // 'm' 168105650Smike 169105650Smike PrintfConvBeg = ObjCObjArg, PrintfConvEnd = PrintErrno, 170105650Smike 171111705Smike // ** Scanf-specific ** 172111705Smike ScanListArg, // '[' 173111705Smike ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg 174111705Smike }; 175102325Smike 176105142Smike ConversionSpecifier(bool isPrintf = true) 177105142Smike : IsPrintf(isPrintf), Position(0), EndScanList(0), kind(InvalidSpecifier) {} 178105142Smike 179105142Smike ConversionSpecifier(bool isPrintf, const char *pos, Kind k) 180105142Smike : IsPrintf(isPrintf), Position(pos), EndScanList(0), kind(k) {} 181130735Smarcel 182130735Smarcel const char *getStart() const { 183130735Smarcel return Position; 184130735Smarcel } 185130735Smarcel 186102325Smike StringRef getCharacters() const { 187102325Smike return StringRef(getStart(), getLength()); 188102325Smike } 189102325Smike 190102325Smike bool consumesDataArgument() const { 191111705Smike switch (kind) { 192111705Smike case PrintErrno: 193111705Smike assert(IsPrintf); 194111705Smike return false; 195102325Smike case PercentArg: 196102325Smike return false; 197102227Smike default: 198102325Smike return true; 199102325Smike } 200102325Smike } 201103457Smike 202102227Smike Kind getKind() const { return kind; } 203103457Smike void setKind(Kind k) { kind = k; } 204103457Smike unsigned getLength() const { 205103457Smike return EndScanList ? EndScanList - Position : 1; 206102227Smike } 207105650Smike 208105650Smike bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; } 209105650Smike bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; } 210105650Smike bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; } 211105650Smike const char *toString() const; 212105650Smike 213102227Smike bool isPrintfKind() const { return IsPrintf; } 214108190Smike 215110051Smike Optional<ConversionSpecifier> getStandardSpecifier() const; 216110051Smike 217110051Smikeprotected: 218110051Smike bool IsPrintf; 219110051Smike const char *Position; 220110051Smike const char *EndScanList; 221110051Smike Kind kind; 222110051Smike}; 223110051Smike 224110051Smikeclass ArgType { 225108190Smikepublic: 226108190Smike enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy, 227108190Smike AnyCharTy, CStrTy, WCStrTy, WIntTy }; 228108190Smikeprivate: 229108190Smike const Kind K; 230110051Smike QualType T; 231110051Smike const char *Name; 232110051Smike bool Ptr; 233110051Smikepublic: 234110051Smike ArgType(Kind k = UnknownTy, const char *n = 0) : K(k), Name(n), Ptr(false) {} 235110051Smike ArgType(QualType t, const char *n = 0) 236110051Smike : K(SpecificTy), T(t), Name(n), Ptr(false) {} 237110051Smike ArgType(CanQualType t) : K(SpecificTy), T(t), Name(0), Ptr(false) {} 238110051Smike 239110051Smike static ArgType Invalid() { return ArgType(InvalidTy); } 240102227Smike bool isValid() const { return K != InvalidTy; } 24194363Smike 242102227Smike /// Create an ArgType which corresponds to the type pointer to A. 243102227Smike static ArgType PtrTo(const ArgType& A) { 244102227Smike assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown"); 24536735Sdfr ArgType Res = A; 24694363Smike Res.Ptr = true; 247108190Smike return Res; 248108190Smike } 249108190Smike 250108190Smike bool matchesType(ASTContext &C, QualType argTy) const; 251108190Smike 252102227Smike QualType getRepresentativeType(ASTContext &C) const; 253102227Smike 254112569Sjake std::string getRepresentativeTypeName(ASTContext &C) const; 255102227Smike}; 256102227Smike 2571541Srgrimesclass OptionalAmount { 25855205Speterpublic: 25915481Sbde enum HowSpecified { NotSpecified, Constant, Arg, Invalid }; 260127239Smarcel 261102227Smike OptionalAmount(HowSpecified howSpecified, 262102421Smike unsigned amount, 263102421Smike const char *amountStart, 264102421Smike unsigned amountLength, 265102421Smike bool usesPositionalArg) 266102421Smike : start(amountStart), length(amountLength), hs(howSpecified), amt(amount), 267102421Smike UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {} 268102421Smike 269102421Smike OptionalAmount(bool valid = true) 270102421Smike : start(0),length(0), hs(valid ? NotSpecified : Invalid), amt(0), 271102421Smike UsesPositionalArg(0), UsesDotPrefix(0) {} 272102421Smike 273102227Smike bool isInvalid() const { 274104341Smike return hs == Invalid; 27515481Sbde } 27612642Sbde 27767708Sphk HowSpecified getHowSpecified() const { return hs; } 27867708Sphk void setHowSpecified(HowSpecified h) { hs = h; } 27955205Speter 28046818Sphk bool hasDataArgument() const { return hs == Arg; } 2811541Srgrimes 282103867Smike unsigned getArgIndex() const { 283103867Smike assert(hasDataArgument()); 2841541Srgrimes return amt; 285103867Smike } 2861541Srgrimes 287103867Smike unsigned getConstantAmount() const { 2881541Srgrimes assert(hs == Constant); 289104341Smike return amt; 29024896Sbde } 291104341Smike 292104341Smike const char *getStart() const { 293104341Smike // We include the . character if it is given. 294104341Smike return start - UsesDotPrefix; 295104341Smike } 296104341Smike 297104341Smike unsigned getConstantLength() const { 298104341Smike assert(hs == Constant); 299130640Sphk return length + UsesDotPrefix; 300130640Sphk } 301104341Smike 30224896Sbde ArgType getArgType(ASTContext &Ctx) const; 30324896Sbde 30424896Sbde void toString(raw_ostream &os) const; 30524896Sbde 30655205Speter bool usesPositionalArg() const { return (bool) UsesPositionalArg; } 30724896Sbde unsigned getPositionalArgIndex() const { 30824896Sbde assert(hasDataArgument()); 30924896Sbde return amt + 1; 31092719Salfred } 31124896Sbde 31224896Sbde bool usesDotPrefix() const { return UsesDotPrefix; } 31324896Sbde void setUsesDotPrefix() { UsesDotPrefix = true; } 31492719Salfred 31524896Sbdeprivate: 31624896Sbde const char *start; 31724896Sbde unsigned length; 31892719Salfred HowSpecified hs; 31924896Sbde unsigned amt; 32024896Sbde bool UsesPositionalArg : 1; 32124896Sbde bool UsesDotPrefix; 32292719Salfred}; 32324896Sbde 32424896Sbde 32555205Speterclass FormatSpecifier { 32624896Sbdeprotected: 32798271Swollman LengthModifier LM; 3281541Srgrimes OptionalAmount FieldWidth; 3291541Srgrimes 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; 335public: 336 FormatSpecifier(bool isPrintf) 337 : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {} 338 339 void setLengthModifier(LengthModifier lm) { 340 LM = lm; 341 } 342 343 void setUsesPositionalArg() { UsesPositionalArg = true; } 344 345 void setArgIndex(unsigned i) { 346 argIndex = i; 347 } 348 349 unsigned getArgIndex() const { 350 return argIndex; 351 } 352 353 unsigned getPositionalArgIndex() const { 354 return argIndex + 1; 355 } 356 357 const LengthModifier &getLengthModifier() const { 358 return LM; 359 } 360 361 const OptionalAmount &getFieldWidth() const { 362 return FieldWidth; 363 } 364 365 void setFieldWidth(const OptionalAmount &Amt) { 366 FieldWidth = Amt; 367 } 368 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 391namespace analyze_printf { 392 393class PrintfConversionSpecifier : 394 public analyze_format_string::ConversionSpecifier { 395public: 396 PrintfConversionSpecifier() 397 : ConversionSpecifier(true, 0, InvalidSpecifier) {} 398 399 PrintfConversionSpecifier(const char *pos, Kind k) 400 : ConversionSpecifier(true, pos, k) {} 401 402 bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; } 403 bool isDoubleArg() const { return kind >= DoubleArgBeg && 404 kind <= DoubleArgEnd; } 405 unsigned getLength() const { 406 // Conversion specifiers currently only are represented by 407 // single characters, but we be flexible. 408 return 1; 409 } 410 411 static bool classof(const analyze_format_string::ConversionSpecifier *CS) { 412 return CS->isPrintfKind(); 413 } 414}; 415 416using analyze_format_string::ArgType; 417using analyze_format_string::LengthModifier; 418using analyze_format_string::OptionalAmount; 419using analyze_format_string::OptionalFlag; 420 421class 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; 429public: 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. 438 void setConversionSpecifier(const PrintfConversionSpecifier &cs) { 439 CS = cs; 440 } 441 void setHasThousandsGrouping(const char *position) { 442 HasThousandsGrouping = true; 443 HasThousandsGrouping.setPosition(position); 444 } 445 void setIsLeftJustified(const char *position) { 446 IsLeftJustified = true; 447 IsLeftJustified.setPosition(position); 448 } 449 void setHasPlusPrefix(const char *position) { 450 HasPlusPrefix = true; 451 HasPlusPrefix.setPosition(position); 452 } 453 void setHasSpacePrefix(const char *position) { 454 HasSpacePrefix = true; 455 HasSpacePrefix.setPosition(position); 456 } 457 void setHasAlternativeForm(const char *position) { 458 HasAlternativeForm = true; 459 HasAlternativeForm.setPosition(position); 460 } 461 void setHasLeadingZeros(const char *position) { 462 HasLeadingZeroes = true; 463 HasLeadingZeroes.setPosition(position); 464 } 465 void setUsesPositionalArg() { UsesPositionalArg = true; } 466 467 // Methods for querying the format specifier. 468 469 const PrintfConversionSpecifier &getConversionSpecifier() const { 470 return cast<PrintfConversionSpecifier>(CS); 471 } 472 473 void setPrecision(const OptionalAmount &Amt) { 474 Precision = Amt; 475 Precision.setUsesDotPrefix(); 476 } 477 478 const OptionalAmount &getPrecision() const { 479 return Precision; 480 } 481 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 493 const OptionalFlag &hasThousandsGrouping() const { 494 return HasThousandsGrouping; 495 } 496 const OptionalFlag &isLeftJustified() const { return IsLeftJustified; } 497 const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; } 498 const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; } 499 const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; } 500 const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; } 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 527namespace analyze_scanf { 528 529class ScanfConversionSpecifier : 530 public analyze_format_string::ConversionSpecifier { 531public: 532 ScanfConversionSpecifier() 533 : ConversionSpecifier(false, 0, InvalidSpecifier) {} 534 535 ScanfConversionSpecifier(const char *pos, Kind k) 536 : ConversionSpecifier(false, pos, k) {} 537 538 void setEndScanList(const char *pos) { EndScanList = pos; } 539 540 static bool classof(const analyze_format_string::ConversionSpecifier *CS) { 541 return !CS->isPrintfKind(); 542 } 543}; 544 545using analyze_format_string::ArgType; 546using analyze_format_string::LengthModifier; 547using analyze_format_string::OptionalAmount; 548using analyze_format_string::OptionalFlag; 549 550class ScanfSpecifier : public analyze_format_string::FormatSpecifier { 551 OptionalFlag SuppressAssignment; // '*' 552public: 553 ScanfSpecifier() : 554 FormatSpecifier(/* isPrintf = */ false), 555 SuppressAssignment("*") {} 556 557 void setSuppressAssignment(const char *position) { 558 SuppressAssignment = true; 559 SuppressAssignment.setPosition(position); 560 } 561 562 const OptionalFlag &getSuppressAssignment() const { 563 return SuppressAssignment; 564 } 565 566 void setConversionSpecifier(const ScanfConversionSpecifier &cs) { 567 CS = cs; 568 } 569 570 const ScanfConversionSpecifier &getConversionSpecifier() const { 571 return cast<ScanfConversionSpecifier>(CS); 572 } 573 574 bool consumesDataArgument() const { 575 return CS.consumesDataArgument() && !SuppressAssignment; 576 } 577 578 ArgType getArgType(ASTContext &Ctx) const; 579 580 bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx); 581 582 void toString(raw_ostream &os) const; 583 584 static ScanfSpecifier Parse(const char *beg, const char *end); 585}; 586 587} // end analyze_scanf namespace 588 589//===----------------------------------------------------------------------===// 590// Parsing and processing of format strings (both fprintf and fscanf). 591 592namespace analyze_format_string { 593 594enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 }; 595 596class FormatStringHandler { 597public: 598 FormatStringHandler() {} 599 virtual ~FormatStringHandler(); 600 601 virtual void HandleNullChar(const char *nullCharacter) {} 602 603 virtual void HandlePosition(const char *startPos, unsigned posLen) {} 604 605 virtual void HandleInvalidPosition(const char *startPos, unsigned posLen, 606 PositionContext p) {} 607 608 virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {} 609 610 virtual void HandleIncompleteSpecifier(const char *startSpecifier, 611 unsigned specifierLen) {} 612 613 // Printf-specific handlers. 614 615 virtual bool HandleInvalidPrintfConversionSpecifier( 616 const analyze_printf::PrintfSpecifier &FS, 617 const char *startSpecifier, 618 unsigned specifierLen) { 619 return true; 620 } 621 622 virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, 623 const char *startSpecifier, 624 unsigned specifierLen) { 625 return true; 626 } 627 628 // Scanf-specific handlers. 629 630 virtual bool HandleInvalidScanfConversionSpecifier( 631 const analyze_scanf::ScanfSpecifier &FS, 632 const char *startSpecifier, 633 unsigned specifierLen) { 634 return true; 635 } 636 637 virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, 638 const char *startSpecifier, 639 unsigned specifierLen) { 640 return true; 641 } 642 643 virtual void HandleIncompleteScanList(const char *start, const char *end) {} 644}; 645 646bool ParsePrintfString(FormatStringHandler &H, 647 const char *beg, const char *end, const LangOptions &LO, 648 const TargetInfo &Target); 649 650bool ParseScanfString(FormatStringHandler &H, 651 const char *beg, const char *end, const LangOptions &LO, 652 const TargetInfo &Target); 653 654} // end analyze_format_string namespace 655} // end clang namespace 656#endif 657