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 // ISO/IEC TR 18037 (fixed-point) specific specifiers.
175 kArg, // %k for signed accum types
176 KArg, // %K for unsigned accum types
177 rArg, // %r for signed fract types
178 RArg, // %R for unsigned fract types
179 FixedPointArgBeg = kArg,
180 FixedPointArgEnd = RArg,
181
182 // Objective-C specific specifiers.
183 ObjCObjArg, // '@'
184 ObjCBeg = ObjCObjArg,
185 ObjCEnd = ObjCObjArg,
186
187 // FreeBSD kernel specific specifiers.
188 FreeBSDbArg,
189 FreeBSDDArg,
190 FreeBSDrArg,
191 FreeBSDyArg,
192
193 // GlibC specific specifiers.
194 PrintErrno, // 'm'
195
196 PrintfConvBeg = ObjCObjArg,
197 PrintfConvEnd = PrintErrno,
198
199 // ** Scanf-specific **
200 ScanListArg, // '['
201 ScanfConvBeg = ScanListArg,
202 ScanfConvEnd = ScanListArg
203 };
204
205 ConversionSpecifier(bool isPrintf = true)
206 : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
207 kind(InvalidSpecifier) {}
208
209 ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
210 : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
211
212 const char *getStart() const {
213 return Position;
214 }
215
216 StringRef getCharacters() const {
217 return StringRef(getStart(), getLength());
218 }
219
220 bool consumesDataArgument() const {
221 switch (kind) {
222 case PrintErrno:
223 assert(IsPrintf);
224 return false;
225 case PercentArg:
226 return false;
227 case InvalidSpecifier:
228 return false;
229 default:
230 return true;
231 }
232 }
233
234 Kind getKind() const { return kind; }
235 void setKind(Kind k) { kind = k; }
236 unsigned getLength() const {
237 return EndScanList ? EndScanList - Position : 1;
238 }
239 void setEndScanList(const char *pos) { EndScanList = pos; }
240
241 bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
242 kind == FreeBSDrArg || kind == FreeBSDyArg; }
243 bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
244 bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
245 bool isDoubleArg() const {
246 return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
247 }
248 bool isFixedPointArg() const {
249 return kind >= FixedPointArgBeg && kind <= FixedPointArgEnd;
250 }
251
252 const char *toString() const;
253
254 bool isPrintfKind() const { return IsPrintf; }
255
256 std::optional<ConversionSpecifier> getStandardSpecifier() const;
257
258protected:
259 bool IsPrintf;
260 const char *Position;
261 const char *EndScanList;
262 Kind kind;
263};
264
265class ArgType {
266public:
267 enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
268 AnyCharTy, CStrTy, WCStrTy, WIntTy };
269
270 /// How well a given conversion specifier matches its argument.
271 enum MatchKind {
272 /// The conversion specifier and the argument types are incompatible. For
273 /// instance, "%d" and float.
274 NoMatch = 0,
275 /// The conversion specifier and the argument type are compatible. For
276 /// instance, "%d" and int.
277 Match = 1,
278 /// The conversion specifier and the argument type are compatible because of
279 /// default argument promotions. For instance, "%hhd" and int.
280 MatchPromotion,
281 /// The conversion specifier and the argument type are compatible but still
282 /// seems likely to be an error. For instanace, "%hhd" and short.
283 NoMatchPromotionTypeConfusion,
284 /// The conversion specifier and the argument type are disallowed by the C
285 /// standard, but are in practice harmless. For instance, "%p" and int*.
286 NoMatchPedantic,
287 /// The conversion specifier and the argument type have different sign.
288 NoMatchSignedness,
289 /// The conversion specifier and the argument type are compatible, but still
290 /// seems likely to be an error. For instance, "%hd" and _Bool.
291 NoMatchTypeConfusion,
292 };
293
294private:
295 const Kind K;
296 QualType T;
297 const char *Name = nullptr;
298 bool Ptr = false;
299
300 /// The TypeKind identifies certain well-known types like size_t and
301 /// ptrdiff_t.
302 enum class TypeKind { DontCare, SizeT, PtrdiffT };
303 TypeKind TK = TypeKind::DontCare;
304
305public:
306 ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
307 ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}
308 ArgType(CanQualType T) : K(SpecificTy), T(T) {}
309
310 static ArgType Invalid() { return ArgType(InvalidTy); }
311 bool isValid() const { return K != InvalidTy; }
312
313 bool isSizeT() const { return TK == TypeKind::SizeT; }
314
315 bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }
316
317 /// Create an ArgType which corresponds to the type pointer to A.
318 static ArgType PtrTo(const ArgType& A) {
319 assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
320 ArgType Res = A;
321 Res.Ptr = true;
322 return Res;
323 }
324
325 /// Create an ArgType which corresponds to the size_t/ssize_t type.
326 static ArgType makeSizeT(const ArgType &A) {
327 ArgType Res = A;
328 Res.TK = TypeKind::SizeT;
329 return Res;
330 }
331
332 /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t
333 /// type.
334 static ArgType makePtrdiffT(const ArgType &A) {
335 ArgType Res = A;
336 Res.TK = TypeKind::PtrdiffT;
337 return Res;
338 }
339
340 MatchKind matchesType(ASTContext &C, QualType argTy) const;
341
342 QualType getRepresentativeType(ASTContext &C) const;
343
344 ArgType makeVectorType(ASTContext &C, unsigned NumElts) const;
345
346 std::string getRepresentativeTypeName(ASTContext &C) const;
347};
348
349class OptionalAmount {
350public:
351 enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
352
353 OptionalAmount(HowSpecified howSpecified,
354 unsigned amount,
355 const char *amountStart,
356 unsigned amountLength,
357 bool usesPositionalArg)
358 : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
359 UsesPositionalArg(usesPositionalArg), UsesDotPrefix(false) {}
360
361 OptionalAmount(bool valid = true)
362 : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
363 UsesPositionalArg(false), UsesDotPrefix(false) {}
364
365 explicit OptionalAmount(unsigned Amount)
366 : start(nullptr), length(0), hs(Constant), amt(Amount),
367 UsesPositionalArg(false), UsesDotPrefix(false) {}
368
369 bool isInvalid() const {
370 return hs == Invalid;
371 }
372
373 HowSpecified getHowSpecified() const { return hs; }
374 void setHowSpecified(HowSpecified h) { hs = h; }
375
376 bool hasDataArgument() const { return hs == Arg; }
377
378 unsigned getArgIndex() const {
379 assert(hasDataArgument());
380 return amt;
381 }
382
383 unsigned getConstantAmount() const {
384 assert(hs == Constant);
385 return amt;
386 }
387
388 const char *getStart() const {
389 // We include the . character if it is given.
390 return start - UsesDotPrefix;
391 }
392
393 unsigned getConstantLength() const {
394 assert(hs == Constant);
395 return length + UsesDotPrefix;
396 }
397
398 ArgType getArgType(ASTContext &Ctx) const;
399
400 void toString(raw_ostream &os) const;
401
402 bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
403 unsigned getPositionalArgIndex() const {
404 assert(hasDataArgument());
405 return amt + 1;
406 }
407
408 bool usesDotPrefix() const { return UsesDotPrefix; }
409 void setUsesDotPrefix() { UsesDotPrefix = true; }
410
411private:
412 const char *start;
413 unsigned length;
414 HowSpecified hs;
415 unsigned amt;
416 bool UsesPositionalArg : 1;
417 bool UsesDotPrefix;
418};
419
420
421class FormatSpecifier {
422protected:
423 LengthModifier LM;
424 OptionalAmount FieldWidth;
425 ConversionSpecifier CS;
426 OptionalAmount VectorNumElts;
427
428 /// Positional arguments, an IEEE extension:
429 /// IEEE Std 1003.1, 2004 Edition
430 /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
431 bool UsesPositionalArg;
432 unsigned argIndex;
433public:
434 FormatSpecifier(bool isPrintf)
435 : CS(isPrintf), VectorNumElts(false),
436 UsesPositionalArg(false), argIndex(0) {}
437
438 void setLengthModifier(LengthModifier lm) {
439 LM = lm;
440 }
441
442 void setUsesPositionalArg() { UsesPositionalArg = true; }
443
444 void setArgIndex(unsigned i) {
445 argIndex = i;
446 }
447
448 unsigned getArgIndex() const {
449 return argIndex;
450 }
451
452 unsigned getPositionalArgIndex() const {
453 return argIndex + 1;
454 }
455
456 const LengthModifier &getLengthModifier() const {
457 return LM;
458 }
459
460 const OptionalAmount &getFieldWidth() const {
461 return FieldWidth;
462 }
463
464 void setVectorNumElts(const OptionalAmount &Amt) {
465 VectorNumElts = Amt;
466 }
467
468 const OptionalAmount &getVectorNumElts() const {
469 return VectorNumElts;
470 }
471
472 void setFieldWidth(const OptionalAmount &Amt) {
473 FieldWidth = Amt;
474 }
475
476 bool usesPositionalArg() const { return UsesPositionalArg; }
477
478 bool hasValidLengthModifier(const TargetInfo &Target,
479 const LangOptions &LO) const;
480
481 bool hasStandardLengthModifier() const;
482
483 std::optional<LengthModifier> getCorrectedLengthModifier() const;
484
485 bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
486
487 bool hasStandardLengthConversionCombination() const;
488
489 /// For a TypedefType QT, if it is a named integer type such as size_t,
490 /// assign the appropriate value to LM and return true.
491 static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
492};
493
494} // end analyze_format_string namespace
495
496//===----------------------------------------------------------------------===//
497/// Pieces specific to fprintf format strings.
498
499namespace analyze_printf {
500
501class PrintfConversionSpecifier :
502 public analyze_format_string::ConversionSpecifier {
503public:
504 PrintfConversionSpecifier()
505 : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
506
507 PrintfConversionSpecifier(const char *pos, Kind k)
508 : ConversionSpecifier(true, pos, k) {}
509
510 bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
511 bool isDoubleArg() const { return kind >= DoubleArgBeg &&
512 kind <= DoubleArgEnd; }
513
514 static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
515 return CS->isPrintfKind();
516 }
517};
518
519using analyze_format_string::ArgType;
520using analyze_format_string::LengthModifier;
521using analyze_format_string::OptionalAmount;
522using analyze_format_string::OptionalFlag;
523
524class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
525 OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
526 OptionalFlag IsLeftJustified; // '-'
527 OptionalFlag HasPlusPrefix; // '+'
528 OptionalFlag HasSpacePrefix; // ' '
529 OptionalFlag HasAlternativeForm; // '#'
530 OptionalFlag HasLeadingZeroes; // '0'
531 OptionalFlag HasObjCTechnicalTerm; // '[tt]'
532 OptionalFlag IsPrivate; // '{private}'
533 OptionalFlag IsPublic; // '{public}'
534 OptionalFlag IsSensitive; // '{sensitive}'
535 OptionalAmount Precision;
536 StringRef MaskType;
537
538 ArgType getScalarArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
539
540public:
541 PrintfSpecifier()
542 : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
543 IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
544 HasAlternativeForm("#"), HasLeadingZeroes("0"),
545 HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public"),
546 IsSensitive("sensitive") {}
547
548 static PrintfSpecifier Parse(const char *beg, const char *end);
549
550 // Methods for incrementally constructing the PrintfSpecifier.
551 void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
552 CS = cs;
553 }
554 void setHasThousandsGrouping(const char *position) {
555 HasThousandsGrouping.setPosition(position);
556 }
557 void setIsLeftJustified(const char *position) {
558 IsLeftJustified.setPosition(position);
559 }
560 void setHasPlusPrefix(const char *position) {
561 HasPlusPrefix.setPosition(position);
562 }
563 void setHasSpacePrefix(const char *position) {
564 HasSpacePrefix.setPosition(position);
565 }
566 void setHasAlternativeForm(const char *position) {
567 HasAlternativeForm.setPosition(position);
568 }
569 void setHasLeadingZeros(const char *position) {
570 HasLeadingZeroes.setPosition(position);
571 }
572 void setHasObjCTechnicalTerm(const char *position) {
573 HasObjCTechnicalTerm.setPosition(position);
574 }
575 void setIsPrivate(const char *position) { IsPrivate.setPosition(position); }
576 void setIsPublic(const char *position) { IsPublic.setPosition(position); }
577 void setIsSensitive(const char *position) {
578 IsSensitive.setPosition(position);
579 }
580 void setUsesPositionalArg() { UsesPositionalArg = true; }
581
582 // Methods for querying the format specifier.
583
584 const PrintfConversionSpecifier &getConversionSpecifier() const {
585 return cast<PrintfConversionSpecifier>(Val: CS);
586 }
587
588 void setPrecision(const OptionalAmount &Amt) {
589 Precision = Amt;
590 Precision.setUsesDotPrefix();
591 }
592
593 const OptionalAmount &getPrecision() const {
594 return Precision;
595 }
596
597 bool consumesDataArgument() const {
598 return getConversionSpecifier().consumesDataArgument();
599 }
600
601 /// Returns the builtin type that a data argument
602 /// paired with this format specifier should have. This method
603 /// will return null if the format specifier does not have
604 /// a matching data argument or the matching argument matches
605 /// more than one type.
606 ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
607
608 const OptionalFlag &hasThousandsGrouping() const {
609 return HasThousandsGrouping;
610 }
611 const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
612 const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
613 const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
614 const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
615 const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
616 const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }
617 const OptionalFlag &isPrivate() const { return IsPrivate; }
618 const OptionalFlag &isPublic() const { return IsPublic; }
619 const OptionalFlag &isSensitive() const { return IsSensitive; }
620 bool usesPositionalArg() const { return UsesPositionalArg; }
621
622 StringRef getMaskType() const { return MaskType; }
623 void setMaskType(StringRef S) { MaskType = S; }
624
625 /// Changes the specifier and length according to a QualType, retaining any
626 /// flags or options. Returns true on success, or false when a conversion
627 /// was not successful.
628 bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
629 bool IsObjCLiteral);
630
631 void toString(raw_ostream &os) const;
632
633 // Validation methods - to check if any element results in undefined behavior
634 bool hasValidPlusPrefix() const;
635 bool hasValidAlternativeForm() const;
636 bool hasValidLeadingZeros() const;
637 bool hasValidSpacePrefix() const;
638 bool hasValidLeftJustified() const;
639 bool hasValidThousandsGroupingPrefix() const;
640
641 bool hasValidPrecision() const;
642 bool hasValidFieldWidth() const;
643};
644} // end analyze_printf namespace
645
646//===----------------------------------------------------------------------===//
647/// Pieces specific to fscanf format strings.
648
649namespace analyze_scanf {
650
651class ScanfConversionSpecifier :
652 public analyze_format_string::ConversionSpecifier {
653public:
654 ScanfConversionSpecifier()
655 : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
656
657 ScanfConversionSpecifier(const char *pos, Kind k)
658 : ConversionSpecifier(false, pos, k) {}
659
660 static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
661 return !CS->isPrintfKind();
662 }
663};
664
665using analyze_format_string::ArgType;
666using analyze_format_string::LengthModifier;
667using analyze_format_string::OptionalAmount;
668using analyze_format_string::OptionalFlag;
669
670class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
671 OptionalFlag SuppressAssignment; // '*'
672public:
673 ScanfSpecifier() :
674 FormatSpecifier(/* isPrintf = */ false),
675 SuppressAssignment("*") {}
676
677 void setSuppressAssignment(const char *position) {
678 SuppressAssignment.setPosition(position);
679 }
680
681 const OptionalFlag &getSuppressAssignment() const {
682 return SuppressAssignment;
683 }
684
685 void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
686 CS = cs;
687 }
688
689 const ScanfConversionSpecifier &getConversionSpecifier() const {
690 return cast<ScanfConversionSpecifier>(Val: CS);
691 }
692
693 bool consumesDataArgument() const {
694 return CS.consumesDataArgument() && !SuppressAssignment;
695 }
696
697 ArgType getArgType(ASTContext &Ctx) const;
698
699 bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
700 ASTContext &Ctx);
701
702 void toString(raw_ostream &os) const;
703
704 static ScanfSpecifier Parse(const char *beg, const char *end);
705};
706
707} // end analyze_scanf namespace
708
709//===----------------------------------------------------------------------===//
710// Parsing and processing of format strings (both fprintf and fscanf).
711
712namespace analyze_format_string {
713
714enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
715
716class FormatStringHandler {
717public:
718 FormatStringHandler() {}
719 virtual ~FormatStringHandler();
720
721 virtual void HandleNullChar(const char *nullCharacter) {}
722
723 virtual void HandlePosition(const char *startPos, unsigned posLen) {}
724
725 virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
726 PositionContext p) {}
727
728 virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
729
730 virtual void HandleIncompleteSpecifier(const char *startSpecifier,
731 unsigned specifierLen) {}
732
733 virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
734 unsigned flagsLen) {}
735
736 virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
737 unsigned flagLen) {}
738
739 virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
740 const char *flagsEnd,
741 const char *conversionPosition) {}
742 // Printf-specific handlers.
743
744 virtual bool HandleInvalidPrintfConversionSpecifier(
745 const analyze_printf::PrintfSpecifier &FS,
746 const char *startSpecifier,
747 unsigned specifierLen) {
748 return true;
749 }
750
751 virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
752 const char *startSpecifier,
753 unsigned specifierLen,
754 const TargetInfo &Target) {
755 return true;
756 }
757
758 /// Handle mask types whose sizes are not between one and eight bytes.
759 virtual void handleInvalidMaskType(StringRef MaskType) {}
760
761 // Scanf-specific handlers.
762
763 virtual bool HandleInvalidScanfConversionSpecifier(
764 const analyze_scanf::ScanfSpecifier &FS,
765 const char *startSpecifier,
766 unsigned specifierLen) {
767 return true;
768 }
769
770 virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
771 const char *startSpecifier,
772 unsigned specifierLen) {
773 return true;
774 }
775
776 virtual void HandleIncompleteScanList(const char *start, const char *end) {}
777};
778
779bool ParsePrintfString(FormatStringHandler &H,
780 const char *beg, const char *end, const LangOptions &LO,
781 const TargetInfo &Target, bool isFreeBSDKPrintf);
782
783bool ParseFormatStringHasSArg(const char *beg, const char *end,
784 const LangOptions &LO, const TargetInfo &Target);
785
786bool ParseScanfString(FormatStringHandler &H,
787 const char *beg, const char *end, const LangOptions &LO,
788 const TargetInfo &Target);
789
790/// Return true if the given string has at least one formatting specifier.
791bool parseFormatStringHasFormattingSpecifiers(const char *Begin,
792 const char *End,
793 const LangOptions &LO,
794 const TargetInfo &Target);
795
796} // end analyze_format_string namespace
797} // end clang namespace
798#endif
799

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