| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
| 18 | #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H |
| 19 | #define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H |
| 20 | |
| 21 | #include "clang/AST/CanonicalType.h" |
| 22 | |
| 23 | namespace clang { |
| 24 | |
| 25 | class TargetInfo; |
| 26 | |
| 27 | |
| 28 | |
| 29 | namespace analyze_format_string { |
| 30 | |
| 31 | |
| 32 | |
| 33 | class OptionalFlag { |
| 34 | public: |
| 35 | OptionalFlag(const char *Representation) |
| 36 | : representation(Representation), flag(false) {} |
| 37 | bool isSet() const { return flag; } |
| 38 | void set() { flag = true; } |
| 39 | void clear() { flag = false; } |
| 40 | void setPosition(const char *position) { |
| 41 | assert(position); |
| 42 | flag = true; |
| 43 | this->position = position; |
| 44 | } |
| 45 | const char *getPosition() const { |
| 46 | assert(position); |
| 47 | return position; |
| 48 | } |
| 49 | const char *toString() const { return representation; } |
| 50 | |
| 51 | |
| 52 | explicit operator bool() const { return flag; } |
| 53 | OptionalFlag& operator=(const bool &rhs) { |
| 54 | flag = rhs; |
| 55 | return *this; |
| 56 | } |
| 57 | private: |
| 58 | const char *representation; |
| 59 | const char *position; |
| 60 | bool flag; |
| 61 | }; |
| 62 | |
| 63 | |
| 64 | class LengthModifier { |
| 65 | public: |
| 66 | enum Kind { |
| 67 | None, |
| 68 | AsChar, |
| 69 | AsShort, |
| 70 | AsShortLong, |
| 71 | AsLong, |
| 72 | AsLongLong, |
| 73 | AsQuad, |
| 74 | AsIntMax, |
| 75 | AsSizeT, |
| 76 | AsPtrDiff, |
| 77 | AsInt32, |
| 78 | AsInt3264, |
| 79 | AsInt64, |
| 80 | AsLongDouble, |
| 81 | AsAllocate, |
| 82 | AsMAllocate, |
| 83 | AsWide, |
| 84 | AsWideChar = AsLong |
| 85 | }; |
| 86 | |
| 87 | LengthModifier() |
| 88 | : Position(nullptr), kind(None) {} |
| 89 | LengthModifier(const char *pos, Kind k) |
| 90 | : Position(pos), kind(k) {} |
| 91 | |
| 92 | const char *getStart() const { |
| 93 | return Position; |
| 94 | } |
| 95 | |
| 96 | unsigned getLength() const { |
| 97 | switch (kind) { |
| 98 | default: |
| 99 | return 1; |
| 100 | case AsLongLong: |
| 101 | case AsChar: |
| 102 | return 2; |
| 103 | case AsInt32: |
| 104 | case AsInt64: |
| 105 | return 3; |
| 106 | case None: |
| 107 | return 0; |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | Kind getKind() const { return kind; } |
| 112 | void setKind(Kind k) { kind = k; } |
| 113 | |
| 114 | const char *toString() const; |
| 115 | |
| 116 | private: |
| 117 | const char *Position; |
| 118 | Kind kind; |
| 119 | }; |
| 120 | |
| 121 | class ConversionSpecifier { |
| 122 | public: |
| 123 | enum Kind { |
| 124 | InvalidSpecifier = 0, |
| 125 | |
| 126 | cArg, |
| 127 | dArg, |
| 128 | DArg, |
| 129 | iArg, |
| 130 | IntArgBeg = dArg, |
| 131 | IntArgEnd = iArg, |
| 132 | |
| 133 | oArg, |
| 134 | OArg, |
| 135 | uArg, |
| 136 | UArg, |
| 137 | xArg, |
| 138 | XArg, |
| 139 | UIntArgBeg = oArg, |
| 140 | UIntArgEnd = XArg, |
| 141 | |
| 142 | fArg, |
| 143 | FArg, |
| 144 | eArg, |
| 145 | EArg, |
| 146 | gArg, |
| 147 | GArg, |
| 148 | aArg, |
| 149 | AArg, |
| 150 | DoubleArgBeg = fArg, |
| 151 | DoubleArgEnd = AArg, |
| 152 | |
| 153 | sArg, |
| 154 | pArg, |
| 155 | nArg, |
| 156 | PercentArg, |
| 157 | CArg, |
| 158 | SArg, |
| 159 | |
| 160 | |
| 161 | |
| 162 | |
| 163 | PArg, |
| 164 | |
| 165 | |
| 166 | |
| 167 | ZArg, |
| 168 | |
| 169 | |
| 170 | ObjCObjArg, |
| 171 | ObjCBeg = ObjCObjArg, |
| 172 | ObjCEnd = ObjCObjArg, |
| 173 | |
| 174 | |
| 175 | FreeBSDbArg, |
| 176 | FreeBSDDArg, |
| 177 | FreeBSDrArg, |
| 178 | FreeBSDyArg, |
| 179 | |
| 180 | |
| 181 | PrintErrno, |
| 182 | |
| 183 | PrintfConvBeg = ObjCObjArg, |
| 184 | PrintfConvEnd = PrintErrno, |
| 185 | |
| 186 | |
| 187 | ScanListArg, |
| 188 | ScanfConvBeg = ScanListArg, |
| 189 | ScanfConvEnd = ScanListArg |
| 190 | }; |
| 191 | |
| 192 | ConversionSpecifier(bool isPrintf = true) |
| 193 | : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr), |
| 194 | kind(InvalidSpecifier) {} |
| 195 | |
| 196 | ConversionSpecifier(bool isPrintf, const char *pos, Kind k) |
| 197 | : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {} |
| 198 | |
| 199 | const char *getStart() const { |
| 200 | return Position; |
| 201 | } |
| 202 | |
| 203 | StringRef getCharacters() const { |
| 204 | return StringRef(getStart(), getLength()); |
| 205 | } |
| 206 | |
| 207 | bool consumesDataArgument() const { |
| 208 | switch (kind) { |
| 209 | case PrintErrno: |
| 210 | assert(IsPrintf); |
| 211 | return false; |
| 212 | case PercentArg: |
| 213 | return false; |
| 214 | case InvalidSpecifier: |
| 215 | return false; |
| 216 | default: |
| 217 | return true; |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | Kind getKind() const { return kind; } |
| 222 | void setKind(Kind k) { kind = k; } |
| 223 | unsigned getLength() const { |
| 224 | return EndScanList ? EndScanList - Position : 1; |
| 225 | } |
| 226 | void setEndScanList(const char *pos) { EndScanList = pos; } |
| 227 | |
| 228 | bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) || |
| 229 | kind == FreeBSDrArg || kind == FreeBSDyArg; } |
| 230 | bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; } |
| 231 | bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; } |
| 232 | bool isDoubleArg() const { |
| 233 | return kind >= DoubleArgBeg && kind <= DoubleArgEnd; |
| 234 | } |
| 235 | |
| 236 | const char *toString() const; |
| 237 | |
| 238 | bool isPrintfKind() const { return IsPrintf; } |
| 239 | |
| 240 | Optional<ConversionSpecifier> getStandardSpecifier() const; |
| 241 | |
| 242 | protected: |
| 243 | bool IsPrintf; |
| 244 | const char *Position; |
| 245 | const char *EndScanList; |
| 246 | Kind kind; |
| 247 | }; |
| 248 | |
| 249 | class ArgType { |
| 250 | public: |
| 251 | enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy, |
| 252 | AnyCharTy, CStrTy, WCStrTy, WIntTy }; |
| 253 | |
| 254 | enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic }; |
| 255 | |
| 256 | private: |
| 257 | const Kind K; |
| 258 | QualType T; |
| 259 | const char *Name = nullptr; |
| 260 | bool Ptr = false; |
| 261 | |
| 262 | |
| 263 | |
| 264 | enum class TypeKind { DontCare, SizeT, PtrdiffT }; |
| 265 | TypeKind TK = TypeKind::DontCare; |
| 266 | |
| 267 | public: |
| 268 | ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {} |
| 269 | ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {} |
| 270 | ArgType(CanQualType T) : K(SpecificTy), T(T) {} |
| 271 | |
| 272 | static ArgType Invalid() { return ArgType(InvalidTy); } |
| 273 | bool isValid() const { return K != InvalidTy; } |
| 274 | |
| 275 | bool isSizeT() const { return TK == TypeKind::SizeT; } |
| 276 | |
| 277 | bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; } |
| 278 | |
| 279 | |
| 280 | static ArgType PtrTo(const ArgType& A) { |
| 281 | (0) . __assert_fail ("A.K >= InvalidTy && \"ArgType cannot be pointer to invalid/unknown\"", "/home/seafit/code_projects/clang_source/clang/include/clang/AST/FormatString.h", 281, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown"); |
| 282 | ArgType Res = A; |
| 283 | Res.Ptr = true; |
| 284 | return Res; |
| 285 | } |
| 286 | |
| 287 | |
| 288 | static ArgType makeSizeT(const ArgType &A) { |
| 289 | ArgType Res = A; |
| 290 | Res.TK = TypeKind::SizeT; |
| 291 | return Res; |
| 292 | } |
| 293 | |
| 294 | |
| 295 | |
| 296 | static ArgType makePtrdiffT(const ArgType &A) { |
| 297 | ArgType Res = A; |
| 298 | Res.TK = TypeKind::PtrdiffT; |
| 299 | return Res; |
| 300 | } |
| 301 | |
| 302 | MatchKind matchesType(ASTContext &C, QualType argTy) const; |
| 303 | |
| 304 | QualType getRepresentativeType(ASTContext &C) const; |
| 305 | |
| 306 | ArgType makeVectorType(ASTContext &C, unsigned NumElts) const; |
| 307 | |
| 308 | std::string getRepresentativeTypeName(ASTContext &C) const; |
| 309 | }; |
| 310 | |
| 311 | class OptionalAmount { |
| 312 | public: |
| 313 | enum HowSpecified { NotSpecified, Constant, Arg, Invalid }; |
| 314 | |
| 315 | OptionalAmount(HowSpecified howSpecified, |
| 316 | unsigned amount, |
| 317 | const char *amountStart, |
| 318 | unsigned amountLength, |
| 319 | bool usesPositionalArg) |
| 320 | : start(amountStart), length(amountLength), hs(howSpecified), amt(amount), |
| 321 | UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {} |
| 322 | |
| 323 | OptionalAmount(bool valid = true) |
| 324 | : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0), |
| 325 | UsesPositionalArg(0), UsesDotPrefix(0) {} |
| 326 | |
| 327 | explicit OptionalAmount(unsigned Amount) |
| 328 | : start(nullptr), length(0), hs(Constant), amt(Amount), |
| 329 | UsesPositionalArg(false), UsesDotPrefix(false) {} |
| 330 | |
| 331 | bool isInvalid() const { |
| 332 | return hs == Invalid; |
| 333 | } |
| 334 | |
| 335 | HowSpecified getHowSpecified() const { return hs; } |
| 336 | void setHowSpecified(HowSpecified h) { hs = h; } |
| 337 | |
| 338 | bool hasDataArgument() const { return hs == Arg; } |
| 339 | |
| 340 | unsigned getArgIndex() const { |
| 341 | assert(hasDataArgument()); |
| 342 | return amt; |
| 343 | } |
| 344 | |
| 345 | unsigned getConstantAmount() const { |
| 346 | assert(hs == Constant); |
| 347 | return amt; |
| 348 | } |
| 349 | |
| 350 | const char *getStart() const { |
| 351 | |
| 352 | return start - UsesDotPrefix; |
| 353 | } |
| 354 | |
| 355 | unsigned getConstantLength() const { |
| 356 | assert(hs == Constant); |
| 357 | return length + UsesDotPrefix; |
| 358 | } |
| 359 | |
| 360 | ArgType getArgType(ASTContext &Ctx) const; |
| 361 | |
| 362 | void toString(raw_ostream &os) const; |
| 363 | |
| 364 | bool usesPositionalArg() const { return (bool) UsesPositionalArg; } |
| 365 | unsigned getPositionalArgIndex() const { |
| 366 | assert(hasDataArgument()); |
| 367 | return amt + 1; |
| 368 | } |
| 369 | |
| 370 | bool usesDotPrefix() const { return UsesDotPrefix; } |
| 371 | void setUsesDotPrefix() { UsesDotPrefix = true; } |
| 372 | |
| 373 | private: |
| 374 | const char *start; |
| 375 | unsigned length; |
| 376 | HowSpecified hs; |
| 377 | unsigned amt; |
| 378 | bool UsesPositionalArg : 1; |
| 379 | bool UsesDotPrefix; |
| 380 | }; |
| 381 | |
| 382 | |
| 383 | class FormatSpecifier { |
| 384 | protected: |
| 385 | LengthModifier LM; |
| 386 | OptionalAmount FieldWidth; |
| 387 | ConversionSpecifier CS; |
| 388 | OptionalAmount VectorNumElts; |
| 389 | |
| 390 | |
| 391 | |
| 392 | |
| 393 | bool UsesPositionalArg; |
| 394 | unsigned argIndex; |
| 395 | public: |
| 396 | FormatSpecifier(bool isPrintf) |
| 397 | : CS(isPrintf), VectorNumElts(false), |
| 398 | UsesPositionalArg(false), argIndex(0) {} |
| 399 | |
| 400 | void setLengthModifier(LengthModifier lm) { |
| 401 | LM = lm; |
| 402 | } |
| 403 | |
| 404 | void setUsesPositionalArg() { UsesPositionalArg = true; } |
| 405 | |
| 406 | void setArgIndex(unsigned i) { |
| 407 | argIndex = i; |
| 408 | } |
| 409 | |
| 410 | unsigned getArgIndex() const { |
| 411 | return argIndex; |
| 412 | } |
| 413 | |
| 414 | unsigned getPositionalArgIndex() const { |
| 415 | return argIndex + 1; |
| 416 | } |
| 417 | |
| 418 | const LengthModifier &getLengthModifier() const { |
| 419 | return LM; |
| 420 | } |
| 421 | |
| 422 | const OptionalAmount &getFieldWidth() const { |
| 423 | return FieldWidth; |
| 424 | } |
| 425 | |
| 426 | void setVectorNumElts(const OptionalAmount &Amt) { |
| 427 | VectorNumElts = Amt; |
| 428 | } |
| 429 | |
| 430 | const OptionalAmount &getVectorNumElts() const { |
| 431 | return VectorNumElts; |
| 432 | } |
| 433 | |
| 434 | void setFieldWidth(const OptionalAmount &Amt) { |
| 435 | FieldWidth = Amt; |
| 436 | } |
| 437 | |
| 438 | bool usesPositionalArg() const { return UsesPositionalArg; } |
| 439 | |
| 440 | bool hasValidLengthModifier(const TargetInfo &Target, |
| 441 | const LangOptions &LO) const; |
| 442 | |
| 443 | bool hasStandardLengthModifier() const; |
| 444 | |
| 445 | Optional<LengthModifier> getCorrectedLengthModifier() const; |
| 446 | |
| 447 | bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const; |
| 448 | |
| 449 | bool hasStandardLengthConversionCombination() const; |
| 450 | |
| 451 | |
| 452 | |
| 453 | static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM); |
| 454 | }; |
| 455 | |
| 456 | } |
| 457 | |
| 458 | |
| 459 | |
| 460 | |
| 461 | namespace analyze_printf { |
| 462 | |
| 463 | class PrintfConversionSpecifier : |
| 464 | public analyze_format_string::ConversionSpecifier { |
| 465 | public: |
| 466 | PrintfConversionSpecifier() |
| 467 | : ConversionSpecifier(true, nullptr, InvalidSpecifier) {} |
| 468 | |
| 469 | PrintfConversionSpecifier(const char *pos, Kind k) |
| 470 | : ConversionSpecifier(true, pos, k) {} |
| 471 | |
| 472 | bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; } |
| 473 | bool isDoubleArg() const { return kind >= DoubleArgBeg && |
| 474 | kind <= DoubleArgEnd; } |
| 475 | |
| 476 | static bool classof(const analyze_format_string::ConversionSpecifier *CS) { |
| 477 | return CS->isPrintfKind(); |
| 478 | } |
| 479 | }; |
| 480 | |
| 481 | using analyze_format_string::ArgType; |
| 482 | using analyze_format_string::LengthModifier; |
| 483 | using analyze_format_string::OptionalAmount; |
| 484 | using analyze_format_string::OptionalFlag; |
| 485 | |
| 486 | class PrintfSpecifier : public analyze_format_string::FormatSpecifier { |
| 487 | OptionalFlag HasThousandsGrouping; |
| 488 | OptionalFlag IsLeftJustified; |
| 489 | OptionalFlag HasPlusPrefix; |
| 490 | OptionalFlag HasSpacePrefix; |
| 491 | OptionalFlag HasAlternativeForm; |
| 492 | OptionalFlag HasLeadingZeroes; |
| 493 | OptionalFlag HasObjCTechnicalTerm; |
| 494 | OptionalFlag IsPrivate; |
| 495 | OptionalFlag IsPublic; |
| 496 | OptionalFlag IsSensitive; |
| 497 | OptionalAmount Precision; |
| 498 | StringRef MaskType; |
| 499 | |
| 500 | ArgType getScalarArgType(ASTContext &Ctx, bool IsObjCLiteral) const; |
| 501 | |
| 502 | public: |
| 503 | PrintfSpecifier() |
| 504 | : FormatSpecifier( true), HasThousandsGrouping("'"), |
| 505 | IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "), |
| 506 | HasAlternativeForm("#"), HasLeadingZeroes("0"), |
| 507 | HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public"), |
| 508 | IsSensitive("sensitive") {} |
| 509 | |
| 510 | static PrintfSpecifier Parse(const char *beg, const char *end); |
| 511 | |
| 512 | |
| 513 | void setConversionSpecifier(const PrintfConversionSpecifier &cs) { |
| 514 | CS = cs; |
| 515 | } |
| 516 | void setHasThousandsGrouping(const char *position) { |
| 517 | HasThousandsGrouping.setPosition(position); |
| 518 | } |
| 519 | void setIsLeftJustified(const char *position) { |
| 520 | IsLeftJustified.setPosition(position); |
| 521 | } |
| 522 | void setHasPlusPrefix(const char *position) { |
| 523 | HasPlusPrefix.setPosition(position); |
| 524 | } |
| 525 | void setHasSpacePrefix(const char *position) { |
| 526 | HasSpacePrefix.setPosition(position); |
| 527 | } |
| 528 | void setHasAlternativeForm(const char *position) { |
| 529 | HasAlternativeForm.setPosition(position); |
| 530 | } |
| 531 | void setHasLeadingZeros(const char *position) { |
| 532 | HasLeadingZeroes.setPosition(position); |
| 533 | } |
| 534 | void setHasObjCTechnicalTerm(const char *position) { |
| 535 | HasObjCTechnicalTerm.setPosition(position); |
| 536 | } |
| 537 | void setIsPrivate(const char *position) { IsPrivate.setPosition(position); } |
| 538 | void setIsPublic(const char *position) { IsPublic.setPosition(position); } |
| 539 | void setIsSensitive(const char *position) { |
| 540 | IsSensitive.setPosition(position); |
| 541 | } |
| 542 | void setUsesPositionalArg() { UsesPositionalArg = true; } |
| 543 | |
| 544 | |
| 545 | |
| 546 | const PrintfConversionSpecifier &getConversionSpecifier() const { |
| 547 | return cast<PrintfConversionSpecifier>(CS); |
| 548 | } |
| 549 | |
| 550 | void setPrecision(const OptionalAmount &Amt) { |
| 551 | Precision = Amt; |
| 552 | Precision.setUsesDotPrefix(); |
| 553 | } |
| 554 | |
| 555 | const OptionalAmount &getPrecision() const { |
| 556 | return Precision; |
| 557 | } |
| 558 | |
| 559 | bool consumesDataArgument() const { |
| 560 | return getConversionSpecifier().consumesDataArgument(); |
| 561 | } |
| 562 | |
| 563 | |
| 564 | |
| 565 | |
| 566 | |
| 567 | |
| 568 | ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const; |
| 569 | |
| 570 | const OptionalFlag &hasThousandsGrouping() const { |
| 571 | return HasThousandsGrouping; |
| 572 | } |
| 573 | const OptionalFlag &isLeftJustified() const { return IsLeftJustified; } |
| 574 | const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; } |
| 575 | const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; } |
| 576 | const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; } |
| 577 | const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; } |
| 578 | const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; } |
| 579 | const OptionalFlag &isPrivate() const { return IsPrivate; } |
| 580 | const OptionalFlag &isPublic() const { return IsPublic; } |
| 581 | const OptionalFlag &isSensitive() const { return IsSensitive; } |
| 582 | bool usesPositionalArg() const { return UsesPositionalArg; } |
| 583 | |
| 584 | StringRef getMaskType() const { return MaskType; } |
| 585 | void setMaskType(StringRef S) { MaskType = S; } |
| 586 | |
| 587 | |
| 588 | |
| 589 | |
| 590 | bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx, |
| 591 | bool IsObjCLiteral); |
| 592 | |
| 593 | void toString(raw_ostream &os) const; |
| 594 | |
| 595 | |
| 596 | bool hasValidPlusPrefix() const; |
| 597 | bool hasValidAlternativeForm() const; |
| 598 | bool hasValidLeadingZeros() const; |
| 599 | bool hasValidSpacePrefix() const; |
| 600 | bool hasValidLeftJustified() const; |
| 601 | bool hasValidThousandsGroupingPrefix() const; |
| 602 | |
| 603 | bool hasValidPrecision() const; |
| 604 | bool hasValidFieldWidth() const; |
| 605 | }; |
| 606 | } |
| 607 | |
| 608 | |
| 609 | |
| 610 | |
| 611 | namespace analyze_scanf { |
| 612 | |
| 613 | class ScanfConversionSpecifier : |
| 614 | public analyze_format_string::ConversionSpecifier { |
| 615 | public: |
| 616 | ScanfConversionSpecifier() |
| 617 | : ConversionSpecifier(false, nullptr, InvalidSpecifier) {} |
| 618 | |
| 619 | ScanfConversionSpecifier(const char *pos, Kind k) |
| 620 | : ConversionSpecifier(false, pos, k) {} |
| 621 | |
| 622 | static bool classof(const analyze_format_string::ConversionSpecifier *CS) { |
| 623 | return !CS->isPrintfKind(); |
| 624 | } |
| 625 | }; |
| 626 | |
| 627 | using analyze_format_string::ArgType; |
| 628 | using analyze_format_string::LengthModifier; |
| 629 | using analyze_format_string::OptionalAmount; |
| 630 | using analyze_format_string::OptionalFlag; |
| 631 | |
| 632 | class ScanfSpecifier : public analyze_format_string::FormatSpecifier { |
| 633 | OptionalFlag SuppressAssignment; |
| 634 | public: |
| 635 | ScanfSpecifier() : |
| 636 | FormatSpecifier( false), |
| 637 | SuppressAssignment("*") {} |
| 638 | |
| 639 | void setSuppressAssignment(const char *position) { |
| 640 | SuppressAssignment.setPosition(position); |
| 641 | } |
| 642 | |
| 643 | const OptionalFlag &getSuppressAssignment() const { |
| 644 | return SuppressAssignment; |
| 645 | } |
| 646 | |
| 647 | void setConversionSpecifier(const ScanfConversionSpecifier &cs) { |
| 648 | CS = cs; |
| 649 | } |
| 650 | |
| 651 | const ScanfConversionSpecifier &getConversionSpecifier() const { |
| 652 | return cast<ScanfConversionSpecifier>(CS); |
| 653 | } |
| 654 | |
| 655 | bool consumesDataArgument() const { |
| 656 | return CS.consumesDataArgument() && !SuppressAssignment; |
| 657 | } |
| 658 | |
| 659 | ArgType getArgType(ASTContext &Ctx) const; |
| 660 | |
| 661 | bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt, |
| 662 | ASTContext &Ctx); |
| 663 | |
| 664 | void toString(raw_ostream &os) const; |
| 665 | |
| 666 | static ScanfSpecifier Parse(const char *beg, const char *end); |
| 667 | }; |
| 668 | |
| 669 | } |
| 670 | |
| 671 | |
| 672 | |
| 673 | |
| 674 | namespace analyze_format_string { |
| 675 | |
| 676 | enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 }; |
| 677 | |
| 678 | class FormatStringHandler { |
| 679 | public: |
| 680 | FormatStringHandler() {} |
| 681 | virtual ~FormatStringHandler(); |
| 682 | |
| 683 | virtual void HandleNullChar(const char *nullCharacter) {} |
| 684 | |
| 685 | virtual void HandlePosition(const char *startPos, unsigned posLen) {} |
| 686 | |
| 687 | virtual void HandleInvalidPosition(const char *startPos, unsigned posLen, |
| 688 | PositionContext p) {} |
| 689 | |
| 690 | virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {} |
| 691 | |
| 692 | virtual void HandleIncompleteSpecifier(const char *startSpecifier, |
| 693 | unsigned specifierLen) {} |
| 694 | |
| 695 | virtual void HandleEmptyObjCModifierFlag(const char *startFlags, |
| 696 | unsigned flagsLen) {} |
| 697 | |
| 698 | virtual void HandleInvalidObjCModifierFlag(const char *startFlag, |
| 699 | unsigned flagLen) {} |
| 700 | |
| 701 | virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart, |
| 702 | const char *flagsEnd, |
| 703 | const char *conversionPosition) {} |
| 704 | |
| 705 | |
| 706 | virtual bool HandleInvalidPrintfConversionSpecifier( |
| 707 | const analyze_printf::PrintfSpecifier &FS, |
| 708 | const char *startSpecifier, |
| 709 | unsigned specifierLen) { |
| 710 | return true; |
| 711 | } |
| 712 | |
| 713 | virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, |
| 714 | const char *startSpecifier, |
| 715 | unsigned specifierLen) { |
| 716 | return true; |
| 717 | } |
| 718 | |
| 719 | |
| 720 | virtual void handleInvalidMaskType(StringRef MaskType) {} |
| 721 | |
| 722 | |
| 723 | |
| 724 | virtual bool HandleInvalidScanfConversionSpecifier( |
| 725 | const analyze_scanf::ScanfSpecifier &FS, |
| 726 | const char *startSpecifier, |
| 727 | unsigned specifierLen) { |
| 728 | return true; |
| 729 | } |
| 730 | |
| 731 | virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, |
| 732 | const char *startSpecifier, |
| 733 | unsigned specifierLen) { |
| 734 | return true; |
| 735 | } |
| 736 | |
| 737 | virtual void HandleIncompleteScanList(const char *start, const char *end) {} |
| 738 | }; |
| 739 | |
| 740 | bool ParsePrintfString(FormatStringHandler &H, |
| 741 | const char *beg, const char *end, const LangOptions &LO, |
| 742 | const TargetInfo &Target, bool isFreeBSDKPrintf); |
| 743 | |
| 744 | bool ParseFormatStringHasSArg(const char *beg, const char *end, |
| 745 | const LangOptions &LO, const TargetInfo &Target); |
| 746 | |
| 747 | bool ParseScanfString(FormatStringHandler &H, |
| 748 | const char *beg, const char *end, const LangOptions &LO, |
| 749 | const TargetInfo &Target); |
| 750 | |
| 751 | } |
| 752 | } |
| 753 | #endif |
| 754 | |