1//= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines APIs for analyzing the format strings of printf, fscanf,
10// and friends.
11//
12// The structure of format strings for fprintf are described in C99 7.19.6.1.
13//
14// The structure of format strings for fscanf are described in C99 7.19.6.2.
15//
16//===----------------------------------------------------------------------===//
17
18#ifndef LLVM_CLANG_AST_FORMATSTRING_H
19#define LLVM_CLANG_AST_FORMATSTRING_H
20
21#include "clang/AST/CanonicalType.h"
22#include <optional>
23
24namespace clang {
25
26class TargetInfo;
27
28//===----------------------------------------------------------------------===//
29/// Common components of both fprintf and fscanf format strings.
30namespace analyze_format_string {
31
32/// Class representing optional flags with location and representation
33/// information.
34class OptionalFlag {
35public:
36 OptionalFlag(const char *Representation)
37 : representation(Representation), flag(false) {}
38 bool isSet() const { return flag; }
39 void set() { flag = true; }
40 void clear() { flag = false; }
41 void setPosition(const char *position) {
42 assert(position);
43 flag = true;
44 this->position = position;
45 }
46 const char *getPosition() const {
47 assert(position);
48 return position;
49 }
50 const char *toString() const { return representation; }
51
52 // Overloaded operators for bool like qualities
53 explicit operator bool() const { return flag; }
54 OptionalFlag& operator=(const bool &rhs) {
55 flag = rhs;
56 return *this; // Return a reference to myself.
57 }
58private:
59 const char *representation;
60 const char *position;
61 bool flag;
62};
63
64/// Represents the length modifier in a format string in scanf/printf.
65class LengthModifier {
66public:
67 enum Kind {
68 None,
69 AsChar, // 'hh'
70 AsShort, // 'h'
71 AsShortLong, // 'hl' (OpenCL float/int vector element)
72 AsLong, // 'l'
73 AsLongLong, // 'll'
74 AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types)
75 AsIntMax, // 'j'
76 AsSizeT, // 'z'
77 AsPtrDiff, // 't'
78 AsInt32, // 'I32' (MSVCRT, like __int32)
79 AsInt3264, // 'I' (MSVCRT, like __int3264 from MIDL)
80 AsInt64, // 'I64' (MSVCRT, like __int64)
81 AsLongDouble, // 'L'
82 AsAllocate, // for '%as', GNU extension to C90 scanf
83 AsMAllocate, // for '%ms', GNU extension to scanf
84 AsWide, // 'w' (MSVCRT, like l but only for c, C, s, S, or Z
85 AsWideChar = AsLong // for '%ls', only makes sense for printf
86 };
87
88 LengthModifier()
89 : Position(nullptr), kind(None) {}
90 LengthModifier(const char *pos, Kind k)
91 : Position(pos), kind(k) {}
92
93 const char *getStart() const {
94 return Position;
95 }
96
97 unsigned getLength() const {
98 switch (kind) {
99 default:
100 return 1;
101 case AsLongLong:
102 case AsChar:
103 return 2;
104 case AsInt32:
105 case AsInt64:
106 return 3;
107 case None:
108 return 0;
109 }
110 }
111
112 Kind getKind() const { return kind; }
113 void setKind(Kind k) { kind = k; }
114
115 const char *toString() const;
116
117private:
118 const char *Position;
119 Kind kind;
120};
121
122class ConversionSpecifier {
123public:
124 enum Kind {
125 InvalidSpecifier = 0,
126 // C99 conversion specifiers.
127 cArg,
128 dArg,
129 DArg, // Apple extension
130 iArg,
131 // C23 conversion specifiers.
132 bArg,
133 BArg,
134
135 IntArgBeg = dArg,
136 IntArgEnd = BArg,
137
138 oArg,
139 OArg, // Apple extension
140 uArg,
141 UArg, // Apple extension
142 xArg,
143 XArg,
144 UIntArgBeg = oArg,
145 UIntArgEnd = XArg,
146
147 fArg,
148 FArg,
149 eArg,
150 EArg,
151 gArg,
152 GArg,
153 aArg,
154 AArg,
155 DoubleArgBeg = fArg,
156 DoubleArgEnd = AArg,
157
158 sArg,
159 pArg,
160 nArg,
161 PercentArg,
162 CArg,
163 SArg,
164
165 // Apple extension: P specifies to os_log that the data being pointed to is
166 // to be copied by os_log. The precision indicates the number of bytes to
167 // copy.
168 PArg,
169
170 // ** Printf-specific **
171
172 ZArg, // MS extension
173
174 // Objective-C specific specifiers.
175 ObjCObjArg, // '@'
176 ObjCBeg = ObjCObjArg,
177 ObjCEnd = ObjCObjArg,
178
179 // FreeBSD kernel specific specifiers.
180 FreeBSDbArg,
181 FreeBSDDArg,
182 FreeBSDrArg,
183 FreeBSDyArg,
184
185 // GlibC specific specifiers.
186 PrintErrno, // 'm'
187
188 PrintfConvBeg = ObjCObjArg,
189 PrintfConvEnd = PrintErrno,
190
191 // ** Scanf-specific **
192 ScanListArg, // '['
193 ScanfConvBeg = ScanListArg,
194 ScanfConvEnd = ScanListArg
195 };
196
197 ConversionSpecifier(bool isPrintf = true)
198 : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
199 kind(InvalidSpecifier) {}
200
201 ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
202 : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
203
204 const char *getStart() const {
205 return Position;
206 }
207
208 StringRef getCharacters() const {
209 return StringRef(getStart(), getLength());
210 }
211
212 bool consumesDataArgument() const {
213 switch (kind) {
214 case PrintErrno:
215 assert(IsPrintf);
216 return false;
217 case PercentArg:
218 return false;
219 case InvalidSpecifier:
220 return false;
221 default:
222 return true;
223 }
224 }
225
226 Kind getKind() const { return kind; }
227 void setKind(Kind k) { kind = k; }
228 unsigned getLength() const {
229 return EndScanList ? EndScanList - Position : 1;
230 }
231 void setEndScanList(const char *pos) { EndScanList = pos; }
232
233 bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
234 kind == FreeBSDrArg || kind == FreeBSDyArg; }
235 bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
236 bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
237 bool isDoubleArg() const {
238 return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
239 }
240
241 const char *toString() const;
242
243 bool isPrintfKind() const { return IsPrintf; }
244
245 std::optional<ConversionSpecifier> getStandardSpecifier() const;
246
247protected:
248 bool IsPrintf;
249 const char *Position;
250 const char *EndScanList;
251 Kind kind;
252};
253
254class ArgType {
255public:
256 enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
257 AnyCharTy, CStrTy, WCStrTy, WIntTy };
258
259 /// How well a given conversion specifier matches its argument.
260 enum MatchKind {
261 /// The conversion specifier and the argument types are incompatible. For
262 /// instance, "%d" and float.
263 NoMatch = 0,
264 /// The conversion specifier and the argument type are compatible. For
265 /// instance, "%d" and int.
266 Match = 1,
267 /// The conversion specifier and the argument type are compatible because of
268 /// default argument promotions. For instance, "%hhd" and int.
269 MatchPromotion,
270 /// The conversion specifier and the argument type are compatible but still
271 /// seems likely to be an error. For instanace, "%hhd" and short.
272 NoMatchPromotionTypeConfusion,
273 /// The conversion specifier and the argument type are disallowed by the C
274 /// standard, but are in practice harmless. For instance, "%p" and int*.
275 NoMatchPedantic,
276 /// The conversion specifier and the argument type are compatible, but still
277 /// seems likely to be an error. For instance, "%hd" and _Bool.
278 NoMatchTypeConfusion,
279 };
280
281private:
282 const Kind K;
283 QualType T;
284 const char *Name = nullptr;
285 bool Ptr = false;
286
287 /// The TypeKind identifies certain well-known types like size_t and
288 /// ptrdiff_t.
289 enum class TypeKind { DontCare, SizeT, PtrdiffT };
290 TypeKind TK = TypeKind::DontCare;
291
292public:
293 ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
294 ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}
295 ArgType(CanQualType T) : K(SpecificTy), T(T) {}
296
297 static ArgType Invalid() { return ArgType(InvalidTy); }
298 bool isValid() const { return K != InvalidTy; }
299
300 bool isSizeT() const { return TK == TypeKind::SizeT; }
301
302 bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }
303
304 /// Create an ArgType which corresponds to the type pointer to A.
305 static ArgType PtrTo(const ArgType& A) {
306 assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
307 ArgType Res = A;
308 Res.Ptr = true;
309 return Res;
310 }
311
312 /// Create an ArgType which corresponds to the size_t/ssize_t type.
313 static ArgType makeSizeT(const ArgType &A) {
314 ArgType Res = A;
315 Res.TK = TypeKind::SizeT;
316 return Res;
317 }
318
319 /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t
320 /// type.
321 static ArgType makePtrdiffT(const ArgType &A) {
322 ArgType Res = A;
323 Res.TK = TypeKind::PtrdiffT;
324 return Res;
325 }
326
327 MatchKind matchesType(ASTContext &C, QualType argTy) const;
328
329 QualType getRepresentativeType(ASTContext &C) const;
330
331 ArgType makeVectorType(ASTContext &C, unsigned NumElts) const;
332
333 std::string getRepresentativeTypeName(ASTContext &C) const;
334};
335
336class OptionalAmount {
337public:
338 enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
339
340 OptionalAmount(HowSpecified howSpecified,
341 unsigned amount,
342 const char *amountStart,
343 unsigned amountLength,
344 bool usesPositionalArg)
345 : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
346 UsesPositionalArg(usesPositionalArg), UsesDotPrefix(false) {}
347
348 OptionalAmount(bool valid = true)
349 : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
350 UsesPositionalArg(false), UsesDotPrefix(false) {}
351
352 explicit OptionalAmount(unsigned Amount)
353 : start(nullptr), length(0), hs(Constant), amt(Amount),
354 UsesPositionalArg(false), UsesDotPrefix(false) {}
355
356 bool isInvalid() const {
357 return hs == Invalid;
358 }
359
360 HowSpecified getHowSpecified() const { return hs; }
361 void setHowSpecified(HowSpecified h) { hs = h; }
362
363 bool hasDataArgument() const { return hs == Arg; }
364
365 unsigned getArgIndex() const {
366 assert(hasDataArgument());
367 return amt;
368 }
369
370 unsigned getConstantAmount() const {
371 assert(hs == Constant);
372 return amt;
373 }
374
375 const char *getStart() const {
376 // We include the . character if it is given.
377 return start - UsesDotPrefix;
378 }
379
380 unsigned getConstantLength() const {
381 assert(hs == Constant);
382 return length + UsesDotPrefix;
383 }
384
385 ArgType getArgType(ASTContext &Ctx) const;
386
387 void toString(raw_ostream &os) const;
388
389 bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
390 unsigned getPositionalArgIndex() const {
391 assert(hasDataArgument());
392 return amt + 1;
393 }
394
395 bool usesDotPrefix() const { return UsesDotPrefix; }
396 void setUsesDotPrefix() { UsesDotPrefix = true; }
397
398private:
399 const char *start;
400 unsigned length;
401 HowSpecified hs;
402 unsigned amt;
403 bool UsesPositionalArg : 1;
404 bool UsesDotPrefix;
405};
406
407
408class FormatSpecifier {
409protected:
410 LengthModifier LM;
411 OptionalAmount FieldWidth;
412 ConversionSpecifier CS;
413 OptionalAmount VectorNumElts;
414
415 /// Positional arguments, an IEEE extension:
416 /// IEEE Std 1003.1, 2004 Edition
417 /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
418 bool UsesPositionalArg;
419 unsigned argIndex;
420public:
421 FormatSpecifier(bool isPrintf)
422 : CS(isPrintf), VectorNumElts(false),
423 UsesPositionalArg(false), argIndex(0) {}
424
425 void setLengthModifier(LengthModifier lm) {
426 LM = lm;
427 }
428
429 void setUsesPositionalArg() { UsesPositionalArg = true; }
430
431 void setArgIndex(unsigned i) {
432 argIndex = i;
433 }
434
435 unsigned getArgIndex() const {
436 return argIndex;
437 }
438
439 unsigned getPositionalArgIndex() const {
440 return argIndex + 1;
441 }
442
443 const LengthModifier &getLengthModifier() const {
444 return LM;
445 }
446
447 const OptionalAmount &getFieldWidth() const {
448 return FieldWidth;
449 }
450
451 void setVectorNumElts(const OptionalAmount &Amt) {
452 VectorNumElts = Amt;
453 }
454
455 const OptionalAmount &getVectorNumElts() const {
456 return VectorNumElts;
457 }
458
459 void setFieldWidth(const OptionalAmount &Amt) {
460 FieldWidth = Amt;
461 }
462
463 bool usesPositionalArg() const { return UsesPositionalArg; }
464
465 bool hasValidLengthModifier(const TargetInfo &Target,
466 const LangOptions &LO) const;
467
468 bool hasStandardLengthModifier() const;
469
470 std::optional<LengthModifier> getCorrectedLengthModifier() const;
471
472 bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
473
474 bool hasStandardLengthConversionCombination() const;
475
476 /// For a TypedefType QT, if it is a named integer type such as size_t,
477 /// assign the appropriate value to LM and return true.
478 static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
479};
480
481} // end analyze_format_string namespace
482
483//===----------------------------------------------------------------------===//
484/// Pieces specific to fprintf format strings.
485
486namespace analyze_printf {
487
488class PrintfConversionSpecifier :
489 public analyze_format_string::ConversionSpecifier {
490public:
491 PrintfConversionSpecifier()
492 : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
493
494 PrintfConversionSpecifier(const char *pos, Kind k)
495 : ConversionSpecifier(true, pos, k) {}
496
497 bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
498 bool isDoubleArg() const { return kind >= DoubleArgBeg &&
499 kind <= DoubleArgEnd; }
500
501 static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
502 return CS->isPrintfKind();
503 }
504};
505
506using analyze_format_string::ArgType;
507using analyze_format_string::LengthModifier;
508using analyze_format_string::OptionalAmount;
509using analyze_format_string::OptionalFlag;
510
511class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
512 OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
513 OptionalFlag IsLeftJustified; // '-'
514 OptionalFlag HasPlusPrefix; // '+'
515 OptionalFlag HasSpacePrefix; // ' '
516 OptionalFlag HasAlternativeForm; // '#'
517 OptionalFlag HasLeadingZeroes; // '0'
518 OptionalFlag HasObjCTechnicalTerm; // '[tt]'
519 OptionalFlag IsPrivate; // '{private}'
520 OptionalFlag IsPublic; // '{public}'
521 OptionalFlag IsSensitive; // '{sensitive}'
522 OptionalAmount Precision;
523 StringRef MaskType;
524
525 ArgType getScalarArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
526
527public:
528 PrintfSpecifier()
529 : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
530 IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
531 HasAlternativeForm("#"), HasLeadingZeroes("0"),
532 HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public"),
533 IsSensitive("sensitive") {}
534
535 static PrintfSpecifier Parse(const char *beg, const char *end);
536
537 // Methods for incrementally constructing the PrintfSpecifier.
538 void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
539 CS = cs;
540 }
541 void setHasThousandsGrouping(const char *position) {
542 HasThousandsGrouping.setPosition(position);
543 }
544 void setIsLeftJustified(const char *position) {
545 IsLeftJustified.setPosition(position);
546 }
547 void setHasPlusPrefix(const char *position) {
548 HasPlusPrefix.setPosition(position);
549 }
550 void setHasSpacePrefix(const char *position) {
551 HasSpacePrefix.setPosition(position);
552 }
553 void setHasAlternativeForm(const char *position) {
554 HasAlternativeForm.setPosition(position);
555 }
556 void setHasLeadingZeros(const char *position) {
557 HasLeadingZeroes.setPosition(position);
558 }
559 void setHasObjCTechnicalTerm(const char *position) {
560 HasObjCTechnicalTerm.setPosition(position);
561 }
562 void setIsPrivate(const char *position) { IsPrivate.setPosition(position); }
563 void setIsPublic(const char *position) { IsPublic.setPosition(position); }
564 void setIsSensitive(const char *position) {
565 IsSensitive.setPosition(position);
566 }
567 void setUsesPositionalArg() { UsesPositionalArg = true; }
568
569 // Methods for querying the format specifier.
570
571 const PrintfConversionSpecifier &getConversionSpecifier() const {
572 return cast<PrintfConversionSpecifier>(Val: CS);
573 }
574
575 void setPrecision(const OptionalAmount &Amt) {
576 Precision = Amt;
577 Precision.setUsesDotPrefix();
578 }
579
580 const OptionalAmount &getPrecision() const {
581 return Precision;
582 }
583
584 bool consumesDataArgument() const {
585 return getConversionSpecifier().consumesDataArgument();
586 }
587
588 /// Returns the builtin type that a data argument
589 /// paired with this format specifier should have. This method
590 /// will return null if the format specifier does not have
591 /// a matching data argument or the matching argument matches
592 /// more than one type.
593 ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
594
595 const OptionalFlag &hasThousandsGrouping() const {
596 return HasThousandsGrouping;
597 }
598 const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
599 const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
600 const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
601 const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
602 const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
603 const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }
604 const OptionalFlag &isPrivate() const { return IsPrivate; }
605 const OptionalFlag &isPublic() const { return IsPublic; }
606 const OptionalFlag &isSensitive() const { return IsSensitive; }
607 bool usesPositionalArg() const { return UsesPositionalArg; }
608
609 StringRef getMaskType() const { return MaskType; }
610 void setMaskType(StringRef S) { MaskType = S; }
611
612 /// Changes the specifier and length according to a QualType, retaining any
613 /// flags or options. Returns true on success, or false when a conversion
614 /// was not successful.
615 bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
616 bool IsObjCLiteral);
617
618 void toString(raw_ostream &os) const;
619
620 // Validation methods - to check if any element results in undefined behavior
621 bool hasValidPlusPrefix() const;
622 bool hasValidAlternativeForm() const;
623 bool hasValidLeadingZeros() const;
624 bool hasValidSpacePrefix() const;
625 bool hasValidLeftJustified() const;
626 bool hasValidThousandsGroupingPrefix() const;
627
628 bool hasValidPrecision() const;
629 bool hasValidFieldWidth() const;
630};
631} // end analyze_printf namespace
632
633//===----------------------------------------------------------------------===//
634/// Pieces specific to fscanf format strings.
635
636namespace analyze_scanf {
637
638class ScanfConversionSpecifier :
639 public analyze_format_string::ConversionSpecifier {
640public:
641 ScanfConversionSpecifier()
642 : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
643
644 ScanfConversionSpecifier(const char *pos, Kind k)
645 : ConversionSpecifier(false, pos, k) {}
646
647 static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
648 return !CS->isPrintfKind();
649 }
650};
651
652using analyze_format_string::ArgType;
653using analyze_format_string::LengthModifier;
654using analyze_format_string::OptionalAmount;
655using analyze_format_string::OptionalFlag;
656
657class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
658 OptionalFlag SuppressAssignment; // '*'
659public:
660 ScanfSpecifier() :
661 FormatSpecifier(/* isPrintf = */ false),
662 SuppressAssignment("*") {}
663
664 void setSuppressAssignment(const char *position) {
665 SuppressAssignment.setPosition(position);
666 }
667
668 const OptionalFlag &getSuppressAssignment() const {
669 return SuppressAssignment;
670 }
671
672 void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
673 CS = cs;
674 }
675
676 const ScanfConversionSpecifier &getConversionSpecifier() const {
677 return cast<ScanfConversionSpecifier>(Val: CS);
678 }
679
680 bool consumesDataArgument() const {
681 return CS.consumesDataArgument() && !SuppressAssignment;
682 }
683
684 ArgType getArgType(ASTContext &Ctx) const;
685
686 bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
687 ASTContext &Ctx);
688
689 void toString(raw_ostream &os) const;
690
691 static ScanfSpecifier Parse(const char *beg, const char *end);
692};
693
694} // end analyze_scanf namespace
695
696//===----------------------------------------------------------------------===//
697// Parsing and processing of format strings (both fprintf and fscanf).
698
699namespace analyze_format_string {
700
701enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
702
703class FormatStringHandler {
704public:
705 FormatStringHandler() {}
706 virtual ~FormatStringHandler();
707
708 virtual void HandleNullChar(const char *nullCharacter) {}
709
710 virtual void HandlePosition(const char *startPos, unsigned posLen) {}
711
712 virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
713 PositionContext p) {}
714
715 virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
716
717 virtual void HandleIncompleteSpecifier(const char *startSpecifier,
718 unsigned specifierLen) {}
719
720 virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
721 unsigned flagsLen) {}
722
723 virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
724 unsigned flagLen) {}
725
726 virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
727 const char *flagsEnd,
728 const char *conversionPosition) {}
729 // Printf-specific handlers.
730
731 virtual bool HandleInvalidPrintfConversionSpecifier(
732 const analyze_printf::PrintfSpecifier &FS,
733 const char *startSpecifier,
734 unsigned specifierLen) {
735 return true;
736 }
737
738 virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
739 const char *startSpecifier,
740 unsigned specifierLen,
741 const TargetInfo &Target) {
742 return true;
743 }
744
745 /// Handle mask types whose sizes are not between one and eight bytes.
746 virtual void handleInvalidMaskType(StringRef MaskType) {}
747
748 // Scanf-specific handlers.
749
750 virtual bool HandleInvalidScanfConversionSpecifier(
751 const analyze_scanf::ScanfSpecifier &FS,
752 const char *startSpecifier,
753 unsigned specifierLen) {
754 return true;
755 }
756
757 virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
758 const char *startSpecifier,
759 unsigned specifierLen) {
760 return true;
761 }
762
763 virtual void HandleIncompleteScanList(const char *start, const char *end) {}
764};
765
766bool ParsePrintfString(FormatStringHandler &H,
767 const char *beg, const char *end, const LangOptions &LO,
768 const TargetInfo &Target, bool isFreeBSDKPrintf);
769
770bool ParseFormatStringHasSArg(const char *beg, const char *end,
771 const LangOptions &LO, const TargetInfo &Target);
772
773bool ParseScanfString(FormatStringHandler &H,
774 const char *beg, const char *end, const LangOptions &LO,
775 const TargetInfo &Target);
776
777/// Return true if the given string has at least one formatting specifier.
778bool parseFormatStringHasFormattingSpecifiers(const char *Begin,
779 const char *End,
780 const LangOptions &LO,
781 const TargetInfo &Target);
782
783} // end analyze_format_string namespace
784} // end clang namespace
785#endif
786

source code of clang/include/clang/AST/FormatString.h