1314fbfa1STim Northover //== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==//
2314fbfa1STim Northover //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6314fbfa1STim Northover //
7314fbfa1STim Northover //===----------------------------------------------------------------------===//
8314fbfa1STim Northover //
9314fbfa1STim Northover // Handling of format string in printf and friends. The structure of format
10314fbfa1STim Northover // strings for fprintf() are described in C99 7.19.6.1.
11314fbfa1STim Northover //
12314fbfa1STim Northover //===----------------------------------------------------------------------===//
13314fbfa1STim Northover
147314aea5SDaniel Kiss #include "FormatStringParsing.h"
15314fbfa1STim Northover #include "clang/AST/FormatString.h"
16314fbfa1STim Northover #include "clang/AST/OSLog.h"
17314fbfa1STim Northover #include "clang/Basic/TargetInfo.h"
187314aea5SDaniel Kiss #include "llvm/Support/Regex.h"
19314fbfa1STim Northover
20314fbfa1STim Northover using clang::analyze_format_string::ArgType;
21314fbfa1STim Northover using clang::analyze_format_string::FormatStringHandler;
22314fbfa1STim Northover using clang::analyze_format_string::LengthModifier;
23314fbfa1STim Northover using clang::analyze_format_string::OptionalAmount;
24314fbfa1STim Northover using clang::analyze_format_string::ConversionSpecifier;
25314fbfa1STim Northover using clang::analyze_printf::PrintfSpecifier;
26314fbfa1STim Northover
27314fbfa1STim Northover using namespace clang;
28314fbfa1STim Northover
29314fbfa1STim Northover typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
30314fbfa1STim Northover PrintfSpecifierResult;
31314fbfa1STim Northover
32314fbfa1STim Northover //===----------------------------------------------------------------------===//
33314fbfa1STim Northover // Methods for parsing format strings.
34314fbfa1STim Northover //===----------------------------------------------------------------------===//
35314fbfa1STim Northover
36314fbfa1STim Northover using analyze_format_string::ParseNonPositionAmount;
37314fbfa1STim Northover
ParsePrecision(FormatStringHandler & H,PrintfSpecifier & FS,const char * Start,const char * & Beg,const char * E,unsigned * argIndex)38314fbfa1STim Northover static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
39314fbfa1STim Northover const char *Start, const char *&Beg, const char *E,
40314fbfa1STim Northover unsigned *argIndex) {
41314fbfa1STim Northover if (argIndex) {
42314fbfa1STim Northover FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
43314fbfa1STim Northover } else {
44314fbfa1STim Northover const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
45314fbfa1STim Northover analyze_format_string::PrecisionPos);
46314fbfa1STim Northover if (Amt.isInvalid())
47314fbfa1STim Northover return true;
48314fbfa1STim Northover FS.setPrecision(Amt);
49314fbfa1STim Northover }
50314fbfa1STim Northover return false;
51314fbfa1STim Northover }
52314fbfa1STim Northover
ParseObjCFlags(FormatStringHandler & H,PrintfSpecifier & FS,const char * FlagBeg,const char * E,bool Warn)53314fbfa1STim Northover static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,
54314fbfa1STim Northover const char *FlagBeg, const char *E, bool Warn) {
55314fbfa1STim Northover StringRef Flag(FlagBeg, E - FlagBeg);
56314fbfa1STim Northover // Currently there is only one flag.
57314fbfa1STim Northover if (Flag == "tt") {
58314fbfa1STim Northover FS.setHasObjCTechnicalTerm(FlagBeg);
59314fbfa1STim Northover return false;
60314fbfa1STim Northover }
61314fbfa1STim Northover // Handle either the case of no flag or an invalid flag.
62314fbfa1STim Northover if (Warn) {
63314fbfa1STim Northover if (Flag == "")
64314fbfa1STim Northover H.HandleEmptyObjCModifierFlag(FlagBeg, E - FlagBeg);
65314fbfa1STim Northover else
66314fbfa1STim Northover H.HandleInvalidObjCModifierFlag(FlagBeg, E - FlagBeg);
67314fbfa1STim Northover }
68314fbfa1STim Northover return true;
69314fbfa1STim Northover }
70314fbfa1STim Northover
ParsePrintfSpecifier(FormatStringHandler & H,const char * & Beg,const char * E,unsigned & argIndex,const LangOptions & LO,const TargetInfo & Target,bool Warn,bool isFreeBSDKPrintf)71314fbfa1STim Northover static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
72314fbfa1STim Northover const char *&Beg,
73314fbfa1STim Northover const char *E,
74314fbfa1STim Northover unsigned &argIndex,
75314fbfa1STim Northover const LangOptions &LO,
76314fbfa1STim Northover const TargetInfo &Target,
77314fbfa1STim Northover bool Warn,
78314fbfa1STim Northover bool isFreeBSDKPrintf) {
79314fbfa1STim Northover
80314fbfa1STim Northover using namespace clang::analyze_format_string;
81314fbfa1STim Northover using namespace clang::analyze_printf;
82314fbfa1STim Northover
83314fbfa1STim Northover const char *I = Beg;
84314fbfa1STim Northover const char *Start = nullptr;
85314fbfa1STim Northover UpdateOnReturn <const char*> UpdateBeg(Beg, I);
86314fbfa1STim Northover
87314fbfa1STim Northover // Look for a '%' character that indicates the start of a format specifier.
88314fbfa1STim Northover for ( ; I != E ; ++I) {
89314fbfa1STim Northover char c = *I;
90314fbfa1STim Northover if (c == '\0') {
91314fbfa1STim Northover // Detect spurious null characters, which are likely errors.
92314fbfa1STim Northover H.HandleNullChar(I);
93314fbfa1STim Northover return true;
94314fbfa1STim Northover }
95314fbfa1STim Northover if (c == '%') {
96314fbfa1STim Northover Start = I++; // Record the start of the format specifier.
97314fbfa1STim Northover break;
98314fbfa1STim Northover }
99314fbfa1STim Northover }
100314fbfa1STim Northover
101314fbfa1STim Northover // No format specifier found?
102314fbfa1STim Northover if (!Start)
103314fbfa1STim Northover return false;
104314fbfa1STim Northover
105314fbfa1STim Northover if (I == E) {
106314fbfa1STim Northover // No more characters left?
107314fbfa1STim Northover if (Warn)
108314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start);
109314fbfa1STim Northover return true;
110314fbfa1STim Northover }
111314fbfa1STim Northover
112314fbfa1STim Northover PrintfSpecifier FS;
113314fbfa1STim Northover if (ParseArgPosition(H, FS, Start, I, E))
114314fbfa1STim Northover return true;
115314fbfa1STim Northover
116314fbfa1STim Northover if (I == E) {
117314fbfa1STim Northover // No more characters left?
118314fbfa1STim Northover if (Warn)
119314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start);
120314fbfa1STim Northover return true;
121314fbfa1STim Northover }
122314fbfa1STim Northover
123314fbfa1STim Northover if (*I == '{') {
124314fbfa1STim Northover ++I;
125314fbfa1STim Northover unsigned char PrivacyFlags = 0;
126314fbfa1STim Northover StringRef MatchedStr;
127314fbfa1STim Northover
128314fbfa1STim Northover do {
129314fbfa1STim Northover StringRef Str(I, E - I);
130d572cf49SAkira Hatanaka std::string Match = "^[[:space:]]*"
131d572cf49SAkira Hatanaka "(private|public|sensitive|mask\\.[^[:space:],}]*)"
132fb1e4465SAkira Hatanaka "[[:space:]]*(,|})";
133314fbfa1STim Northover llvm::Regex R(Match);
134314fbfa1STim Northover SmallVector<StringRef, 2> Matches;
135314fbfa1STim Northover
136314fbfa1STim Northover if (R.match(Str, &Matches)) {
137314fbfa1STim Northover MatchedStr = Matches[1];
138314fbfa1STim Northover I += Matches[0].size();
139314fbfa1STim Northover
140314fbfa1STim Northover // Set the privacy flag if the privacy annotation in the
141314fbfa1STim Northover // comma-delimited segment is at least as strict as the privacy
142314fbfa1STim Northover // annotations in previous comma-delimited segments.
143d572cf49SAkira Hatanaka if (MatchedStr.startswith("mask")) {
144d572cf49SAkira Hatanaka StringRef MaskType = MatchedStr.substr(sizeof("mask.") - 1);
145d572cf49SAkira Hatanaka unsigned Size = MaskType.size();
146d572cf49SAkira Hatanaka if (Warn && (Size == 0 || Size > 8))
147d572cf49SAkira Hatanaka H.handleInvalidMaskType(MaskType);
148d572cf49SAkira Hatanaka FS.setMaskType(MaskType);
149d572cf49SAkira Hatanaka } else if (MatchedStr.equals("sensitive"))
150fb1e4465SAkira Hatanaka PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsSensitive;
151fb1e4465SAkira Hatanaka else if (PrivacyFlags !=
152fb1e4465SAkira Hatanaka clang::analyze_os_log::OSLogBufferItem::IsSensitive &&
153fb1e4465SAkira Hatanaka MatchedStr.equals("private"))
154314fbfa1STim Northover PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate;
155314fbfa1STim Northover else if (PrivacyFlags == 0 && MatchedStr.equals("public"))
156314fbfa1STim Northover PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic;
157314fbfa1STim Northover } else {
158314fbfa1STim Northover size_t CommaOrBracePos =
159314fbfa1STim Northover Str.find_if([](char c) { return c == ',' || c == '}'; });
160314fbfa1STim Northover
161314fbfa1STim Northover if (CommaOrBracePos == StringRef::npos) {
162314fbfa1STim Northover // Neither a comma nor the closing brace was found.
163314fbfa1STim Northover if (Warn)
164314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start);
165314fbfa1STim Northover return true;
166314fbfa1STim Northover }
167314fbfa1STim Northover
168314fbfa1STim Northover I += CommaOrBracePos + 1;
169314fbfa1STim Northover }
170314fbfa1STim Northover // Continue until the closing brace is found.
171314fbfa1STim Northover } while (*(I - 1) == ',');
172314fbfa1STim Northover
173314fbfa1STim Northover // Set the privacy flag.
174314fbfa1STim Northover switch (PrivacyFlags) {
175314fbfa1STim Northover case 0:
176314fbfa1STim Northover break;
177314fbfa1STim Northover case clang::analyze_os_log::OSLogBufferItem::IsPrivate:
178314fbfa1STim Northover FS.setIsPrivate(MatchedStr.data());
179314fbfa1STim Northover break;
180314fbfa1STim Northover case clang::analyze_os_log::OSLogBufferItem::IsPublic:
181314fbfa1STim Northover FS.setIsPublic(MatchedStr.data());
182314fbfa1STim Northover break;
183fb1e4465SAkira Hatanaka case clang::analyze_os_log::OSLogBufferItem::IsSensitive:
184fb1e4465SAkira Hatanaka FS.setIsSensitive(MatchedStr.data());
185fb1e4465SAkira Hatanaka break;
186314fbfa1STim Northover default:
187314fbfa1STim Northover llvm_unreachable("Unexpected privacy flag value");
188314fbfa1STim Northover }
189314fbfa1STim Northover }
190314fbfa1STim Northover
191314fbfa1STim Northover // Look for flags (if any).
192314fbfa1STim Northover bool hasMore = true;
193314fbfa1STim Northover for ( ; I != E; ++I) {
194314fbfa1STim Northover switch (*I) {
195314fbfa1STim Northover default: hasMore = false; break;
196314fbfa1STim Northover case '\'':
197314fbfa1STim Northover // FIXME: POSIX specific. Always accept?
198314fbfa1STim Northover FS.setHasThousandsGrouping(I);
199314fbfa1STim Northover break;
200314fbfa1STim Northover case '-': FS.setIsLeftJustified(I); break;
201314fbfa1STim Northover case '+': FS.setHasPlusPrefix(I); break;
202314fbfa1STim Northover case ' ': FS.setHasSpacePrefix(I); break;
203314fbfa1STim Northover case '#': FS.setHasAlternativeForm(I); break;
204314fbfa1STim Northover case '0': FS.setHasLeadingZeros(I); break;
205314fbfa1STim Northover }
206314fbfa1STim Northover if (!hasMore)
207314fbfa1STim Northover break;
208314fbfa1STim Northover }
209314fbfa1STim Northover
210314fbfa1STim Northover if (I == E) {
211314fbfa1STim Northover // No more characters left?
212314fbfa1STim Northover if (Warn)
213314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start);
214314fbfa1STim Northover return true;
215314fbfa1STim Northover }
216314fbfa1STim Northover
217314fbfa1STim Northover // Look for the field width (if any).
218314fbfa1STim Northover if (ParseFieldWidth(H, FS, Start, I, E,
219314fbfa1STim Northover FS.usesPositionalArg() ? nullptr : &argIndex))
220314fbfa1STim Northover return true;
221314fbfa1STim Northover
222314fbfa1STim Northover if (I == E) {
223314fbfa1STim Northover // No more characters left?
224314fbfa1STim Northover if (Warn)
225314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start);
226314fbfa1STim Northover return true;
227314fbfa1STim Northover }
228314fbfa1STim Northover
229314fbfa1STim Northover // Look for the precision (if any).
230314fbfa1STim Northover if (*I == '.') {
231314fbfa1STim Northover ++I;
232314fbfa1STim Northover if (I == E) {
233314fbfa1STim Northover if (Warn)
234314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start);
235314fbfa1STim Northover return true;
236314fbfa1STim Northover }
237314fbfa1STim Northover
238314fbfa1STim Northover if (ParsePrecision(H, FS, Start, I, E,
239314fbfa1STim Northover FS.usesPositionalArg() ? nullptr : &argIndex))
240314fbfa1STim Northover return true;
241314fbfa1STim Northover
242314fbfa1STim Northover if (I == E) {
243314fbfa1STim Northover // No more characters left?
244314fbfa1STim Northover if (Warn)
245314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start);
246314fbfa1STim Northover return true;
247314fbfa1STim Northover }
248314fbfa1STim Northover }
249314fbfa1STim Northover
2500ff50d49SMatt Arsenault if (ParseVectorModifier(H, FS, I, E, LO))
2510ff50d49SMatt Arsenault return true;
2520ff50d49SMatt Arsenault
253314fbfa1STim Northover // Look for the length modifier.
254314fbfa1STim Northover if (ParseLengthModifier(FS, I, E, LO) && I == E) {
255314fbfa1STim Northover // No more characters left?
256314fbfa1STim Northover if (Warn)
257314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start);
258314fbfa1STim Northover return true;
259314fbfa1STim Northover }
260314fbfa1STim Northover
261314fbfa1STim Northover // Look for the Objective-C modifier flags, if any.
262314fbfa1STim Northover // We parse these here, even if they don't apply to
263314fbfa1STim Northover // the conversion specifier, and then emit an error
264314fbfa1STim Northover // later if the conversion specifier isn't '@'. This
265314fbfa1STim Northover // enables better recovery, and we don't know if
266314fbfa1STim Northover // these flags are applicable until later.
267314fbfa1STim Northover const char *ObjCModifierFlagsStart = nullptr,
268314fbfa1STim Northover *ObjCModifierFlagsEnd = nullptr;
269314fbfa1STim Northover if (*I == '[') {
270314fbfa1STim Northover ObjCModifierFlagsStart = I;
271314fbfa1STim Northover ++I;
272314fbfa1STim Northover auto flagStart = I;
273314fbfa1STim Northover for (;; ++I) {
274314fbfa1STim Northover ObjCModifierFlagsEnd = I;
275314fbfa1STim Northover if (I == E) {
276314fbfa1STim Northover if (Warn)
277314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start);
278314fbfa1STim Northover return true;
279314fbfa1STim Northover }
280314fbfa1STim Northover // Did we find the closing ']'?
281314fbfa1STim Northover if (*I == ']') {
282314fbfa1STim Northover if (ParseObjCFlags(H, FS, flagStart, I, Warn))
283314fbfa1STim Northover return true;
284314fbfa1STim Northover ++I;
285314fbfa1STim Northover break;
286314fbfa1STim Northover }
287314fbfa1STim Northover // There are no separators defined yet for multiple
288314fbfa1STim Northover // Objective-C modifier flags. When those are
289314fbfa1STim Northover // defined, this is the place to check.
290314fbfa1STim Northover }
291314fbfa1STim Northover }
292314fbfa1STim Northover
293314fbfa1STim Northover if (*I == '\0') {
294314fbfa1STim Northover // Detect spurious null characters, which are likely errors.
295314fbfa1STim Northover H.HandleNullChar(I);
296314fbfa1STim Northover return true;
297314fbfa1STim Northover }
298314fbfa1STim Northover
299314fbfa1STim Northover // Finally, look for the conversion specifier.
300314fbfa1STim Northover const char *conversionPosition = I++;
301314fbfa1STim Northover ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
302314fbfa1STim Northover switch (*conversionPosition) {
303314fbfa1STim Northover default:
304314fbfa1STim Northover break;
305314fbfa1STim Northover // C99: 7.19.6.1 (section 8).
306314fbfa1STim Northover case '%': k = ConversionSpecifier::PercentArg; break;
307314fbfa1STim Northover case 'A': k = ConversionSpecifier::AArg; break;
308314fbfa1STim Northover case 'E': k = ConversionSpecifier::EArg; break;
309314fbfa1STim Northover case 'F': k = ConversionSpecifier::FArg; break;
310314fbfa1STim Northover case 'G': k = ConversionSpecifier::GArg; break;
311314fbfa1STim Northover case 'X': k = ConversionSpecifier::XArg; break;
312314fbfa1STim Northover case 'a': k = ConversionSpecifier::aArg; break;
313314fbfa1STim Northover case 'c': k = ConversionSpecifier::cArg; break;
314314fbfa1STim Northover case 'd': k = ConversionSpecifier::dArg; break;
315314fbfa1STim Northover case 'e': k = ConversionSpecifier::eArg; break;
316314fbfa1STim Northover case 'f': k = ConversionSpecifier::fArg; break;
317314fbfa1STim Northover case 'g': k = ConversionSpecifier::gArg; break;
318314fbfa1STim Northover case 'i': k = ConversionSpecifier::iArg; break;
31958fc8082SMatt Arsenault case 'n':
32058fc8082SMatt Arsenault // Not handled, but reserved in OpenCL.
32158fc8082SMatt Arsenault if (!LO.OpenCL)
32258fc8082SMatt Arsenault k = ConversionSpecifier::nArg;
32358fc8082SMatt Arsenault break;
324314fbfa1STim Northover case 'o': k = ConversionSpecifier::oArg; break;
325314fbfa1STim Northover case 'p': k = ConversionSpecifier::pArg; break;
326314fbfa1STim Northover case 's': k = ConversionSpecifier::sArg; break;
327314fbfa1STim Northover case 'u': k = ConversionSpecifier::uArg; break;
328314fbfa1STim Northover case 'x': k = ConversionSpecifier::xArg; break;
329314fbfa1STim Northover // POSIX specific.
330314fbfa1STim Northover case 'C': k = ConversionSpecifier::CArg; break;
331314fbfa1STim Northover case 'S': k = ConversionSpecifier::SArg; break;
332314fbfa1STim Northover // Apple extension for os_log
333314fbfa1STim Northover case 'P':
334314fbfa1STim Northover k = ConversionSpecifier::PArg;
335314fbfa1STim Northover break;
336314fbfa1STim Northover // Objective-C.
337314fbfa1STim Northover case '@': k = ConversionSpecifier::ObjCObjArg; break;
338314fbfa1STim Northover // Glibc specific.
339314fbfa1STim Northover case 'm': k = ConversionSpecifier::PrintErrno; break;
340314fbfa1STim Northover // FreeBSD kernel specific.
341314fbfa1STim Northover case 'b':
342314fbfa1STim Northover if (isFreeBSDKPrintf)
343314fbfa1STim Northover k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
344314fbfa1STim Northover break;
345314fbfa1STim Northover case 'r':
346314fbfa1STim Northover if (isFreeBSDKPrintf)
347314fbfa1STim Northover k = ConversionSpecifier::FreeBSDrArg; // int
348314fbfa1STim Northover break;
349314fbfa1STim Northover case 'y':
350314fbfa1STim Northover if (isFreeBSDKPrintf)
351314fbfa1STim Northover k = ConversionSpecifier::FreeBSDyArg; // int
352314fbfa1STim Northover break;
353314fbfa1STim Northover // Apple-specific.
354314fbfa1STim Northover case 'D':
355314fbfa1STim Northover if (isFreeBSDKPrintf)
356314fbfa1STim Northover k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *
357314fbfa1STim Northover else if (Target.getTriple().isOSDarwin())
358314fbfa1STim Northover k = ConversionSpecifier::DArg;
359314fbfa1STim Northover break;
360314fbfa1STim Northover case 'O':
361314fbfa1STim Northover if (Target.getTriple().isOSDarwin())
362314fbfa1STim Northover k = ConversionSpecifier::OArg;
363314fbfa1STim Northover break;
364314fbfa1STim Northover case 'U':
365314fbfa1STim Northover if (Target.getTriple().isOSDarwin())
366314fbfa1STim Northover k = ConversionSpecifier::UArg;
367314fbfa1STim Northover break;
368314fbfa1STim Northover // MS specific.
369314fbfa1STim Northover case 'Z':
370314fbfa1STim Northover if (Target.getTriple().isOSMSVCRT())
371314fbfa1STim Northover k = ConversionSpecifier::ZArg;
372e19dc613SMatt Arsenault break;
373314fbfa1STim Northover }
374314fbfa1STim Northover
375314fbfa1STim Northover // Check to see if we used the Objective-C modifier flags with
376314fbfa1STim Northover // a conversion specifier other than '@'.
377314fbfa1STim Northover if (k != ConversionSpecifier::ObjCObjArg &&
378314fbfa1STim Northover k != ConversionSpecifier::InvalidSpecifier &&
379314fbfa1STim Northover ObjCModifierFlagsStart) {
380314fbfa1STim Northover H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart,
381314fbfa1STim Northover ObjCModifierFlagsEnd + 1,
382314fbfa1STim Northover conversionPosition);
383314fbfa1STim Northover return true;
384314fbfa1STim Northover }
385314fbfa1STim Northover
386314fbfa1STim Northover PrintfConversionSpecifier CS(conversionPosition, k);
387314fbfa1STim Northover FS.setConversionSpecifier(CS);
388314fbfa1STim Northover if (CS.consumesDataArgument() && !FS.usesPositionalArg())
389314fbfa1STim Northover FS.setArgIndex(argIndex++);
390314fbfa1STim Northover // FreeBSD kernel specific.
391314fbfa1STim Northover if (k == ConversionSpecifier::FreeBSDbArg ||
392314fbfa1STim Northover k == ConversionSpecifier::FreeBSDDArg)
393314fbfa1STim Northover argIndex++;
394314fbfa1STim Northover
395314fbfa1STim Northover if (k == ConversionSpecifier::InvalidSpecifier) {
396314fbfa1STim Northover unsigned Len = I - Start;
397314fbfa1STim Northover if (ParseUTF8InvalidSpecifier(Start, E, Len)) {
398314fbfa1STim Northover CS.setEndScanList(Start + Len);
399314fbfa1STim Northover FS.setConversionSpecifier(CS);
400314fbfa1STim Northover }
401314fbfa1STim Northover // Assume the conversion takes one argument.
402314fbfa1STim Northover return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len);
403314fbfa1STim Northover }
404314fbfa1STim Northover return PrintfSpecifierResult(Start, FS);
405314fbfa1STim Northover }
406314fbfa1STim Northover
ParsePrintfString(FormatStringHandler & H,const char * I,const char * E,const LangOptions & LO,const TargetInfo & Target,bool isFreeBSDKPrintf)407314fbfa1STim Northover bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
408314fbfa1STim Northover const char *I,
409314fbfa1STim Northover const char *E,
410314fbfa1STim Northover const LangOptions &LO,
411314fbfa1STim Northover const TargetInfo &Target,
412314fbfa1STim Northover bool isFreeBSDKPrintf) {
413314fbfa1STim Northover
414314fbfa1STim Northover unsigned argIndex = 0;
415314fbfa1STim Northover
416314fbfa1STim Northover // Keep looking for a format specifier until we have exhausted the string.
417314fbfa1STim Northover while (I != E) {
418314fbfa1STim Northover const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
419314fbfa1STim Northover LO, Target, true,
420314fbfa1STim Northover isFreeBSDKPrintf);
421314fbfa1STim Northover // Did a fail-stop error of any kind occur when parsing the specifier?
422314fbfa1STim Northover // If so, don't do any more processing.
423314fbfa1STim Northover if (FSR.shouldStop())
424314fbfa1STim Northover return true;
425314fbfa1STim Northover // Did we exhaust the string or encounter an error that
426314fbfa1STim Northover // we can recover from?
427314fbfa1STim Northover if (!FSR.hasValue())
428314fbfa1STim Northover continue;
429314fbfa1STim Northover // We have a format specifier. Pass it to the callback.
430314fbfa1STim Northover if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
431cd4e600fSAlex Brachet I - FSR.getStart(), Target))
432314fbfa1STim Northover return true;
433314fbfa1STim Northover }
434314fbfa1STim Northover assert(I == E && "Format string not exhausted");
435314fbfa1STim Northover return false;
436314fbfa1STim Northover }
437314fbfa1STim Northover
ParseFormatStringHasSArg(const char * I,const char * E,const LangOptions & LO,const TargetInfo & Target)438314fbfa1STim Northover bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
439314fbfa1STim Northover const char *E,
440314fbfa1STim Northover const LangOptions &LO,
441314fbfa1STim Northover const TargetInfo &Target) {
442314fbfa1STim Northover
443314fbfa1STim Northover unsigned argIndex = 0;
444314fbfa1STim Northover
445314fbfa1STim Northover // Keep looking for a %s format specifier until we have exhausted the string.
446314fbfa1STim Northover FormatStringHandler H;
447314fbfa1STim Northover while (I != E) {
448314fbfa1STim Northover const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
449314fbfa1STim Northover LO, Target, false,
450314fbfa1STim Northover false);
451314fbfa1STim Northover // Did a fail-stop error of any kind occur when parsing the specifier?
452314fbfa1STim Northover // If so, don't do any more processing.
453314fbfa1STim Northover if (FSR.shouldStop())
454314fbfa1STim Northover return false;
455314fbfa1STim Northover // Did we exhaust the string or encounter an error that
456314fbfa1STim Northover // we can recover from?
457314fbfa1STim Northover if (!FSR.hasValue())
458314fbfa1STim Northover continue;
459314fbfa1STim Northover const analyze_printf::PrintfSpecifier &FS = FSR.getValue();
460314fbfa1STim Northover // Return true if this a %s format specifier.
461314fbfa1STim Northover if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg)
462314fbfa1STim Northover return true;
463314fbfa1STim Northover }
464314fbfa1STim Northover return false;
465314fbfa1STim Northover }
466314fbfa1STim Northover
parseFormatStringHasFormattingSpecifiers(const char * Begin,const char * End,const LangOptions & LO,const TargetInfo & Target)467aa385569SErik Pilkington bool clang::analyze_format_string::parseFormatStringHasFormattingSpecifiers(
468aa385569SErik Pilkington const char *Begin, const char *End, const LangOptions &LO,
469aa385569SErik Pilkington const TargetInfo &Target) {
470aa385569SErik Pilkington unsigned ArgIndex = 0;
471aa385569SErik Pilkington // Keep looking for a formatting specifier until we have exhausted the string.
472aa385569SErik Pilkington FormatStringHandler H;
473aa385569SErik Pilkington while (Begin != End) {
474aa385569SErik Pilkington const PrintfSpecifierResult &FSR =
475aa385569SErik Pilkington ParsePrintfSpecifier(H, Begin, End, ArgIndex, LO, Target, false, false);
476aa385569SErik Pilkington if (FSR.shouldStop())
477aa385569SErik Pilkington break;
478aa385569SErik Pilkington if (FSR.hasValue())
479aa385569SErik Pilkington return true;
480aa385569SErik Pilkington }
481aa385569SErik Pilkington return false;
482aa385569SErik Pilkington }
483aa385569SErik Pilkington
484314fbfa1STim Northover //===----------------------------------------------------------------------===//
485314fbfa1STim Northover // Methods on PrintfSpecifier.
486314fbfa1STim Northover //===----------------------------------------------------------------------===//
487314fbfa1STim Northover
getScalarArgType(ASTContext & Ctx,bool IsObjCLiteral) const4880ff50d49SMatt Arsenault ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
489314fbfa1STim Northover bool IsObjCLiteral) const {
490314fbfa1STim Northover if (CS.getKind() == ConversionSpecifier::cArg)
491314fbfa1STim Northover switch (LM.getKind()) {
492314fbfa1STim Northover case LengthModifier::None:
493314fbfa1STim Northover return Ctx.IntTy;
494314fbfa1STim Northover case LengthModifier::AsLong:
495314fbfa1STim Northover case LengthModifier::AsWide:
496314fbfa1STim Northover return ArgType(ArgType::WIntTy, "wint_t");
497314fbfa1STim Northover case LengthModifier::AsShort:
498314fbfa1STim Northover if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
499314fbfa1STim Northover return Ctx.IntTy;
500314fbfa1STim Northover LLVM_FALLTHROUGH;
501314fbfa1STim Northover default:
502314fbfa1STim Northover return ArgType::Invalid();
503314fbfa1STim Northover }
504314fbfa1STim Northover
505314fbfa1STim Northover if (CS.isIntArg())
506314fbfa1STim Northover switch (LM.getKind()) {
507314fbfa1STim Northover case LengthModifier::AsLongDouble:
508314fbfa1STim Northover // GNU extension.
509314fbfa1STim Northover return Ctx.LongLongTy;
510314fbfa1STim Northover case LengthModifier::None:
51158fc8082SMatt Arsenault case LengthModifier::AsShortLong:
512314fbfa1STim Northover return Ctx.IntTy;
513314fbfa1STim Northover case LengthModifier::AsInt32:
514314fbfa1STim Northover return ArgType(Ctx.IntTy, "__int32");
51558fc8082SMatt Arsenault case LengthModifier::AsChar:
51658fc8082SMatt Arsenault return ArgType::AnyCharTy;
517314fbfa1STim Northover case LengthModifier::AsShort: return Ctx.ShortTy;
518314fbfa1STim Northover case LengthModifier::AsLong: return Ctx.LongTy;
519314fbfa1STim Northover case LengthModifier::AsLongLong:
520314fbfa1STim Northover case LengthModifier::AsQuad:
521314fbfa1STim Northover return Ctx.LongLongTy;
522314fbfa1STim Northover case LengthModifier::AsInt64:
523314fbfa1STim Northover return ArgType(Ctx.LongLongTy, "__int64");
524314fbfa1STim Northover case LengthModifier::AsIntMax:
525314fbfa1STim Northover return ArgType(Ctx.getIntMaxType(), "intmax_t");
526314fbfa1STim Northover case LengthModifier::AsSizeT:
527314fbfa1STim Northover return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
528314fbfa1STim Northover case LengthModifier::AsInt3264:
529314fbfa1STim Northover return Ctx.getTargetInfo().getTriple().isArch64Bit()
530314fbfa1STim Northover ? ArgType(Ctx.LongLongTy, "__int64")
531314fbfa1STim Northover : ArgType(Ctx.IntTy, "__int32");
532314fbfa1STim Northover case LengthModifier::AsPtrDiff:
533314fbfa1STim Northover return ArgType::makePtrdiffT(
534314fbfa1STim Northover ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
535314fbfa1STim Northover case LengthModifier::AsAllocate:
536314fbfa1STim Northover case LengthModifier::AsMAllocate:
537314fbfa1STim Northover case LengthModifier::AsWide:
538314fbfa1STim Northover return ArgType::Invalid();
539314fbfa1STim Northover }
540314fbfa1STim Northover
541314fbfa1STim Northover if (CS.isUIntArg())
542314fbfa1STim Northover switch (LM.getKind()) {
543314fbfa1STim Northover case LengthModifier::AsLongDouble:
544314fbfa1STim Northover // GNU extension.
545314fbfa1STim Northover return Ctx.UnsignedLongLongTy;
546314fbfa1STim Northover case LengthModifier::None:
54758fc8082SMatt Arsenault case LengthModifier::AsShortLong:
548314fbfa1STim Northover return Ctx.UnsignedIntTy;
549314fbfa1STim Northover case LengthModifier::AsInt32:
550314fbfa1STim Northover return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
551314fbfa1STim Northover case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
552314fbfa1STim Northover case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
553314fbfa1STim Northover case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
554314fbfa1STim Northover case LengthModifier::AsLongLong:
555314fbfa1STim Northover case LengthModifier::AsQuad:
556314fbfa1STim Northover return Ctx.UnsignedLongLongTy;
557314fbfa1STim Northover case LengthModifier::AsInt64:
558314fbfa1STim Northover return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
559314fbfa1STim Northover case LengthModifier::AsIntMax:
560314fbfa1STim Northover return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
561314fbfa1STim Northover case LengthModifier::AsSizeT:
562314fbfa1STim Northover return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));
563314fbfa1STim Northover case LengthModifier::AsInt3264:
564314fbfa1STim Northover return Ctx.getTargetInfo().getTriple().isArch64Bit()
565314fbfa1STim Northover ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
566314fbfa1STim Northover : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
567314fbfa1STim Northover case LengthModifier::AsPtrDiff:
568314fbfa1STim Northover return ArgType::makePtrdiffT(
569314fbfa1STim Northover ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
570314fbfa1STim Northover case LengthModifier::AsAllocate:
571314fbfa1STim Northover case LengthModifier::AsMAllocate:
572314fbfa1STim Northover case LengthModifier::AsWide:
573314fbfa1STim Northover return ArgType::Invalid();
574314fbfa1STim Northover }
575314fbfa1STim Northover
576314fbfa1STim Northover if (CS.isDoubleArg()) {
57758fc8082SMatt Arsenault if (!VectorNumElts.isInvalid()) {
57858fc8082SMatt Arsenault switch (LM.getKind()) {
57958fc8082SMatt Arsenault case LengthModifier::AsShort:
58058fc8082SMatt Arsenault return Ctx.HalfTy;
58158fc8082SMatt Arsenault case LengthModifier::AsShortLong:
58258fc8082SMatt Arsenault return Ctx.FloatTy;
58358fc8082SMatt Arsenault case LengthModifier::AsLong:
58458fc8082SMatt Arsenault default:
58558fc8082SMatt Arsenault return Ctx.DoubleTy;
58658fc8082SMatt Arsenault }
58758fc8082SMatt Arsenault }
58858fc8082SMatt Arsenault
589314fbfa1STim Northover if (LM.getKind() == LengthModifier::AsLongDouble)
590314fbfa1STim Northover return Ctx.LongDoubleTy;
591314fbfa1STim Northover return Ctx.DoubleTy;
592314fbfa1STim Northover }
593314fbfa1STim Northover
594314fbfa1STim Northover if (CS.getKind() == ConversionSpecifier::nArg) {
595314fbfa1STim Northover switch (LM.getKind()) {
596314fbfa1STim Northover case LengthModifier::None:
597314fbfa1STim Northover return ArgType::PtrTo(Ctx.IntTy);
598314fbfa1STim Northover case LengthModifier::AsChar:
599314fbfa1STim Northover return ArgType::PtrTo(Ctx.SignedCharTy);
600314fbfa1STim Northover case LengthModifier::AsShort:
601314fbfa1STim Northover return ArgType::PtrTo(Ctx.ShortTy);
602314fbfa1STim Northover case LengthModifier::AsLong:
603314fbfa1STim Northover return ArgType::PtrTo(Ctx.LongTy);
604314fbfa1STim Northover case LengthModifier::AsLongLong:
605314fbfa1STim Northover case LengthModifier::AsQuad:
606314fbfa1STim Northover return ArgType::PtrTo(Ctx.LongLongTy);
607314fbfa1STim Northover case LengthModifier::AsIntMax:
608314fbfa1STim Northover return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
609314fbfa1STim Northover case LengthModifier::AsSizeT:
610314fbfa1STim Northover return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
611314fbfa1STim Northover case LengthModifier::AsPtrDiff:
612314fbfa1STim Northover return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
613314fbfa1STim Northover case LengthModifier::AsLongDouble:
614314fbfa1STim Northover return ArgType(); // FIXME: Is this a known extension?
615314fbfa1STim Northover case LengthModifier::AsAllocate:
616314fbfa1STim Northover case LengthModifier::AsMAllocate:
617314fbfa1STim Northover case LengthModifier::AsInt32:
618314fbfa1STim Northover case LengthModifier::AsInt3264:
619314fbfa1STim Northover case LengthModifier::AsInt64:
620314fbfa1STim Northover case LengthModifier::AsWide:
621314fbfa1STim Northover return ArgType::Invalid();
62258fc8082SMatt Arsenault case LengthModifier::AsShortLong:
62358fc8082SMatt Arsenault llvm_unreachable("only used for OpenCL which doesn not handle nArg");
624314fbfa1STim Northover }
625314fbfa1STim Northover }
626314fbfa1STim Northover
627314fbfa1STim Northover switch (CS.getKind()) {
628314fbfa1STim Northover case ConversionSpecifier::sArg:
629314fbfa1STim Northover if (LM.getKind() == LengthModifier::AsWideChar) {
630314fbfa1STim Northover if (IsObjCLiteral)
631314fbfa1STim Northover return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
632314fbfa1STim Northover "const unichar *");
633314fbfa1STim Northover return ArgType(ArgType::WCStrTy, "wchar_t *");
634314fbfa1STim Northover }
635314fbfa1STim Northover if (LM.getKind() == LengthModifier::AsWide)
636314fbfa1STim Northover return ArgType(ArgType::WCStrTy, "wchar_t *");
637314fbfa1STim Northover return ArgType::CStrTy;
638314fbfa1STim Northover case ConversionSpecifier::SArg:
639314fbfa1STim Northover if (IsObjCLiteral)
640314fbfa1STim Northover return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
641314fbfa1STim Northover "const unichar *");
642314fbfa1STim Northover if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
643314fbfa1STim Northover LM.getKind() == LengthModifier::AsShort)
644314fbfa1STim Northover return ArgType::CStrTy;
645314fbfa1STim Northover return ArgType(ArgType::WCStrTy, "wchar_t *");
646314fbfa1STim Northover case ConversionSpecifier::CArg:
647314fbfa1STim Northover if (IsObjCLiteral)
648314fbfa1STim Northover return ArgType(Ctx.UnsignedShortTy, "unichar");
649314fbfa1STim Northover if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
650314fbfa1STim Northover LM.getKind() == LengthModifier::AsShort)
651314fbfa1STim Northover return Ctx.IntTy;
652314fbfa1STim Northover return ArgType(Ctx.WideCharTy, "wchar_t");
653314fbfa1STim Northover case ConversionSpecifier::pArg:
654314fbfa1STim Northover case ConversionSpecifier::PArg:
655314fbfa1STim Northover return ArgType::CPointerTy;
656314fbfa1STim Northover case ConversionSpecifier::ObjCObjArg:
657314fbfa1STim Northover return ArgType::ObjCPointerTy;
658314fbfa1STim Northover default:
659314fbfa1STim Northover break;
660314fbfa1STim Northover }
661314fbfa1STim Northover
662314fbfa1STim Northover // FIXME: Handle other cases.
663314fbfa1STim Northover return ArgType();
664314fbfa1STim Northover }
665314fbfa1STim Northover
6660ff50d49SMatt Arsenault
getArgType(ASTContext & Ctx,bool IsObjCLiteral) const6670ff50d49SMatt Arsenault ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
6680ff50d49SMatt Arsenault bool IsObjCLiteral) const {
6690ff50d49SMatt Arsenault const PrintfConversionSpecifier &CS = getConversionSpecifier();
6700ff50d49SMatt Arsenault
6710ff50d49SMatt Arsenault if (!CS.consumesDataArgument())
6720ff50d49SMatt Arsenault return ArgType::Invalid();
6730ff50d49SMatt Arsenault
6740ff50d49SMatt Arsenault ArgType ScalarTy = getScalarArgType(Ctx, IsObjCLiteral);
6750ff50d49SMatt Arsenault if (!ScalarTy.isValid() || VectorNumElts.isInvalid())
6760ff50d49SMatt Arsenault return ScalarTy;
6770ff50d49SMatt Arsenault
6780ff50d49SMatt Arsenault return ScalarTy.makeVectorType(Ctx, VectorNumElts.getConstantAmount());
6790ff50d49SMatt Arsenault }
6800ff50d49SMatt Arsenault
fixType(QualType QT,const LangOptions & LangOpt,ASTContext & Ctx,bool IsObjCLiteral)681314fbfa1STim Northover bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
682314fbfa1STim Northover ASTContext &Ctx, bool IsObjCLiteral) {
683314fbfa1STim Northover // %n is different from other conversion specifiers; don't try to fix it.
684314fbfa1STim Northover if (CS.getKind() == ConversionSpecifier::nArg)
685314fbfa1STim Northover return false;
686314fbfa1STim Northover
687314fbfa1STim Northover // Handle Objective-C objects first. Note that while the '%@' specifier will
688314fbfa1STim Northover // not warn for structure pointer or void pointer arguments (because that's
689314fbfa1STim Northover // how CoreFoundation objects are implemented), we only show a fixit for '%@'
690314fbfa1STim Northover // if we know it's an object (block, id, class, or __attribute__((NSObject))).
691314fbfa1STim Northover if (QT->isObjCRetainableType()) {
692314fbfa1STim Northover if (!IsObjCLiteral)
693314fbfa1STim Northover return false;
694314fbfa1STim Northover
695314fbfa1STim Northover CS.setKind(ConversionSpecifier::ObjCObjArg);
696314fbfa1STim Northover
697314fbfa1STim Northover // Disable irrelevant flags
698314fbfa1STim Northover HasThousandsGrouping = false;
699314fbfa1STim Northover HasPlusPrefix = false;
700314fbfa1STim Northover HasSpacePrefix = false;
701314fbfa1STim Northover HasAlternativeForm = false;
702314fbfa1STim Northover HasLeadingZeroes = false;
703314fbfa1STim Northover Precision.setHowSpecified(OptionalAmount::NotSpecified);
704314fbfa1STim Northover LM.setKind(LengthModifier::None);
705314fbfa1STim Northover
706314fbfa1STim Northover return true;
707314fbfa1STim Northover }
708314fbfa1STim Northover
709314fbfa1STim Northover // Handle strings next (char *, wchar_t *)
710314fbfa1STim Northover if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
711314fbfa1STim Northover CS.setKind(ConversionSpecifier::sArg);
712314fbfa1STim Northover
713314fbfa1STim Northover // Disable irrelevant flags
71440446663SKazu Hirata HasAlternativeForm = false;
71540446663SKazu Hirata HasLeadingZeroes = false;
716314fbfa1STim Northover
717314fbfa1STim Northover // Set the long length modifier for wide characters
718314fbfa1STim Northover if (QT->getPointeeType()->isWideCharType())
719314fbfa1STim Northover LM.setKind(LengthModifier::AsWideChar);
720314fbfa1STim Northover else
721314fbfa1STim Northover LM.setKind(LengthModifier::None);
722314fbfa1STim Northover
723314fbfa1STim Northover return true;
724314fbfa1STim Northover }
725314fbfa1STim Northover
726314fbfa1STim Northover // If it's an enum, get its underlying type.
727314fbfa1STim Northover if (const EnumType *ETy = QT->getAs<EnumType>())
728314fbfa1STim Northover QT = ETy->getDecl()->getIntegerType();
729314fbfa1STim Northover
730314fbfa1STim Northover const BuiltinType *BT = QT->getAs<BuiltinType>();
7310ff50d49SMatt Arsenault if (!BT) {
7320ff50d49SMatt Arsenault const VectorType *VT = QT->getAs<VectorType>();
7330ff50d49SMatt Arsenault if (VT) {
7340ff50d49SMatt Arsenault QT = VT->getElementType();
7350ff50d49SMatt Arsenault BT = QT->getAs<BuiltinType>();
7360ff50d49SMatt Arsenault VectorNumElts = OptionalAmount(VT->getNumElements());
7370ff50d49SMatt Arsenault }
7380ff50d49SMatt Arsenault }
7390ff50d49SMatt Arsenault
7400ff50d49SMatt Arsenault // We can only work with builtin types.
741314fbfa1STim Northover if (!BT)
742314fbfa1STim Northover return false;
743314fbfa1STim Northover
744314fbfa1STim Northover // Set length modifier
745314fbfa1STim Northover switch (BT->getKind()) {
746314fbfa1STim Northover case BuiltinType::Bool:
747314fbfa1STim Northover case BuiltinType::WChar_U:
748314fbfa1STim Northover case BuiltinType::WChar_S:
749314fbfa1STim Northover case BuiltinType::Char8: // FIXME: Treat like 'char'?
750314fbfa1STim Northover case BuiltinType::Char16:
751314fbfa1STim Northover case BuiltinType::Char32:
752314fbfa1STim Northover case BuiltinType::UInt128:
753314fbfa1STim Northover case BuiltinType::Int128:
754314fbfa1STim Northover case BuiltinType::Half:
755ecd682bbSTies Stuij case BuiltinType::BFloat16:
756314fbfa1STim Northover case BuiltinType::Float16:
757314fbfa1STim Northover case BuiltinType::Float128:
758fae0dfa6SQiu Chaofan case BuiltinType::Ibm128:
759314fbfa1STim Northover case BuiltinType::ShortAccum:
760314fbfa1STim Northover case BuiltinType::Accum:
761314fbfa1STim Northover case BuiltinType::LongAccum:
762314fbfa1STim Northover case BuiltinType::UShortAccum:
763314fbfa1STim Northover case BuiltinType::UAccum:
764314fbfa1STim Northover case BuiltinType::ULongAccum:
765314fbfa1STim Northover case BuiltinType::ShortFract:
766314fbfa1STim Northover case BuiltinType::Fract:
767314fbfa1STim Northover case BuiltinType::LongFract:
768314fbfa1STim Northover case BuiltinType::UShortFract:
769314fbfa1STim Northover case BuiltinType::UFract:
770314fbfa1STim Northover case BuiltinType::ULongFract:
771314fbfa1STim Northover case BuiltinType::SatShortAccum:
772314fbfa1STim Northover case BuiltinType::SatAccum:
773314fbfa1STim Northover case BuiltinType::SatLongAccum:
774314fbfa1STim Northover case BuiltinType::SatUShortAccum:
775314fbfa1STim Northover case BuiltinType::SatUAccum:
776314fbfa1STim Northover case BuiltinType::SatULongAccum:
777314fbfa1STim Northover case BuiltinType::SatShortFract:
778314fbfa1STim Northover case BuiltinType::SatFract:
779314fbfa1STim Northover case BuiltinType::SatLongFract:
780314fbfa1STim Northover case BuiltinType::SatUShortFract:
781314fbfa1STim Northover case BuiltinType::SatUFract:
782314fbfa1STim Northover case BuiltinType::SatULongFract:
783314fbfa1STim Northover // Various types which are non-trivial to correct.
784314fbfa1STim Northover return false;
785314fbfa1STim Northover
786314fbfa1STim Northover #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
787314fbfa1STim Northover case BuiltinType::Id:
788314fbfa1STim Northover #include "clang/Basic/OpenCLImageTypes.def"
7893fee3518SAndrew Savonichev #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
7903fee3518SAndrew Savonichev case BuiltinType::Id:
7913fee3518SAndrew Savonichev #include "clang/Basic/OpenCLExtensionTypes.def"
792eb485fbcSRichard Sandiford #define SVE_TYPE(Name, Id, SingletonId) \
793eb485fbcSRichard Sandiford case BuiltinType::Id:
794eb485fbcSRichard Sandiford #include "clang/Basic/AArch64SVEACLETypes.def"
79557d83c3aSBaptiste Saleil #define PPC_VECTOR_TYPE(Name, Id, Size) \
79640dd4d52SBaptiste Saleil case BuiltinType::Id:
79740dd4d52SBaptiste Saleil #include "clang/Basic/PPCTypes.def"
798766ee109SHsiangkai Wang #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
799766ee109SHsiangkai Wang #include "clang/Basic/RISCVVTypes.def"
800314fbfa1STim Northover #define SIGNED_TYPE(Id, SingletonId)
801314fbfa1STim Northover #define UNSIGNED_TYPE(Id, SingletonId)
802314fbfa1STim Northover #define FLOATING_TYPE(Id, SingletonId)
803314fbfa1STim Northover #define BUILTIN_TYPE(Id, SingletonId) \
804314fbfa1STim Northover case BuiltinType::Id:
805314fbfa1STim Northover #include "clang/AST/BuiltinTypes.def"
806314fbfa1STim Northover // Misc other stuff which doesn't make sense here.
807314fbfa1STim Northover return false;
808314fbfa1STim Northover
809314fbfa1STim Northover case BuiltinType::UInt:
810314fbfa1STim Northover case BuiltinType::Int:
811314fbfa1STim Northover case BuiltinType::Float:
81258fc8082SMatt Arsenault LM.setKind(VectorNumElts.isInvalid() ?
81358fc8082SMatt Arsenault LengthModifier::None : LengthModifier::AsShortLong);
814314fbfa1STim Northover break;
81558fc8082SMatt Arsenault case BuiltinType::Double:
81658fc8082SMatt Arsenault LM.setKind(VectorNumElts.isInvalid() ?
81758fc8082SMatt Arsenault LengthModifier::None : LengthModifier::AsLong);
81858fc8082SMatt Arsenault break;
819314fbfa1STim Northover case BuiltinType::Char_U:
820314fbfa1STim Northover case BuiltinType::UChar:
821314fbfa1STim Northover case BuiltinType::Char_S:
822314fbfa1STim Northover case BuiltinType::SChar:
823314fbfa1STim Northover LM.setKind(LengthModifier::AsChar);
824314fbfa1STim Northover break;
825314fbfa1STim Northover
826314fbfa1STim Northover case BuiltinType::Short:
827314fbfa1STim Northover case BuiltinType::UShort:
828314fbfa1STim Northover LM.setKind(LengthModifier::AsShort);
829314fbfa1STim Northover break;
830314fbfa1STim Northover
831314fbfa1STim Northover case BuiltinType::Long:
832314fbfa1STim Northover case BuiltinType::ULong:
833314fbfa1STim Northover LM.setKind(LengthModifier::AsLong);
834314fbfa1STim Northover break;
835314fbfa1STim Northover
836314fbfa1STim Northover case BuiltinType::LongLong:
837314fbfa1STim Northover case BuiltinType::ULongLong:
838314fbfa1STim Northover LM.setKind(LengthModifier::AsLongLong);
839314fbfa1STim Northover break;
840314fbfa1STim Northover
841314fbfa1STim Northover case BuiltinType::LongDouble:
842314fbfa1STim Northover LM.setKind(LengthModifier::AsLongDouble);
843314fbfa1STim Northover break;
844314fbfa1STim Northover }
845314fbfa1STim Northover
846314fbfa1STim Northover // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
847*888673b6SJonas Devlieghere if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
848314fbfa1STim Northover namedTypeToLengthModifier(QT, LM);
849314fbfa1STim Northover
850314fbfa1STim Northover // If fixing the length modifier was enough, we might be done.
85158fc8082SMatt Arsenault if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
852314fbfa1STim Northover // If we're going to offer a fix anyway, make sure the sign matches.
853314fbfa1STim Northover switch (CS.getKind()) {
854314fbfa1STim Northover case ConversionSpecifier::uArg:
855314fbfa1STim Northover case ConversionSpecifier::UArg:
856314fbfa1STim Northover if (QT->isSignedIntegerType())
857314fbfa1STim Northover CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
858314fbfa1STim Northover break;
859314fbfa1STim Northover case ConversionSpecifier::dArg:
860314fbfa1STim Northover case ConversionSpecifier::DArg:
861314fbfa1STim Northover case ConversionSpecifier::iArg:
862314fbfa1STim Northover if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
863314fbfa1STim Northover CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
864314fbfa1STim Northover break;
865314fbfa1STim Northover default:
866314fbfa1STim Northover // Other specifiers do not have signed/unsigned variants.
867314fbfa1STim Northover break;
868314fbfa1STim Northover }
869314fbfa1STim Northover
870314fbfa1STim Northover const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
871314fbfa1STim Northover if (ATR.isValid() && ATR.matchesType(Ctx, QT))
872314fbfa1STim Northover return true;
873314fbfa1STim Northover }
874314fbfa1STim Northover
875314fbfa1STim Northover // Set conversion specifier and disable any flags which do not apply to it.
876314fbfa1STim Northover // Let typedefs to char fall through to int, as %c is silly for uint8_t.
877*888673b6SJonas Devlieghere if (!isa<TypedefType>(QT) && QT->isCharType()) {
878314fbfa1STim Northover CS.setKind(ConversionSpecifier::cArg);
879314fbfa1STim Northover LM.setKind(LengthModifier::None);
880314fbfa1STim Northover Precision.setHowSpecified(OptionalAmount::NotSpecified);
88140446663SKazu Hirata HasAlternativeForm = false;
88240446663SKazu Hirata HasLeadingZeroes = false;
88340446663SKazu Hirata HasPlusPrefix = false;
884314fbfa1STim Northover }
885314fbfa1STim Northover // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
886314fbfa1STim Northover else if (QT->isRealFloatingType()) {
887314fbfa1STim Northover CS.setKind(ConversionSpecifier::fArg);
888*888673b6SJonas Devlieghere }
889*888673b6SJonas Devlieghere else if (QT->isSignedIntegerType()) {
890314fbfa1STim Northover CS.setKind(ConversionSpecifier::dArg);
89140446663SKazu Hirata HasAlternativeForm = false;
892*888673b6SJonas Devlieghere }
893*888673b6SJonas Devlieghere else if (QT->isUnsignedIntegerType()) {
894314fbfa1STim Northover CS.setKind(ConversionSpecifier::uArg);
89540446663SKazu Hirata HasAlternativeForm = false;
89640446663SKazu Hirata HasPlusPrefix = false;
897314fbfa1STim Northover } else {
898314fbfa1STim Northover llvm_unreachable("Unexpected type");
899314fbfa1STim Northover }
900314fbfa1STim Northover
901314fbfa1STim Northover return true;
902314fbfa1STim Northover }
903314fbfa1STim Northover
toString(raw_ostream & os) const904314fbfa1STim Northover void PrintfSpecifier::toString(raw_ostream &os) const {
905314fbfa1STim Northover // Whilst some features have no defined order, we are using the order
906314fbfa1STim Northover // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
907314fbfa1STim Northover os << "%";
908314fbfa1STim Northover
909314fbfa1STim Northover // Positional args
910314fbfa1STim Northover if (usesPositionalArg()) {
911314fbfa1STim Northover os << getPositionalArgIndex() << "$";
912314fbfa1STim Northover }
913314fbfa1STim Northover
914314fbfa1STim Northover // Conversion flags
915314fbfa1STim Northover if (IsLeftJustified) os << "-";
916314fbfa1STim Northover if (HasPlusPrefix) os << "+";
917314fbfa1STim Northover if (HasSpacePrefix) os << " ";
918314fbfa1STim Northover if (HasAlternativeForm) os << "#";
919314fbfa1STim Northover if (HasLeadingZeroes) os << "0";
920314fbfa1STim Northover
921314fbfa1STim Northover // Minimum field width
922314fbfa1STim Northover FieldWidth.toString(os);
923314fbfa1STim Northover // Precision
924314fbfa1STim Northover Precision.toString(os);
9250ff50d49SMatt Arsenault
9260ff50d49SMatt Arsenault // Vector modifier
9270ff50d49SMatt Arsenault if (!VectorNumElts.isInvalid())
9280ff50d49SMatt Arsenault os << 'v' << VectorNumElts.getConstantAmount();
9290ff50d49SMatt Arsenault
930314fbfa1STim Northover // Length modifier
931314fbfa1STim Northover os << LM.toString();
932314fbfa1STim Northover // Conversion specifier
933314fbfa1STim Northover os << CS.toString();
934314fbfa1STim Northover }
935314fbfa1STim Northover
hasValidPlusPrefix() const936314fbfa1STim Northover bool PrintfSpecifier::hasValidPlusPrefix() const {
937314fbfa1STim Northover if (!HasPlusPrefix)
938314fbfa1STim Northover return true;
939314fbfa1STim Northover
940314fbfa1STim Northover // The plus prefix only makes sense for signed conversions
941314fbfa1STim Northover switch (CS.getKind()) {
942314fbfa1STim Northover case ConversionSpecifier::dArg:
943314fbfa1STim Northover case ConversionSpecifier::DArg:
944314fbfa1STim Northover case ConversionSpecifier::iArg:
945314fbfa1STim Northover case ConversionSpecifier::fArg:
946314fbfa1STim Northover case ConversionSpecifier::FArg:
947314fbfa1STim Northover case ConversionSpecifier::eArg:
948314fbfa1STim Northover case ConversionSpecifier::EArg:
949314fbfa1STim Northover case ConversionSpecifier::gArg:
950314fbfa1STim Northover case ConversionSpecifier::GArg:
951314fbfa1STim Northover case ConversionSpecifier::aArg:
952314fbfa1STim Northover case ConversionSpecifier::AArg:
953314fbfa1STim Northover case ConversionSpecifier::FreeBSDrArg:
954314fbfa1STim Northover case ConversionSpecifier::FreeBSDyArg:
955314fbfa1STim Northover return true;
956314fbfa1STim Northover
957314fbfa1STim Northover default:
958314fbfa1STim Northover return false;
959314fbfa1STim Northover }
960314fbfa1STim Northover }
961314fbfa1STim Northover
hasValidAlternativeForm() const962314fbfa1STim Northover bool PrintfSpecifier::hasValidAlternativeForm() const {
963314fbfa1STim Northover if (!HasAlternativeForm)
964314fbfa1STim Northover return true;
965314fbfa1STim Northover
966314fbfa1STim Northover // Alternate form flag only valid with the oxXaAeEfFgG conversions
967314fbfa1STim Northover switch (CS.getKind()) {
968314fbfa1STim Northover case ConversionSpecifier::oArg:
969314fbfa1STim Northover case ConversionSpecifier::OArg:
970314fbfa1STim Northover case ConversionSpecifier::xArg:
971314fbfa1STim Northover case ConversionSpecifier::XArg:
972314fbfa1STim Northover case ConversionSpecifier::aArg:
973314fbfa1STim Northover case ConversionSpecifier::AArg:
974314fbfa1STim Northover case ConversionSpecifier::eArg:
975314fbfa1STim Northover case ConversionSpecifier::EArg:
976314fbfa1STim Northover case ConversionSpecifier::fArg:
977314fbfa1STim Northover case ConversionSpecifier::FArg:
978314fbfa1STim Northover case ConversionSpecifier::gArg:
979314fbfa1STim Northover case ConversionSpecifier::GArg:
980314fbfa1STim Northover case ConversionSpecifier::FreeBSDrArg:
981314fbfa1STim Northover case ConversionSpecifier::FreeBSDyArg:
982314fbfa1STim Northover return true;
983314fbfa1STim Northover
984314fbfa1STim Northover default:
985314fbfa1STim Northover return false;
986314fbfa1STim Northover }
987314fbfa1STim Northover }
988314fbfa1STim Northover
hasValidLeadingZeros() const989314fbfa1STim Northover bool PrintfSpecifier::hasValidLeadingZeros() const {
990314fbfa1STim Northover if (!HasLeadingZeroes)
991314fbfa1STim Northover return true;
992314fbfa1STim Northover
993314fbfa1STim Northover // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
994314fbfa1STim Northover switch (CS.getKind()) {
995314fbfa1STim Northover case ConversionSpecifier::dArg:
996314fbfa1STim Northover case ConversionSpecifier::DArg:
997314fbfa1STim Northover case ConversionSpecifier::iArg:
998314fbfa1STim Northover case ConversionSpecifier::oArg:
999314fbfa1STim Northover case ConversionSpecifier::OArg:
1000314fbfa1STim Northover case ConversionSpecifier::uArg:
1001314fbfa1STim Northover case ConversionSpecifier::UArg:
1002314fbfa1STim Northover case ConversionSpecifier::xArg:
1003314fbfa1STim Northover case ConversionSpecifier::XArg:
1004314fbfa1STim Northover case ConversionSpecifier::aArg:
1005314fbfa1STim Northover case ConversionSpecifier::AArg:
1006314fbfa1STim Northover case ConversionSpecifier::eArg:
1007314fbfa1STim Northover case ConversionSpecifier::EArg:
1008314fbfa1STim Northover case ConversionSpecifier::fArg:
1009314fbfa1STim Northover case ConversionSpecifier::FArg:
1010314fbfa1STim Northover case ConversionSpecifier::gArg:
1011314fbfa1STim Northover case ConversionSpecifier::GArg:
1012314fbfa1STim Northover case ConversionSpecifier::FreeBSDrArg:
1013314fbfa1STim Northover case ConversionSpecifier::FreeBSDyArg:
1014314fbfa1STim Northover return true;
1015314fbfa1STim Northover
1016314fbfa1STim Northover default:
1017314fbfa1STim Northover return false;
1018314fbfa1STim Northover }
1019314fbfa1STim Northover }
1020314fbfa1STim Northover
hasValidSpacePrefix() const1021314fbfa1STim Northover bool PrintfSpecifier::hasValidSpacePrefix() const {
1022314fbfa1STim Northover if (!HasSpacePrefix)
1023314fbfa1STim Northover return true;
1024314fbfa1STim Northover
1025314fbfa1STim Northover // The space prefix only makes sense for signed conversions
1026314fbfa1STim Northover switch (CS.getKind()) {
1027314fbfa1STim Northover case ConversionSpecifier::dArg:
1028314fbfa1STim Northover case ConversionSpecifier::DArg:
1029314fbfa1STim Northover case ConversionSpecifier::iArg:
1030314fbfa1STim Northover case ConversionSpecifier::fArg:
1031314fbfa1STim Northover case ConversionSpecifier::FArg:
1032314fbfa1STim Northover case ConversionSpecifier::eArg:
1033314fbfa1STim Northover case ConversionSpecifier::EArg:
1034314fbfa1STim Northover case ConversionSpecifier::gArg:
1035314fbfa1STim Northover case ConversionSpecifier::GArg:
1036314fbfa1STim Northover case ConversionSpecifier::aArg:
1037314fbfa1STim Northover case ConversionSpecifier::AArg:
1038314fbfa1STim Northover case ConversionSpecifier::FreeBSDrArg:
1039314fbfa1STim Northover case ConversionSpecifier::FreeBSDyArg:
1040314fbfa1STim Northover return true;
1041314fbfa1STim Northover
1042314fbfa1STim Northover default:
1043314fbfa1STim Northover return false;
1044314fbfa1STim Northover }
1045314fbfa1STim Northover }
1046314fbfa1STim Northover
hasValidLeftJustified() const1047314fbfa1STim Northover bool PrintfSpecifier::hasValidLeftJustified() const {
1048314fbfa1STim Northover if (!IsLeftJustified)
1049314fbfa1STim Northover return true;
1050314fbfa1STim Northover
1051314fbfa1STim Northover // The left justified flag is valid for all conversions except n
1052314fbfa1STim Northover switch (CS.getKind()) {
1053314fbfa1STim Northover case ConversionSpecifier::nArg:
1054314fbfa1STim Northover return false;
1055314fbfa1STim Northover
1056314fbfa1STim Northover default:
1057314fbfa1STim Northover return true;
1058314fbfa1STim Northover }
1059314fbfa1STim Northover }
1060314fbfa1STim Northover
hasValidThousandsGroupingPrefix() const1061314fbfa1STim Northover bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
1062314fbfa1STim Northover if (!HasThousandsGrouping)
1063314fbfa1STim Northover return true;
1064314fbfa1STim Northover
1065314fbfa1STim Northover switch (CS.getKind()) {
1066314fbfa1STim Northover case ConversionSpecifier::dArg:
1067314fbfa1STim Northover case ConversionSpecifier::DArg:
1068314fbfa1STim Northover case ConversionSpecifier::iArg:
1069314fbfa1STim Northover case ConversionSpecifier::uArg:
1070314fbfa1STim Northover case ConversionSpecifier::UArg:
1071314fbfa1STim Northover case ConversionSpecifier::fArg:
1072314fbfa1STim Northover case ConversionSpecifier::FArg:
1073314fbfa1STim Northover case ConversionSpecifier::gArg:
1074314fbfa1STim Northover case ConversionSpecifier::GArg:
1075314fbfa1STim Northover return true;
1076314fbfa1STim Northover default:
1077314fbfa1STim Northover return false;
1078314fbfa1STim Northover }
1079314fbfa1STim Northover }
1080314fbfa1STim Northover
hasValidPrecision() const1081314fbfa1STim Northover bool PrintfSpecifier::hasValidPrecision() const {
1082314fbfa1STim Northover if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
1083314fbfa1STim Northover return true;
1084314fbfa1STim Northover
1085314fbfa1STim Northover // Precision is only valid with the diouxXaAeEfFgGsP conversions
1086314fbfa1STim Northover switch (CS.getKind()) {
1087314fbfa1STim Northover case ConversionSpecifier::dArg:
1088314fbfa1STim Northover case ConversionSpecifier::DArg:
1089314fbfa1STim Northover case ConversionSpecifier::iArg:
1090314fbfa1STim Northover case ConversionSpecifier::oArg:
1091314fbfa1STim Northover case ConversionSpecifier::OArg:
1092314fbfa1STim Northover case ConversionSpecifier::uArg:
1093314fbfa1STim Northover case ConversionSpecifier::UArg:
1094314fbfa1STim Northover case ConversionSpecifier::xArg:
1095314fbfa1STim Northover case ConversionSpecifier::XArg:
1096314fbfa1STim Northover case ConversionSpecifier::aArg:
1097314fbfa1STim Northover case ConversionSpecifier::AArg:
1098314fbfa1STim Northover case ConversionSpecifier::eArg:
1099314fbfa1STim Northover case ConversionSpecifier::EArg:
1100314fbfa1STim Northover case ConversionSpecifier::fArg:
1101314fbfa1STim Northover case ConversionSpecifier::FArg:
1102314fbfa1STim Northover case ConversionSpecifier::gArg:
1103314fbfa1STim Northover case ConversionSpecifier::GArg:
1104314fbfa1STim Northover case ConversionSpecifier::sArg:
1105314fbfa1STim Northover case ConversionSpecifier::FreeBSDrArg:
1106314fbfa1STim Northover case ConversionSpecifier::FreeBSDyArg:
1107314fbfa1STim Northover case ConversionSpecifier::PArg:
1108314fbfa1STim Northover return true;
1109314fbfa1STim Northover
1110314fbfa1STim Northover default:
1111314fbfa1STim Northover return false;
1112314fbfa1STim Northover }
1113314fbfa1STim Northover }
hasValidFieldWidth() const1114314fbfa1STim Northover bool PrintfSpecifier::hasValidFieldWidth() const {
1115314fbfa1STim Northover if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
1116314fbfa1STim Northover return true;
1117314fbfa1STim Northover
1118314fbfa1STim Northover // The field width is valid for all conversions except n
1119314fbfa1STim Northover switch (CS.getKind()) {
1120314fbfa1STim Northover case ConversionSpecifier::nArg:
1121314fbfa1STim Northover return false;
1122314fbfa1STim Northover
1123314fbfa1STim Northover default:
1124314fbfa1STim Northover return true;
1125314fbfa1STim Northover }
1126314fbfa1STim Northover }
1127