clang 23.0.0git
PrintfFormatString.cpp
Go to the documentation of this file.
1//== PrintfFormatString.cpp - Analysis of printf 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// Handling of format string in printf and friends. The structure of format
10// strings for fprintf() are described in C99 7.19.6.1.
11//
12//===----------------------------------------------------------------------===//
13
14#include "FormatStringParsing.h"
16#include "clang/AST/OSLog.h"
18#include "llvm/Support/Regex.h"
19
26
27using namespace clang;
28
31
32//===----------------------------------------------------------------------===//
33// Methods for parsing format strings.
34//===----------------------------------------------------------------------===//
35
37
39 const char *Start, const char *&Beg, const char *E,
40 unsigned *argIndex) {
41 if (argIndex) {
42 FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
43 } else {
44 const OptionalAmount Amt = ParsePositionAmount(
45 H, Start, Beg, E, analyze_format_string::PrecisionPos);
46 if (Amt.isInvalid())
47 return true;
48 FS.setPrecision(Amt);
49 }
50 return false;
51}
52
54 const char *FlagBeg, const char *E, bool Warn) {
55 StringRef Flag(FlagBeg, E - FlagBeg);
56 // Currently there is only one flag.
57 if (Flag == "tt") {
58 FS.setHasObjCTechnicalTerm(FlagBeg);
59 return false;
60 }
61 // Handle either the case of no flag or an invalid flag.
62 if (Warn) {
63 if (Flag == "")
64 H.HandleEmptyObjCModifierFlag(FlagBeg, E - FlagBeg);
65 else
66 H.HandleInvalidObjCModifierFlag(FlagBeg, E - FlagBeg);
67 }
68 return true;
69}
70
72ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
73 unsigned &argIndex, const LangOptions &LO,
74 const TargetInfo &Target, bool Warn,
75 bool isFreeBSDKPrintf) {
76
77 using namespace clang::analyze_format_string;
78 using namespace clang::analyze_printf;
79
80 const char *I = Beg;
81 const char *Start = nullptr;
82 UpdateOnReturn<const char *> UpdateBeg(Beg, I);
83
84 // Look for a '%' character that indicates the start of a format specifier.
85 for (; I != E; ++I) {
86 char c = *I;
87 if (c == '\0') {
88 // Detect spurious null characters, which are likely errors.
89 H.HandleNullChar(I);
90 return true;
91 }
92 if (c == '%') {
93 Start = I++; // Record the start of the format specifier.
94 break;
95 }
96 }
97
98 // No format specifier found?
99 if (!Start)
100 return false;
101
102 if (I == E) {
103 // No more characters left?
104 if (Warn)
105 H.HandleIncompleteSpecifier(Start, E - Start);
106 return true;
107 }
108
110 if (ParseArgPosition(H, FS, Start, I, E))
111 return true;
112
113 if (I == E) {
114 // No more characters left?
115 if (Warn)
116 H.HandleIncompleteSpecifier(Start, E - Start);
117 return true;
118 }
119
120 if (*I == '{') {
121 ++I;
122 unsigned char PrivacyFlags = 0;
123 StringRef MatchedStr;
124
125 do {
126 StringRef Str(I, E - I);
127 std::string Match = "^[[:space:]]*"
128 "(private|public|sensitive|mask\\.[^[:space:],}]*)"
129 "[[:space:]]*(,|})";
130 llvm::Regex R(Match);
132
133 if (R.match(Str, &Matches)) {
134 MatchedStr = Matches[1];
135 I += Matches[0].size();
136
137 // Set the privacy flag if the privacy annotation in the
138 // comma-delimited segment is at least as strict as the privacy
139 // annotations in previous comma-delimited segments.
140 if (MatchedStr.starts_with("mask")) {
141 StringRef MaskType = MatchedStr.substr(sizeof("mask.") - 1);
142 unsigned Size = MaskType.size();
143 if (Warn && (Size == 0 || Size > 8))
144 H.handleInvalidMaskType(MaskType);
145 FS.setMaskType(MaskType);
146 } else if (MatchedStr == "sensitive")
148 else if (PrivacyFlags !=
150 MatchedStr == "private")
152 else if (PrivacyFlags == 0 && MatchedStr == "public")
154 } else {
155 size_t CommaOrBracePos =
156 Str.find_if([](char c) { return c == ',' || c == '}'; });
157
158 if (CommaOrBracePos == StringRef::npos) {
159 // Neither a comma nor the closing brace was found.
160 if (Warn)
161 H.HandleIncompleteSpecifier(Start, E - Start);
162 return true;
163 }
164
165 I += CommaOrBracePos + 1;
166 }
167 // Continue until the closing brace is found.
168 } while (*(I - 1) == ',');
169
170 // Set the privacy flag.
171 switch (PrivacyFlags) {
172 case 0:
173 break;
175 FS.setIsPrivate(MatchedStr.data());
176 break;
178 FS.setIsPublic(MatchedStr.data());
179 break;
181 FS.setIsSensitive(MatchedStr.data());
182 break;
183 default:
184 llvm_unreachable("Unexpected privacy flag value");
185 }
186 }
187
188 // Look for flags (if any).
189 bool hasMore = true;
190 for (; I != E; ++I) {
191 switch (*I) {
192 default:
193 hasMore = false;
194 break;
195 case '\'':
196 // FIXME: POSIX specific. Always accept?
198 break;
199 case '-':
200 FS.setIsLeftJustified(I);
201 break;
202 case '+':
203 FS.setHasPlusPrefix(I);
204 break;
205 case ' ':
206 FS.setHasSpacePrefix(I);
207 break;
208 case '#':
210 break;
211 case '0':
212 FS.setHasLeadingZeros(I);
213 break;
214 }
215 if (!hasMore)
216 break;
217 }
218
219 if (I == E) {
220 // No more characters left?
221 if (Warn)
222 H.HandleIncompleteSpecifier(Start, E - Start);
223 return true;
224 }
225
226 // Look for the field width (if any).
227 if (ParseFieldWidth(H, FS, Start, I, E,
228 FS.usesPositionalArg() ? nullptr : &argIndex))
229 return true;
230
231 if (I == E) {
232 // No more characters left?
233 if (Warn)
234 H.HandleIncompleteSpecifier(Start, E - Start);
235 return true;
236 }
237
238 // Look for the precision (if any).
239 if (*I == '.') {
240 ++I;
241 if (I == E) {
242 if (Warn)
243 H.HandleIncompleteSpecifier(Start, E - Start);
244 return true;
245 }
246
247 if (ParsePrecision(H, FS, Start, I, E,
248 FS.usesPositionalArg() ? nullptr : &argIndex))
249 return true;
250
251 if (I == E) {
252 // No more characters left?
253 if (Warn)
254 H.HandleIncompleteSpecifier(Start, E - Start);
255 return true;
256 }
257 }
258
259 if (ParseVectorModifier(H, FS, I, E, LO))
260 return true;
261
262 // Look for the length modifier.
263 if (ParseLengthModifier(FS, I, E, LO) && I == E) {
264 // No more characters left?
265 if (Warn)
266 H.HandleIncompleteSpecifier(Start, E - Start);
267 return true;
268 }
269
270 // Look for the Objective-C modifier flags, if any.
271 // We parse these here, even if they don't apply to
272 // the conversion specifier, and then emit an error
273 // later if the conversion specifier isn't '@'. This
274 // enables better recovery, and we don't know if
275 // these flags are applicable until later.
276 const char *ObjCModifierFlagsStart = nullptr, *ObjCModifierFlagsEnd = nullptr;
277 if (*I == '[') {
278 ObjCModifierFlagsStart = I;
279 ++I;
280 auto flagStart = I;
281 for (;; ++I) {
282 ObjCModifierFlagsEnd = I;
283 if (I == E) {
284 if (Warn)
285 H.HandleIncompleteSpecifier(Start, E - Start);
286 return true;
287 }
288 // Did we find the closing ']'?
289 if (*I == ']') {
290 if (ParseObjCFlags(H, FS, flagStart, I, Warn))
291 return true;
292 ++I;
293 break;
294 }
295 // There are no separators defined yet for multiple
296 // Objective-C modifier flags. When those are
297 // defined, this is the place to check.
298 }
299 }
300
301 if (*I == '\0') {
302 // Detect spurious null characters, which are likely errors.
303 H.HandleNullChar(I);
304 return true;
305 }
306
307 // Finally, look for the conversion specifier.
308 const char *conversionPosition = I++;
310 switch (*conversionPosition) {
311 default:
312 break;
313 // C99: 7.19.6.1 (section 8).
314 case '%':
316 break;
317 case 'A':
319 break;
320 case 'E':
322 break;
323 case 'F':
325 break;
326 case 'G':
328 break;
329 case 'X':
331 break;
332 case 'a':
334 break;
335 case 'c':
337 break;
338 case 'd':
340 break;
341 case 'e':
343 break;
344 case 'f':
346 break;
347 case 'g':
349 break;
350 case 'i':
352 break;
353 case 'n':
354 // Not handled, but reserved in OpenCL.
355 if (!LO.OpenCL)
357 break;
358 case 'o':
360 break;
361 case 'p':
363 break;
364 case 's':
366 break;
367 case 'u':
369 break;
370 case 'x':
372 break;
373 // C23.
374 case 'b':
375 if (isFreeBSDKPrintf)
376 k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
377 else
379 break;
380 case 'B':
382 break;
383 // POSIX specific.
384 case 'C':
386 break;
387 case 'S':
389 break;
390 // Apple extension for os_log
391 case 'P':
393 break;
394 // Objective-C.
395 case '@':
397 break;
398 // Glibc specific.
399 case 'm':
401 break;
402 case 'r':
403 if (isFreeBSDKPrintf)
405 else if (LO.FixedPoint)
407 break;
408 case 'y':
409 if (isFreeBSDKPrintf)
411 break;
412 // Apple-specific.
413 case 'D':
414 if (isFreeBSDKPrintf)
415 k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *
416 else if (Target.getTriple().isOSDarwin())
418 break;
419 case 'O':
420 if (Target.getTriple().isOSDarwin())
422 break;
423 case 'U':
424 if (Target.getTriple().isOSDarwin())
426 break;
427 // MS specific.
428 case 'Z':
429 if (Target.getTriple().isOSMSVCRT())
431 break;
432 // ISO/IEC TR 18037 (fixed-point) specific.
433 // NOTE: 'r' is handled up above since FreeBSD also supports %r.
434 case 'k':
435 if (LO.FixedPoint)
437 break;
438 case 'K':
439 if (LO.FixedPoint)
441 break;
442 case 'R':
443 if (LO.FixedPoint)
445 break;
446 }
447
448 // Check to see if we used the Objective-C modifier flags with
449 // a conversion specifier other than '@'.
451 k != ConversionSpecifier::InvalidSpecifier && ObjCModifierFlagsStart) {
453 ObjCModifierFlagsStart, ObjCModifierFlagsEnd + 1, conversionPosition);
454 return true;
455 }
456
457 PrintfConversionSpecifier CS(conversionPosition, k);
459 if (CS.consumesDataArgument() && !FS.usesPositionalArg())
460 FS.setArgIndex(argIndex++);
461 // FreeBSD kernel specific.
464 argIndex++;
465
467 unsigned Len = I - Start;
468 if (ParseUTF8InvalidSpecifier(Start, E, Len)) {
469 CS.setEndScanList(Start + Len);
471 }
472 // Assume the conversion takes one argument.
473 return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len);
474 }
475 return PrintfSpecifierResult(Start, FS);
476}
477
479 FormatStringHandler &H, const char *I, const char *E, const LangOptions &LO,
480 const TargetInfo &Target, bool isFreeBSDKPrintf) {
481
482 unsigned argIndex = 0;
483
484 // Keep looking for a format specifier until we have exhausted the string.
485 while (I != E) {
487 H, I, E, argIndex, LO, Target, true, isFreeBSDKPrintf);
488 // Did a fail-stop error of any kind occur when parsing the specifier?
489 // If so, don't do any more processing.
490 if (FSR.shouldStop())
491 return true;
492 // Did we exhaust the string or encounter an error that
493 // we can recover from?
494 if (!FSR.hasValue())
495 continue;
496 // We have a format specifier. Pass it to the callback.
497 if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
498 I - FSR.getStart(), Target))
499 return true;
500 }
501 assert(I == E && "Format string not exhausted");
502 return false;
503}
504
506 const char *I, const char *E, const LangOptions &LO,
507 const TargetInfo &Target) {
508
509 unsigned argIndex = 0;
510
511 // Keep looking for a %s format specifier until we have exhausted the string.
513 while (I != E) {
514 const PrintfSpecifierResult &FSR =
515 ParsePrintfSpecifier(H, I, E, argIndex, LO, Target, false, false);
516 // Did a fail-stop error of any kind occur when parsing the specifier?
517 // If so, don't do any more processing.
518 if (FSR.shouldStop())
519 return false;
520 // Did we exhaust the string or encounter an error that
521 // we can recover from?
522 if (!FSR.hasValue())
523 continue;
525 // Return true if this a %s format specifier.
526 if (FS.getConversionSpecifier().getKind() ==
528 return true;
529 }
530 return false;
531}
532
534 const char *Begin, const char *End, const LangOptions &LO,
535 const TargetInfo &Target) {
536 unsigned ArgIndex = 0;
537 // Keep looking for a formatting specifier until we have exhausted the string.
539 while (Begin != End) {
540 const PrintfSpecifierResult &FSR =
541 ParsePrintfSpecifier(H, Begin, End, ArgIndex, LO, Target, false, false);
542 if (FSR.shouldStop())
543 break;
544 if (FSR.hasValue())
545 return true;
546 }
547 return false;
548}
549
550//===----------------------------------------------------------------------===//
551// Methods on PrintfSpecifier.
552//===----------------------------------------------------------------------===//
553
554ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
555 bool IsObjCLiteral) const {
557 switch (LM.getKind()) {
559 return Ctx.IntTy;
562 return ArgType(ArgType::WIntTy, "wint_t");
564 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
565 return Ctx.IntTy;
566 [[fallthrough]];
567 default:
568 return ArgType::Invalid();
569 }
570
571 if (CS.isIntArg())
572 switch (LM.getKind()) {
574 // GNU extension.
575 return Ctx.LongLongTy;
578 return Ctx.IntTy;
580 return ArgType(Ctx.IntTy, "__int32");
582 return ArgType::AnyCharTy;
584 return Ctx.ShortTy;
586 return Ctx.LongTy;
589 return Ctx.LongLongTy;
591 return ArgType(Ctx.LongLongTy, "__int64");
593 return ArgType(Ctx.getIntMaxType(), "intmax_t");
595 return ArgType::makeSizeT(
596 ArgType(Ctx.getSignedSizeType(), "signed size_t"));
598 return Ctx.getTargetInfo().getTriple().isArch64Bit()
599 ? ArgType(Ctx.LongLongTy, "__int64")
600 : ArgType(Ctx.IntTy, "__int32");
603 ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
607 return ArgType::Invalid();
608 }
609
610 if (CS.isUIntArg())
611 switch (LM.getKind()) {
613 // GNU extension.
614 return Ctx.UnsignedLongLongTy;
617 return Ctx.UnsignedIntTy;
619 return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
621 return Ctx.UnsignedCharTy;
623 return Ctx.UnsignedShortTy;
625 return Ctx.UnsignedLongTy;
628 return Ctx.UnsignedLongLongTy;
630 return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
632 return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
634 return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));
636 return Ctx.getTargetInfo().getTriple().isArch64Bit()
637 ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
638 : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
641 ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
645 return ArgType::Invalid();
646 }
647
648 if (CS.isDoubleArg()) {
649 if (!VectorNumElts.isInvalid()) {
650 switch (LM.getKind()) {
652 return Ctx.HalfTy;
654 return Ctx.FloatTy;
656 default:
657 return Ctx.DoubleTy;
658 }
659 }
660
661 if (LM.getKind() == LengthModifier::AsLongDouble)
662 return Ctx.LongDoubleTy;
663 return Ctx.DoubleTy;
664 }
665
666 if (CS.getKind() == ConversionSpecifier::nArg) {
667 switch (LM.getKind()) {
669 return ArgType::PtrTo(Ctx.IntTy);
671 return ArgType::PtrTo(Ctx.SignedCharTy);
673 return ArgType::PtrTo(Ctx.ShortTy);
675 return ArgType::PtrTo(Ctx.LongTy);
678 return ArgType::PtrTo(Ctx.LongLongTy);
680 return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
683 ArgType(Ctx.getSignedSizeType(), "signed size_t")));
686 ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")));
688 return ArgType(); // FIXME: Is this a known extension?
695 return ArgType::Invalid();
697 llvm_unreachable("only used for OpenCL which doesn not handle nArg");
698 }
699 }
700
701 if (CS.isFixedPointArg() && !Ctx.getLangOpts().FixedPoint)
702 return ArgType::Invalid();
703
704 switch (CS.getKind()) {
706 if (LM.getKind() == LengthModifier::AsWideChar) {
707 if (IsObjCLiteral)
708 return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
709 "const unichar *");
710 return ArgType(ArgType::WCStrTy, "wchar_t *");
711 }
712 if (LM.getKind() == LengthModifier::AsWide)
713 return ArgType(ArgType::WCStrTy, "wchar_t *");
714 return ArgType::CStrTy;
716 if (IsObjCLiteral)
717 return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
718 "const unichar *");
719 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
720 LM.getKind() == LengthModifier::AsShort)
721 return ArgType::CStrTy;
722 return ArgType(ArgType::WCStrTy, "wchar_t *");
724 if (IsObjCLiteral)
725 return ArgType(Ctx.UnsignedShortTy, "unichar");
726 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
727 LM.getKind() == LengthModifier::AsShort)
728 return Ctx.IntTy;
729 return ArgType(Ctx.WideCharTy, "wchar_t");
732 return ArgType::CPointerTy;
736 switch (LM.getKind()) {
738 return Ctx.AccumTy;
740 return Ctx.ShortAccumTy;
742 return Ctx.LongAccumTy;
743 default:
744 return ArgType::Invalid();
745 }
747 switch (LM.getKind()) {
749 return Ctx.UnsignedAccumTy;
751 return Ctx.UnsignedShortAccumTy;
753 return Ctx.UnsignedLongAccumTy;
754 default:
755 return ArgType::Invalid();
756 }
758 switch (LM.getKind()) {
760 return Ctx.FractTy;
762 return Ctx.ShortFractTy;
764 return Ctx.LongFractTy;
765 default:
766 return ArgType::Invalid();
767 }
769 switch (LM.getKind()) {
771 return Ctx.UnsignedFractTy;
773 return Ctx.UnsignedShortFractTy;
775 return Ctx.UnsignedLongFractTy;
776 default:
777 return ArgType::Invalid();
778 }
779 default:
780 break;
781 }
782
783 // FIXME: Handle other cases.
784 return ArgType();
785}
786
787ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, bool IsObjCLiteral) const {
789
790 if (!CS.consumesDataArgument())
791 return ArgType::Invalid();
792
793 ArgType ScalarTy = getScalarArgType(Ctx, IsObjCLiteral);
794 if (!ScalarTy.isValid() || VectorNumElts.isInvalid())
795 return ScalarTy;
796
797 return ScalarTy.makeVectorType(Ctx, VectorNumElts.getConstantAmount());
798}
799
801 ASTContext &Ctx, bool IsObjCLiteral) {
802 // %n is different from other conversion specifiers; don't try to fix it.
803 if (CS.getKind() == ConversionSpecifier::nArg)
804 return false;
805
806 // Handle Objective-C objects first. Note that while the '%@' specifier will
807 // not warn for structure pointer or void pointer arguments (because that's
808 // how CoreFoundation objects are implemented), we only show a fixit for '%@'
809 // if we know it's an object (block, id, class, or __attribute__((NSObject))).
810 if (QT->isObjCRetainableType()) {
811 if (!IsObjCLiteral)
812 return false;
813
815
816 // Disable irrelevant flags
817 HasThousandsGrouping = false;
818 HasPlusPrefix = false;
819 HasSpacePrefix = false;
820 HasAlternativeForm = false;
821 HasLeadingZeroes = false;
822 Precision.setHowSpecified(OptionalAmount::NotSpecified);
823 LM.setKind(LengthModifier::None);
824
825 return true;
826 }
827
828 // Handle strings next (char *, wchar_t *)
829 if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
831
832 // Disable irrelevant flags
833 HasAlternativeForm = false;
834 HasLeadingZeroes = false;
835
836 // Set the long length modifier for wide characters
837 if (QT->getPointeeType()->isWideCharType())
839 else
840 LM.setKind(LengthModifier::None);
841
842 return true;
843 }
844
845 // If it's an enum, get its underlying type.
846 if (const auto *ED = QT->getAsEnumDecl())
847 QT = ED->getIntegerType();
848
849 const BuiltinType *BT = QT->getAs<BuiltinType>();
850 if (!BT) {
851 const VectorType *VT = QT->getAs<VectorType>();
852 if (VT) {
853 QT = VT->getElementType();
854 BT = QT->getAs<BuiltinType>();
856 }
857 }
858
859 // We can only work with builtin types.
860 if (!BT)
861 return false;
862
863 // Set length modifier
864 switch (BT->getKind()) {
865 case BuiltinType::Bool:
866 case BuiltinType::WChar_U:
867 case BuiltinType::WChar_S:
868 case BuiltinType::Char8: // FIXME: Treat like 'char'?
869 case BuiltinType::Char16:
870 case BuiltinType::Char32:
871 case BuiltinType::UInt128:
872 case BuiltinType::Int128:
873 case BuiltinType::Half:
874 case BuiltinType::BFloat16:
875 case BuiltinType::Float16:
876 case BuiltinType::Float128:
877 case BuiltinType::Ibm128:
878 case BuiltinType::ShortAccum:
879 case BuiltinType::Accum:
880 case BuiltinType::LongAccum:
881 case BuiltinType::UShortAccum:
882 case BuiltinType::UAccum:
883 case BuiltinType::ULongAccum:
884 case BuiltinType::ShortFract:
885 case BuiltinType::Fract:
886 case BuiltinType::LongFract:
887 case BuiltinType::UShortFract:
888 case BuiltinType::UFract:
889 case BuiltinType::ULongFract:
890 case BuiltinType::SatShortAccum:
891 case BuiltinType::SatAccum:
892 case BuiltinType::SatLongAccum:
893 case BuiltinType::SatUShortAccum:
894 case BuiltinType::SatUAccum:
895 case BuiltinType::SatULongAccum:
896 case BuiltinType::SatShortFract:
897 case BuiltinType::SatFract:
898 case BuiltinType::SatLongFract:
899 case BuiltinType::SatUShortFract:
900 case BuiltinType::SatUFract:
901 case BuiltinType::SatULongFract:
902 // Various types which are non-trivial to correct.
903 return false;
904
905#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
906 case BuiltinType::Id:
907#include "clang/Basic/OpenCLImageTypes.def"
908
909#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) case BuiltinType::Id:
910#include "clang/Basic/OpenCLExtensionTypes.def"
911
912#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
913#include "clang/Basic/AArch64ACLETypes.def"
914
915#define PPC_VECTOR_TYPE(Name, Id, Size) case BuiltinType::Id:
916#include "clang/Basic/PPCTypes.def"
917
918#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
919#include "clang/Basic/RISCVVTypes.def"
920
921#define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
922#include "clang/Basic/WebAssemblyReferenceTypes.def"
923
924#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id:
925#include "clang/Basic/AMDGPUTypes.def"
926
927#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
928#include "clang/Basic/HLSLIntangibleTypes.def"
929
930#define SIGNED_TYPE(Id, SingletonId)
931#define UNSIGNED_TYPE(Id, SingletonId)
932#define FLOATING_TYPE(Id, SingletonId)
933#define BUILTIN_TYPE(Id, SingletonId) case BuiltinType::Id:
934#include "clang/AST/BuiltinTypes.def"
935
936 // Misc other stuff which doesn't make sense here.
937 return false;
938
939 case BuiltinType::UInt:
940 case BuiltinType::Int:
941 case BuiltinType::Float:
942 LM.setKind(VectorNumElts.isInvalid() ? LengthModifier::None
944 break;
945 case BuiltinType::Double:
946 LM.setKind(VectorNumElts.isInvalid() ? LengthModifier::None
948 break;
949 case BuiltinType::Char_U:
950 case BuiltinType::UChar:
951 case BuiltinType::Char_S:
952 case BuiltinType::SChar:
953 LM.setKind(LengthModifier::AsChar);
954 break;
955
956 case BuiltinType::Short:
957 case BuiltinType::UShort:
959 break;
960
961 case BuiltinType::Long:
962 case BuiltinType::ULong:
963 LM.setKind(LengthModifier::AsLong);
964 break;
965
966 case BuiltinType::LongLong:
967 case BuiltinType::ULongLong:
969 break;
970
971 case BuiltinType::LongDouble:
973 break;
974 }
975
976 // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
977 if (LangOpt.C99 || LangOpt.CPlusPlus11)
979
980 // If fixing the length modifier was enough, we might be done.
981 if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
982 // If we're going to offer a fix anyway, make sure the sign matches.
983 switch (CS.getKind()) {
986 if (QT->isSignedIntegerType())
988 break;
992 if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
994 break;
995 default:
996 // Other specifiers do not have signed/unsigned variants.
997 break;
998 }
999
1000 const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
1001 if (ATR.isValid() && ATR.matchesType(Ctx, QT))
1002 return true;
1003 }
1004
1005 // Set conversion specifier and disable any flags which do not apply to it.
1006 // Let typedefs to char fall through to int, as %c is silly for uint8_t.
1007 if (!QT->getAs<TypedefType>() && QT->isCharType()) {
1009 LM.setKind(LengthModifier::None);
1010 Precision.setHowSpecified(OptionalAmount::NotSpecified);
1011 HasAlternativeForm = false;
1012 HasLeadingZeroes = false;
1013 HasPlusPrefix = false;
1014 }
1015 // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
1016 else if (QT->isRealFloatingType()) {
1018 } else if (QT->isSignedIntegerType()) {
1020 HasAlternativeForm = false;
1021 } else if (QT->isUnsignedIntegerType()) {
1023 HasAlternativeForm = false;
1024 HasPlusPrefix = false;
1025 } else {
1026 llvm_unreachable("Unexpected type");
1027 }
1028
1029 return true;
1030}
1031
1032void PrintfSpecifier::toString(raw_ostream &os) const {
1033 // Whilst some features have no defined order, we are using the order
1034 // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
1035 os << "%";
1036
1037 // Positional args
1038 if (usesPositionalArg()) {
1039 os << getPositionalArgIndex() << "$";
1040 }
1041
1042 // Conversion flags
1043 if (IsLeftJustified)
1044 os << "-";
1045 if (HasPlusPrefix)
1046 os << "+";
1047 if (HasSpacePrefix)
1048 os << " ";
1049 if (HasAlternativeForm)
1050 os << "#";
1051 if (HasLeadingZeroes)
1052 os << "0";
1053
1054 // Minimum field width
1055 FieldWidth.toString(os);
1056 // Precision
1057 Precision.toString(os);
1058
1059 // Vector modifier
1060 if (!VectorNumElts.isInvalid())
1061 os << 'v' << VectorNumElts.getConstantAmount();
1062
1063 // Length modifier
1064 os << LM.toString();
1065 // Conversion specifier
1066 os << CS.toString();
1067}
1068
1070 if (!HasPlusPrefix)
1071 return true;
1072
1073 // The plus prefix only makes sense for signed conversions
1074 switch (CS.getKind()) {
1090 return true;
1091
1092 default:
1093 return false;
1094 }
1095}
1096
1098 if (!HasAlternativeForm)
1099 return true;
1100
1101 // Alternate form flag only valid with the bBoxXaAeEfFgGrRkK conversions
1102 switch (CS.getKind()) {
1123 return true;
1124
1125 default:
1126 return false;
1127 }
1128}
1129
1131 if (!HasLeadingZeroes)
1132 return true;
1133
1134 // Leading zeroes flag only valid with the bBdiouxXaAeEfFgGrRkK conversions
1135 switch (CS.getKind()) {
1161 return true;
1162
1163 default:
1164 return false;
1165 }
1166}
1167
1169 if (!HasSpacePrefix)
1170 return true;
1171
1172 // The space prefix only makes sense for signed conversions
1173 switch (CS.getKind()) {
1189 return true;
1190
1191 default:
1192 return false;
1193 }
1194}
1195
1197 if (!IsLeftJustified)
1198 return true;
1199
1200 // The left justified flag is valid for all conversions except n
1201 switch (CS.getKind()) {
1203 return false;
1204
1205 default:
1206 return true;
1207 }
1208}
1209
1211 if (!HasThousandsGrouping)
1212 return true;
1213
1214 switch (CS.getKind()) {
1224 return true;
1225 default:
1226 return false;
1227 }
1228}
1229
1231 if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
1232 return true;
1233
1234 // Precision is only valid with the bBdiouxXaAeEfFgGsPrRkK conversions
1235 switch (CS.getKind()) {
1263 return true;
1264
1265 default:
1266 return false;
1267 }
1268}
1270 if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
1271 return true;
1272
1273 // The field width is valid for all conversions except n
1274 switch (CS.getKind()) {
1276 return false;
1277
1278 default:
1279 return true;
1280 }
1281}
llvm::MachO::Target Target
Definition MachO.h:51
clang::analyze_format_string::SpecifierResult< PrintfSpecifier > PrintfSpecifierResult
static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, const char *Start, const char *&Beg, const char *E, unsigned *argIndex)
static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, unsigned &argIndex, const LangOptions &LO, const TargetInfo &Target, bool Warn, bool isFreeBSDKPrintf)
static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS, const char *FlagBeg, const char *E, bool Warn)
__device__ __2f16 float c
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:227
CanQualType AccumTy
CanQualType LongTy
CanQualType UnsignedShortAccumTy
QualType getUnsignedPointerDiffType() const
Return the unique unsigned counterpart of "ptrdiff_t" integer type.
CanQualType ShortAccumTy
CanQualType FloatTy
CanQualType DoubleTy
CanQualType getIntMaxType() const
Return the unique type for "intmax_t" (C99 7.18.1.5), defined in <stdint.h>.
CanQualType LongDoubleTy
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
CanQualType UnsignedLongFractTy
CanQualType WideCharTy
const LangOptions & getLangOpts() const
Definition ASTContext.h:959
QualType getPointerDiffType() const
Return the unique type for "ptrdiff_t" (C99 7.17) defined in <stddef.h>.
CanQualType UnsignedFractTy
CanQualType UnsignedLongTy
CanQualType UnsignedLongAccumTy
CanQualType ShortFractTy
CanQualType IntTy
CanQualType SignedCharTy
CanQualType UnsignedCharTy
CanQualType UnsignedShortFractTy
CanQualType UnsignedIntTy
CanQualType UnsignedLongLongTy
CanQualType UnsignedShortTy
CanQualType ShortTy
CanQualType FractTy
CanQualType LongAccumTy
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:924
CanQualType LongFractTy
QualType getSignedSizeType() const
Return the unique signed counterpart of the integer type corresponding to size_t.
CanQualType LongLongTy
CanQualType getUIntMaxType() const
Return the unique type for "uintmax_t" (C99 7.18.1.5), defined in <stdint.h>.
CanQualType HalfTy
CanQualType UnsignedAccumTy
This class is used for builtin types like 'int'.
Definition TypeBase.h:3219
Kind getKind() const
Definition TypeBase.h:3267
QualType withConst() const
Retrieves a version of this type with const applied.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
A (possibly-)qualified type.
Definition TypeBase.h:937
Exposes information about the current target.
Definition TargetInfo.h:227
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
Definition Type.cpp:2266
bool isCharType() const
Definition Type.cpp:2193
bool isPointerType() const
Definition TypeBase.h:8673
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
bool isAnyCharacterType() const
Determine whether this type is any of the built-in character types.
Definition Type.cpp:2229
EnumDecl * getAsEnumDecl() const
Retrieves the EnumDecl this type refers to.
Definition Type.h:53
bool isRealFloatingType() const
Floating point categories.
Definition Type.cpp:2405
bool isWideCharType() const
Definition Type.cpp:2202
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
Definition Type.cpp:2332
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9266
bool isObjCRetainableType() const
Definition Type.cpp:5417
Represents a GCC generic vector type.
Definition TypeBase.h:4230
unsigned getNumElements() const
Definition TypeBase.h:4245
QualType getElementType() const
Definition TypeBase.h:4244
ArgType makeVectorType(ASTContext &C, unsigned NumElts) const
MatchKind matchesType(ASTContext &C, QualType argTy) const
static bool namedTypeToLengthModifier(ASTContext &Ctx, QualType QT, LengthModifier &LM)
For a TypedefType QT, if it is a named integer type such as size_t, assign the appropriate value to L...
bool hasValidLengthModifier(const TargetInfo &Target, const LangOptions &LO) const
virtual bool HandleInvalidPrintfConversionSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen)
virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart, const char *flagsEnd, const char *conversionPosition)
virtual void HandleInvalidObjCModifierFlag(const char *startFlag, unsigned flagLen)
virtual void HandleNullChar(const char *nullCharacter)
virtual void handleInvalidMaskType(StringRef MaskType)
Handle mask types whose sizes are not between one and eight bytes.
virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen, const TargetInfo &Target)
virtual void HandleEmptyObjCModifierFlag(const char *startFlags, unsigned flagsLen)
virtual void HandleIncompleteSpecifier(const char *startSpecifier, unsigned specifierLen)
Represents the length modifier in a format string in scanf/printf.
static ArgType makePtrdiffT(const ArgType &A)
Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t type.
static ArgType PtrTo(const ArgType &A)
Create an ArgType which corresponds to the type pointer to A.
static ArgType makeSizeT(const ArgType &A)
Create an ArgType which corresponds to the size_t/ssize_t type.
void setHasAlternativeForm(const char *position)
void setIsSensitive(const char *position)
void setHasSpacePrefix(const char *position)
void setHasThousandsGrouping(const char *position)
void setIsLeftJustified(const char *position)
bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx, bool IsObjCLiteral)
Changes the specifier and length according to a QualType, retaining any flags or options.
void setHasPlusPrefix(const char *position)
void setIsPrivate(const char *position)
const PrintfConversionSpecifier & getConversionSpecifier() const
void setHasLeadingZeros(const char *position)
ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const
Returns the builtin type that a data argument paired with this format specifier should have.
void setIsPublic(const char *position)
void setPrecision(const OptionalAmount &Amt)
void setHasObjCTechnicalTerm(const char *position)
void setConversionSpecifier(const PrintfConversionSpecifier &cs)
Defines the clang::TargetInfo interface.
Common components of both fprintf and fscanf format strings.
bool parseFormatStringHasFormattingSpecifiers(const char *Begin, const char *End, const LangOptions &LO, const TargetInfo &Target)
Return true if the given string has at least one formatting specifier.
bool ParseFieldWidth(FormatStringHandler &H, FormatSpecifier &CS, const char *Start, const char *&Beg, const char *E, unsigned *argIndex)
OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E, unsigned &argIndex)
bool ParsePrintfString(FormatStringHandler &H, const char *beg, const char *end, const LangOptions &LO, const TargetInfo &Target, bool isFreeBSDKPrintf)
bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const char *E, const LangOptions &LO, bool IsScanf=false)
Returns true if a LengthModifier was parsed and installed in the FormatSpecifier& argument,...
bool ParseArgPosition(FormatStringHandler &H, FormatSpecifier &CS, const char *Start, const char *&Beg, const char *E)
bool ParseVectorModifier(FormatStringHandler &H, FormatSpecifier &FS, const char *&Beg, const char *E, const LangOptions &LO)
bool ParseFormatStringHasSArg(const char *beg, const char *end, const LangOptions &LO, const TargetInfo &Target)
bool ParseUTF8InvalidSpecifier(const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len)
Returns true if the invalid specifier in SpecifierBegin is a UTF-8 string; check that it won't go fur...
Pieces specific to fprintf format strings.
The JSON file list parser is used to communicate input to InstallAPI.
@ Match
This is not an overload because the signature exactly matches an existing declaration.
Definition Sema.h:830