1212795Sdim//= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===// 2212795Sdim// 3212795Sdim// The LLVM Compiler Infrastructure 4212795Sdim// 5212795Sdim// This file is distributed under the University of Illinois Open Source 6212795Sdim// License. See LICENSE.TXT for details. 7212795Sdim// 8212795Sdim//===----------------------------------------------------------------------===// 9212795Sdim// 10212795Sdim// This file defines APIs for analyzing the format strings of printf, fscanf, 11212795Sdim// and friends. 12212795Sdim// 13212795Sdim// The structure of format strings for fprintf are described in C99 7.19.6.1. 14212795Sdim// 15212795Sdim// The structure of format strings for fscanf are described in C99 7.19.6.2. 16212795Sdim// 17212795Sdim//===----------------------------------------------------------------------===// 18212795Sdim 19212795Sdim#ifndef LLVM_CLANG_FORMAT_H 20212795Sdim#define LLVM_CLANG_FORMAT_H 21212795Sdim 22212795Sdim#include "clang/AST/CanonicalType.h" 23212795Sdim 24212795Sdimnamespace clang { 25212795Sdim 26245431Sdimclass TargetInfo; 27245431Sdim 28212795Sdim//===----------------------------------------------------------------------===// 29212795Sdim/// Common components of both fprintf and fscanf format strings. 30212795Sdimnamespace analyze_format_string { 31212795Sdim 32212795Sdim/// Class representing optional flags with location and representation 33212795Sdim/// information. 34212795Sdimclass OptionalFlag { 35212795Sdimpublic: 36212795Sdim OptionalFlag(const char *Representation) 37212795Sdim : representation(Representation), flag(false) {} 38212795Sdim bool isSet() { return flag; } 39212795Sdim void set() { flag = true; } 40212795Sdim void clear() { flag = false; } 41212795Sdim void setPosition(const char *position) { 42212795Sdim assert(position); 43212795Sdim this->position = position; 44212795Sdim } 45212795Sdim const char *getPosition() const { 46212795Sdim assert(position); 47212795Sdim return position; 48212795Sdim } 49212795Sdim const char *toString() const { return representation; } 50212795Sdim 51212795Sdim // Overloaded operators for bool like qualities 52263509Sdim LLVM_EXPLICIT operator bool() const { return flag; } 53212795Sdim OptionalFlag& operator=(const bool &rhs) { 54212795Sdim flag = rhs; 55212795Sdim return *this; // Return a reference to myself. 56212795Sdim } 57212795Sdimprivate: 58212795Sdim const char *representation; 59212795Sdim const char *position; 60212795Sdim bool flag; 61212795Sdim}; 62212795Sdim 63212795Sdim/// Represents the length modifier in a format string in scanf/printf. 64212795Sdimclass LengthModifier { 65212795Sdimpublic: 66212795Sdim enum Kind { 67212795Sdim None, 68212795Sdim AsChar, // 'hh' 69212795Sdim AsShort, // 'h' 70212795Sdim AsLong, // 'l' 71235633Sdim AsLongLong, // 'll' 72235633Sdim AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types) 73212795Sdim AsIntMax, // 'j' 74212795Sdim AsSizeT, // 'z' 75212795Sdim AsPtrDiff, // 't' 76263509Sdim AsInt32, // 'I32' (MSVCRT, like __int32) 77263509Sdim AsInt3264, // 'I' (MSVCRT, like __int3264 from MIDL) 78263509Sdim AsInt64, // 'I64' (MSVCRT, like __int64) 79212795Sdim AsLongDouble, // 'L' 80235633Sdim AsAllocate, // for '%as', GNU extension to C90 scanf 81235633Sdim AsMAllocate, // for '%ms', GNU extension to scanf 82212795Sdim AsWideChar = AsLong // for '%ls', only makes sense for printf 83212795Sdim }; 84212795Sdim 85212795Sdim LengthModifier() 86212795Sdim : Position(0), kind(None) {} 87212795Sdim LengthModifier(const char *pos, Kind k) 88212795Sdim : Position(pos), kind(k) {} 89212795Sdim 90212795Sdim const char *getStart() const { 91212795Sdim return Position; 92212795Sdim } 93212795Sdim 94212795Sdim unsigned getLength() const { 95212795Sdim switch (kind) { 96212795Sdim default: 97212795Sdim return 1; 98212795Sdim case AsLongLong: 99212795Sdim case AsChar: 100212795Sdim return 2; 101263509Sdim case AsInt32: 102263509Sdim case AsInt64: 103263509Sdim return 3; 104212795Sdim case None: 105212795Sdim return 0; 106212795Sdim } 107212795Sdim } 108212795Sdim 109212795Sdim Kind getKind() const { return kind; } 110212795Sdim void setKind(Kind k) { kind = k; } 111212795Sdim 112212795Sdim const char *toString() const; 113212795Sdim 114212795Sdimprivate: 115212795Sdim const char *Position; 116212795Sdim Kind kind; 117212795Sdim}; 118235633Sdim 119212795Sdimclass ConversionSpecifier { 120212795Sdimpublic: 121212795Sdim enum Kind { 122212795Sdim InvalidSpecifier = 0, 123212795Sdim // C99 conversion specifiers. 124212795Sdim cArg, 125212795Sdim dArg, 126245431Sdim DArg, // Apple extension 127212795Sdim iArg, 128245431Sdim IntArgBeg = dArg, IntArgEnd = iArg, 129235633Sdim 130212795Sdim oArg, 131245431Sdim OArg, // Apple extension 132212795Sdim uArg, 133245431Sdim UArg, // Apple extension 134212795Sdim xArg, 135212795Sdim XArg, 136212795Sdim UIntArgBeg = oArg, UIntArgEnd = XArg, 137235633Sdim 138212795Sdim fArg, 139212795Sdim FArg, 140212795Sdim eArg, 141212795Sdim EArg, 142212795Sdim gArg, 143212795Sdim GArg, 144212795Sdim aArg, 145212795Sdim AArg, 146212795Sdim DoubleArgBeg = fArg, DoubleArgEnd = AArg, 147235633Sdim 148212795Sdim sArg, 149212795Sdim pArg, 150212795Sdim nArg, 151212795Sdim PercentArg, 152212795Sdim CArg, 153212795Sdim SArg, 154235633Sdim 155212795Sdim // ** Printf-specific ** 156235633Sdim 157212795Sdim // Objective-C specific specifiers. 158212795Sdim ObjCObjArg, // '@' 159212795Sdim ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg, 160235633Sdim 161212904Sdim // FreeBSD specific specifiers 162245431Sdim FreeBSDbArg, 163245431Sdim FreeBSDDArg, 164245431Sdim FreeBSDrArg, 165235633Sdim 166212795Sdim // GlibC specific specifiers. 167212795Sdim PrintErrno, // 'm' 168235633Sdim 169212795Sdim PrintfConvBeg = ObjCObjArg, PrintfConvEnd = PrintErrno, 170235633Sdim 171235633Sdim // ** Scanf-specific ** 172212795Sdim ScanListArg, // '[' 173212795Sdim ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg 174212795Sdim }; 175235633Sdim 176245431Sdim ConversionSpecifier(bool isPrintf = true) 177212795Sdim : IsPrintf(isPrintf), Position(0), EndScanList(0), kind(InvalidSpecifier) {} 178235633Sdim 179212795Sdim ConversionSpecifier(bool isPrintf, const char *pos, Kind k) 180212795Sdim : IsPrintf(isPrintf), Position(pos), EndScanList(0), kind(k) {} 181235633Sdim 182212795Sdim const char *getStart() const { 183212795Sdim return Position; 184212795Sdim } 185235633Sdim 186226890Sdim StringRef getCharacters() const { 187226890Sdim return StringRef(getStart(), getLength()); 188212795Sdim } 189235633Sdim 190212795Sdim bool consumesDataArgument() const { 191212795Sdim switch (kind) { 192212795Sdim case PrintErrno: 193212795Sdim assert(IsPrintf); 194245431Sdim return false; 195212795Sdim case PercentArg: 196212795Sdim return false; 197212795Sdim default: 198212795Sdim return true; 199212795Sdim } 200212795Sdim } 201235633Sdim 202212795Sdim Kind getKind() const { return kind; } 203212795Sdim void setKind(Kind k) { kind = k; } 204212795Sdim unsigned getLength() const { 205212795Sdim return EndScanList ? EndScanList - Position : 1; 206212795Sdim } 207235633Sdim 208245431Sdim bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; } 209235633Sdim bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; } 210245431Sdim bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; } 211212795Sdim const char *toString() const; 212235633Sdim 213212795Sdim bool isPrintfKind() const { return IsPrintf; } 214245431Sdim 215252723Sdim Optional<ConversionSpecifier> getStandardSpecifier() const; 216212795Sdim 217212795Sdimprotected: 218212795Sdim bool IsPrintf; 219212795Sdim const char *Position; 220212795Sdim const char *EndScanList; 221212795Sdim Kind kind; 222212795Sdim}; 223212795Sdim 224245431Sdimclass ArgType { 225212795Sdimpublic: 226212795Sdim enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy, 227235633Sdim AnyCharTy, CStrTy, WCStrTy, WIntTy }; 228212795Sdimprivate: 229212795Sdim const Kind K; 230212795Sdim QualType T; 231235633Sdim const char *Name; 232245431Sdim bool Ptr; 233212795Sdimpublic: 234245431Sdim ArgType(Kind k = UnknownTy, const char *n = 0) : K(k), Name(n), Ptr(false) {} 235245431Sdim ArgType(QualType t, const char *n = 0) 236245431Sdim : K(SpecificTy), T(t), Name(n), Ptr(false) {} 237245431Sdim ArgType(CanQualType t) : K(SpecificTy), T(t), Name(0), Ptr(false) {} 238212795Sdim 239245431Sdim static ArgType Invalid() { return ArgType(InvalidTy); } 240212795Sdim bool isValid() const { return K != InvalidTy; } 241212795Sdim 242245431Sdim /// Create an ArgType which corresponds to the type pointer to A. 243245431Sdim static ArgType PtrTo(const ArgType& A) { 244245431Sdim assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown"); 245245431Sdim ArgType Res = A; 246245431Sdim Res.Ptr = true; 247245431Sdim return Res; 248212795Sdim } 249212795Sdim 250212795Sdim bool matchesType(ASTContext &C, QualType argTy) const; 251212795Sdim 252212795Sdim QualType getRepresentativeType(ASTContext &C) const; 253235633Sdim 254235633Sdim std::string getRepresentativeTypeName(ASTContext &C) const; 255212795Sdim}; 256212795Sdim 257212795Sdimclass OptionalAmount { 258212795Sdimpublic: 259212795Sdim enum HowSpecified { NotSpecified, Constant, Arg, Invalid }; 260212795Sdim 261212795Sdim OptionalAmount(HowSpecified howSpecified, 262212795Sdim unsigned amount, 263212795Sdim const char *amountStart, 264212795Sdim unsigned amountLength, 265212795Sdim bool usesPositionalArg) 266212795Sdim : start(amountStart), length(amountLength), hs(howSpecified), amt(amount), 267212795Sdim UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {} 268212795Sdim 269212795Sdim OptionalAmount(bool valid = true) 270212795Sdim : start(0),length(0), hs(valid ? NotSpecified : Invalid), amt(0), 271212795Sdim UsesPositionalArg(0), UsesDotPrefix(0) {} 272212795Sdim 273212795Sdim bool isInvalid() const { 274212795Sdim return hs == Invalid; 275212795Sdim } 276212795Sdim 277212795Sdim HowSpecified getHowSpecified() const { return hs; } 278212795Sdim void setHowSpecified(HowSpecified h) { hs = h; } 279212795Sdim 280212795Sdim bool hasDataArgument() const { return hs == Arg; } 281212795Sdim 282212795Sdim unsigned getArgIndex() const { 283212795Sdim assert(hasDataArgument()); 284212795Sdim return amt; 285212795Sdim } 286212795Sdim 287212795Sdim unsigned getConstantAmount() const { 288212795Sdim assert(hs == Constant); 289212795Sdim return amt; 290212795Sdim } 291212795Sdim 292212795Sdim const char *getStart() const { 293212795Sdim // We include the . character if it is given. 294212795Sdim return start - UsesDotPrefix; 295212795Sdim } 296212795Sdim 297212795Sdim unsigned getConstantLength() const { 298212795Sdim assert(hs == Constant); 299212795Sdim return length + UsesDotPrefix; 300212795Sdim } 301212795Sdim 302245431Sdim ArgType getArgType(ASTContext &Ctx) const; 303212795Sdim 304226890Sdim void toString(raw_ostream &os) const; 305212795Sdim 306212795Sdim bool usesPositionalArg() const { return (bool) UsesPositionalArg; } 307212795Sdim unsigned getPositionalArgIndex() const { 308212795Sdim assert(hasDataArgument()); 309212795Sdim return amt + 1; 310212795Sdim } 311212795Sdim 312212795Sdim bool usesDotPrefix() const { return UsesDotPrefix; } 313212795Sdim void setUsesDotPrefix() { UsesDotPrefix = true; } 314212795Sdim 315212795Sdimprivate: 316212795Sdim const char *start; 317212795Sdim unsigned length; 318212795Sdim HowSpecified hs; 319212795Sdim unsigned amt; 320212795Sdim bool UsesPositionalArg : 1; 321212795Sdim bool UsesDotPrefix; 322212795Sdim}; 323212795Sdim 324212795Sdim 325212795Sdimclass FormatSpecifier { 326212795Sdimprotected: 327212795Sdim LengthModifier LM; 328212795Sdim OptionalAmount FieldWidth; 329212795Sdim ConversionSpecifier CS; 330235633Sdim /// Positional arguments, an IEEE extension: 331235633Sdim /// IEEE Std 1003.1, 2004 Edition 332235633Sdim /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html 333212795Sdim bool UsesPositionalArg; 334212795Sdim unsigned argIndex; 335212795Sdimpublic: 336212795Sdim FormatSpecifier(bool isPrintf) 337212795Sdim : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {} 338212795Sdim 339212795Sdim void setLengthModifier(LengthModifier lm) { 340212795Sdim LM = lm; 341212795Sdim } 342212795Sdim 343212795Sdim void setUsesPositionalArg() { UsesPositionalArg = true; } 344212795Sdim 345212795Sdim void setArgIndex(unsigned i) { 346212795Sdim argIndex = i; 347212795Sdim } 348212795Sdim 349212795Sdim unsigned getArgIndex() const { 350212795Sdim return argIndex; 351212795Sdim } 352212795Sdim 353212795Sdim unsigned getPositionalArgIndex() const { 354212795Sdim return argIndex + 1; 355212795Sdim } 356212795Sdim 357212795Sdim const LengthModifier &getLengthModifier() const { 358212795Sdim return LM; 359212795Sdim } 360212795Sdim 361212795Sdim const OptionalAmount &getFieldWidth() const { 362212795Sdim return FieldWidth; 363212795Sdim } 364212795Sdim 365212795Sdim void setFieldWidth(const OptionalAmount &Amt) { 366212795Sdim FieldWidth = Amt; 367212795Sdim } 368212795Sdim 369212795Sdim bool usesPositionalArg() const { return UsesPositionalArg; } 370235633Sdim 371245431Sdim bool hasValidLengthModifier(const TargetInfo &Target) const; 372235633Sdim 373235633Sdim bool hasStandardLengthModifier() const; 374235633Sdim 375252723Sdim Optional<LengthModifier> getCorrectedLengthModifier() const; 376245431Sdim 377235633Sdim bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const; 378235633Sdim 379235633Sdim bool hasStandardLengthConversionCombination() const; 380245431Sdim 381245431Sdim /// For a TypedefType QT, if it is a named integer type such as size_t, 382245431Sdim /// assign the appropriate value to LM and return true. 383245431Sdim static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM); 384212795Sdim}; 385212795Sdim 386212795Sdim} // end analyze_format_string namespace 387212795Sdim 388212795Sdim//===----------------------------------------------------------------------===// 389212795Sdim/// Pieces specific to fprintf format strings. 390212795Sdim 391212795Sdimnamespace analyze_printf { 392212795Sdim 393235633Sdimclass PrintfConversionSpecifier : 394212795Sdim public analyze_format_string::ConversionSpecifier { 395212795Sdimpublic: 396212795Sdim PrintfConversionSpecifier() 397212795Sdim : ConversionSpecifier(true, 0, InvalidSpecifier) {} 398212795Sdim 399212795Sdim PrintfConversionSpecifier(const char *pos, Kind k) 400212795Sdim : ConversionSpecifier(true, pos, k) {} 401212795Sdim 402212795Sdim bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; } 403235633Sdim bool isDoubleArg() const { return kind >= DoubleArgBeg && 404235633Sdim kind <= DoubleArgEnd; } 405212795Sdim unsigned getLength() const { 406212795Sdim // Conversion specifiers currently only are represented by 407212795Sdim // single characters, but we be flexible. 408212795Sdim return 1; 409212795Sdim } 410212795Sdim 411212795Sdim static bool classof(const analyze_format_string::ConversionSpecifier *CS) { 412212795Sdim return CS->isPrintfKind(); 413212795Sdim } 414212795Sdim}; 415212795Sdim 416245431Sdimusing analyze_format_string::ArgType; 417212795Sdimusing analyze_format_string::LengthModifier; 418212795Sdimusing analyze_format_string::OptionalAmount; 419212795Sdimusing analyze_format_string::OptionalFlag; 420212795Sdim 421212795Sdimclass PrintfSpecifier : public analyze_format_string::FormatSpecifier { 422218893Sdim OptionalFlag HasThousandsGrouping; // ''', POSIX extension. 423212795Sdim OptionalFlag IsLeftJustified; // '-' 424212795Sdim OptionalFlag HasPlusPrefix; // '+' 425212795Sdim OptionalFlag HasSpacePrefix; // ' ' 426212795Sdim OptionalFlag HasAlternativeForm; // '#' 427212795Sdim OptionalFlag HasLeadingZeroes; // '0' 428212795Sdim OptionalAmount Precision; 429212795Sdimpublic: 430212795Sdim PrintfSpecifier() : 431212795Sdim FormatSpecifier(/* isPrintf = */ true), 432218893Sdim HasThousandsGrouping("'"), IsLeftJustified("-"), HasPlusPrefix("+"), 433218893Sdim HasSpacePrefix(" "), HasAlternativeForm("#"), HasLeadingZeroes("0") {} 434212795Sdim 435212795Sdim static PrintfSpecifier Parse(const char *beg, const char *end); 436212795Sdim 437212795Sdim // Methods for incrementally constructing the PrintfSpecifier. 438212795Sdim void setConversionSpecifier(const PrintfConversionSpecifier &cs) { 439212795Sdim CS = cs; 440212795Sdim } 441218893Sdim void setHasThousandsGrouping(const char *position) { 442218893Sdim HasThousandsGrouping = true; 443218893Sdim HasThousandsGrouping.setPosition(position); 444218893Sdim } 445212795Sdim void setIsLeftJustified(const char *position) { 446212795Sdim IsLeftJustified = true; 447212795Sdim IsLeftJustified.setPosition(position); 448212795Sdim } 449212795Sdim void setHasPlusPrefix(const char *position) { 450212795Sdim HasPlusPrefix = true; 451212795Sdim HasPlusPrefix.setPosition(position); 452212795Sdim } 453212795Sdim void setHasSpacePrefix(const char *position) { 454212795Sdim HasSpacePrefix = true; 455212795Sdim HasSpacePrefix.setPosition(position); 456212795Sdim } 457212795Sdim void setHasAlternativeForm(const char *position) { 458212795Sdim HasAlternativeForm = true; 459212795Sdim HasAlternativeForm.setPosition(position); 460212795Sdim } 461212795Sdim void setHasLeadingZeros(const char *position) { 462212795Sdim HasLeadingZeroes = true; 463212795Sdim HasLeadingZeroes.setPosition(position); 464212795Sdim } 465212795Sdim void setUsesPositionalArg() { UsesPositionalArg = true; } 466212795Sdim 467212795Sdim // Methods for querying the format specifier. 468212795Sdim 469212795Sdim const PrintfConversionSpecifier &getConversionSpecifier() const { 470212795Sdim return cast<PrintfConversionSpecifier>(CS); 471212795Sdim } 472212795Sdim 473212795Sdim void setPrecision(const OptionalAmount &Amt) { 474212795Sdim Precision = Amt; 475212795Sdim Precision.setUsesDotPrefix(); 476212795Sdim } 477212795Sdim 478212795Sdim const OptionalAmount &getPrecision() const { 479212795Sdim return Precision; 480212795Sdim } 481235633Sdim 482212795Sdim bool consumesDataArgument() const { 483212795Sdim return getConversionSpecifier().consumesDataArgument(); 484212795Sdim } 485212795Sdim 486212795Sdim /// \brief Returns the builtin type that a data argument 487212795Sdim /// paired with this format specifier should have. This method 488212795Sdim /// will return null if the format specifier does not have 489212795Sdim /// a matching data argument or the matching argument matches 490212795Sdim /// more than one type. 491245431Sdim ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const; 492212795Sdim 493235633Sdim const OptionalFlag &hasThousandsGrouping() const { 494218893Sdim return HasThousandsGrouping; 495218893Sdim } 496212795Sdim const OptionalFlag &isLeftJustified() const { return IsLeftJustified; } 497212795Sdim const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; } 498212795Sdim const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; } 499212795Sdim const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; } 500212795Sdim const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; } 501212795Sdim bool usesPositionalArg() const { return UsesPositionalArg; } 502212795Sdim 503235633Sdim /// Changes the specifier and length according to a QualType, retaining any 504235633Sdim /// flags or options. Returns true on success, or false when a conversion 505235633Sdim /// was not successful. 506235633Sdim bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx, 507235633Sdim bool IsObjCLiteral); 508212795Sdim 509226890Sdim void toString(raw_ostream &os) const; 510212795Sdim 511235633Sdim // Validation methods - to check if any element results in undefined behavior 512212795Sdim bool hasValidPlusPrefix() const; 513212795Sdim bool hasValidAlternativeForm() const; 514212795Sdim bool hasValidLeadingZeros() const; 515212795Sdim bool hasValidSpacePrefix() const; 516212795Sdim bool hasValidLeftJustified() const; 517218893Sdim bool hasValidThousandsGroupingPrefix() const; 518212795Sdim 519212795Sdim bool hasValidPrecision() const; 520212795Sdim bool hasValidFieldWidth() const; 521212795Sdim}; 522212795Sdim} // end analyze_printf namespace 523212795Sdim 524212795Sdim//===----------------------------------------------------------------------===// 525212795Sdim/// Pieces specific to fscanf format strings. 526212795Sdim 527212795Sdimnamespace analyze_scanf { 528212795Sdim 529212795Sdimclass ScanfConversionSpecifier : 530212795Sdim public analyze_format_string::ConversionSpecifier { 531212795Sdimpublic: 532212795Sdim ScanfConversionSpecifier() 533212795Sdim : ConversionSpecifier(false, 0, InvalidSpecifier) {} 534212795Sdim 535212795Sdim ScanfConversionSpecifier(const char *pos, Kind k) 536212795Sdim : ConversionSpecifier(false, pos, k) {} 537212795Sdim 538212795Sdim void setEndScanList(const char *pos) { EndScanList = pos; } 539235633Sdim 540212795Sdim static bool classof(const analyze_format_string::ConversionSpecifier *CS) { 541212795Sdim return !CS->isPrintfKind(); 542235633Sdim } 543212795Sdim}; 544212795Sdim 545245431Sdimusing analyze_format_string::ArgType; 546212795Sdimusing analyze_format_string::LengthModifier; 547212795Sdimusing analyze_format_string::OptionalAmount; 548212795Sdimusing analyze_format_string::OptionalFlag; 549212795Sdim 550212795Sdimclass ScanfSpecifier : public analyze_format_string::FormatSpecifier { 551212795Sdim OptionalFlag SuppressAssignment; // '*' 552212795Sdimpublic: 553212795Sdim ScanfSpecifier() : 554212795Sdim FormatSpecifier(/* isPrintf = */ false), 555212795Sdim SuppressAssignment("*") {} 556212795Sdim 557212795Sdim void setSuppressAssignment(const char *position) { 558212795Sdim SuppressAssignment = true; 559212795Sdim SuppressAssignment.setPosition(position); 560212795Sdim } 561212795Sdim 562212795Sdim const OptionalFlag &getSuppressAssignment() const { 563212795Sdim return SuppressAssignment; 564212795Sdim } 565212795Sdim 566212795Sdim void setConversionSpecifier(const ScanfConversionSpecifier &cs) { 567212795Sdim CS = cs; 568212795Sdim } 569212795Sdim 570212795Sdim const ScanfConversionSpecifier &getConversionSpecifier() const { 571212795Sdim return cast<ScanfConversionSpecifier>(CS); 572212795Sdim } 573235633Sdim 574212795Sdim bool consumesDataArgument() const { 575212795Sdim return CS.consumesDataArgument() && !SuppressAssignment; 576212795Sdim } 577212795Sdim 578245431Sdim ArgType getArgType(ASTContext &Ctx) const; 579235633Sdim 580235633Sdim bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx); 581235633Sdim 582235633Sdim void toString(raw_ostream &os) const; 583235633Sdim 584212795Sdim static ScanfSpecifier Parse(const char *beg, const char *end); 585212795Sdim}; 586212795Sdim 587212795Sdim} // end analyze_scanf namespace 588212795Sdim 589212795Sdim//===----------------------------------------------------------------------===// 590212795Sdim// Parsing and processing of format strings (both fprintf and fscanf). 591212795Sdim 592212795Sdimnamespace analyze_format_string { 593212795Sdim 594212795Sdimenum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 }; 595212795Sdim 596212795Sdimclass FormatStringHandler { 597212795Sdimpublic: 598212795Sdim FormatStringHandler() {} 599212795Sdim virtual ~FormatStringHandler(); 600212795Sdim 601212795Sdim virtual void HandleNullChar(const char *nullCharacter) {} 602212795Sdim 603235633Sdim virtual void HandlePosition(const char *startPos, unsigned posLen) {} 604235633Sdim 605212795Sdim virtual void HandleInvalidPosition(const char *startPos, unsigned posLen, 606212795Sdim PositionContext p) {} 607212795Sdim 608212795Sdim virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {} 609212795Sdim 610212795Sdim virtual void HandleIncompleteSpecifier(const char *startSpecifier, 611212795Sdim unsigned specifierLen) {} 612212795Sdim 613212795Sdim // Printf-specific handlers. 614212795Sdim 615212795Sdim virtual bool HandleInvalidPrintfConversionSpecifier( 616212795Sdim const analyze_printf::PrintfSpecifier &FS, 617212795Sdim const char *startSpecifier, 618212795Sdim unsigned specifierLen) { 619212795Sdim return true; 620212795Sdim } 621212795Sdim 622212795Sdim virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, 623212795Sdim const char *startSpecifier, 624212795Sdim unsigned specifierLen) { 625212795Sdim return true; 626212795Sdim } 627212795Sdim 628212795Sdim // Scanf-specific handlers. 629212795Sdim 630212795Sdim virtual bool HandleInvalidScanfConversionSpecifier( 631212795Sdim const analyze_scanf::ScanfSpecifier &FS, 632212795Sdim const char *startSpecifier, 633212795Sdim unsigned specifierLen) { 634212795Sdim return true; 635212795Sdim } 636212795Sdim 637212795Sdim virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, 638212795Sdim const char *startSpecifier, 639212795Sdim unsigned specifierLen) { 640212795Sdim return true; 641212795Sdim } 642212795Sdim 643212795Sdim virtual void HandleIncompleteScanList(const char *start, const char *end) {} 644212795Sdim}; 645212795Sdim 646212795Sdimbool ParsePrintfString(FormatStringHandler &H, 647245431Sdim const char *beg, const char *end, const LangOptions &LO, 648245431Sdim const TargetInfo &Target); 649212795Sdim 650212795Sdimbool ParseScanfString(FormatStringHandler &H, 651245431Sdim const char *beg, const char *end, const LangOptions &LO, 652245431Sdim const TargetInfo &Target); 653212795Sdim 654212795Sdim} // end analyze_format_string namespace 655212795Sdim} // end clang namespace 656212795Sdim#endif 657