/src/llvm-project/clang/lib/AST/PrintfFormatString.cpp
Line | Count | Source (jump to first uncovered line) |
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" |
15 | | #include "clang/AST/FormatString.h" |
16 | | #include "clang/AST/OSLog.h" |
17 | | #include "clang/Basic/TargetInfo.h" |
18 | | #include "llvm/Support/Regex.h" |
19 | | |
20 | | using clang::analyze_format_string::ArgType; |
21 | | using clang::analyze_format_string::FormatStringHandler; |
22 | | using clang::analyze_format_string::LengthModifier; |
23 | | using clang::analyze_format_string::OptionalAmount; |
24 | | using clang::analyze_format_string::ConversionSpecifier; |
25 | | using clang::analyze_printf::PrintfSpecifier; |
26 | | |
27 | | using namespace clang; |
28 | | |
29 | | typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier> |
30 | | PrintfSpecifierResult; |
31 | | |
32 | | //===----------------------------------------------------------------------===// |
33 | | // Methods for parsing format strings. |
34 | | //===----------------------------------------------------------------------===// |
35 | | |
36 | | using analyze_format_string::ParseNonPositionAmount; |
37 | | |
38 | | static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, |
39 | | const char *Start, const char *&Beg, const char *E, |
40 | 0 | unsigned *argIndex) { |
41 | 0 | if (argIndex) { |
42 | 0 | FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex)); |
43 | 0 | } else { |
44 | 0 | const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, |
45 | 0 | analyze_format_string::PrecisionPos); |
46 | 0 | if (Amt.isInvalid()) |
47 | 0 | return true; |
48 | 0 | FS.setPrecision(Amt); |
49 | 0 | } |
50 | 0 | return false; |
51 | 0 | } |
52 | | |
53 | | static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS, |
54 | 0 | const char *FlagBeg, const char *E, bool Warn) { |
55 | 0 | StringRef Flag(FlagBeg, E - FlagBeg); |
56 | | // Currently there is only one flag. |
57 | 0 | if (Flag == "tt") { |
58 | 0 | FS.setHasObjCTechnicalTerm(FlagBeg); |
59 | 0 | return false; |
60 | 0 | } |
61 | | // Handle either the case of no flag or an invalid flag. |
62 | 0 | if (Warn) { |
63 | 0 | if (Flag == "") |
64 | 0 | H.HandleEmptyObjCModifierFlag(FlagBeg, E - FlagBeg); |
65 | 0 | else |
66 | 0 | H.HandleInvalidObjCModifierFlag(FlagBeg, E - FlagBeg); |
67 | 0 | } |
68 | 0 | return true; |
69 | 0 | } |
70 | | |
71 | | static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, |
72 | | const char *&Beg, |
73 | | const char *E, |
74 | | unsigned &argIndex, |
75 | | const LangOptions &LO, |
76 | | const TargetInfo &Target, |
77 | | bool Warn, |
78 | 0 | bool isFreeBSDKPrintf) { |
79 | |
|
80 | 0 | using namespace clang::analyze_format_string; |
81 | 0 | using namespace clang::analyze_printf; |
82 | |
|
83 | 0 | const char *I = Beg; |
84 | 0 | const char *Start = nullptr; |
85 | 0 | UpdateOnReturn <const char*> UpdateBeg(Beg, I); |
86 | | |
87 | | // Look for a '%' character that indicates the start of a format specifier. |
88 | 0 | for ( ; I != E ; ++I) { |
89 | 0 | char c = *I; |
90 | 0 | if (c == '\0') { |
91 | | // Detect spurious null characters, which are likely errors. |
92 | 0 | H.HandleNullChar(I); |
93 | 0 | return true; |
94 | 0 | } |
95 | 0 | if (c == '%') { |
96 | 0 | Start = I++; // Record the start of the format specifier. |
97 | 0 | break; |
98 | 0 | } |
99 | 0 | } |
100 | | |
101 | | // No format specifier found? |
102 | 0 | if (!Start) |
103 | 0 | return false; |
104 | | |
105 | 0 | if (I == E) { |
106 | | // No more characters left? |
107 | 0 | if (Warn) |
108 | 0 | H.HandleIncompleteSpecifier(Start, E - Start); |
109 | 0 | return true; |
110 | 0 | } |
111 | | |
112 | 0 | PrintfSpecifier FS; |
113 | 0 | if (ParseArgPosition(H, FS, Start, I, E)) |
114 | 0 | return true; |
115 | | |
116 | 0 | if (I == E) { |
117 | | // No more characters left? |
118 | 0 | if (Warn) |
119 | 0 | H.HandleIncompleteSpecifier(Start, E - Start); |
120 | 0 | return true; |
121 | 0 | } |
122 | | |
123 | 0 | if (*I == '{') { |
124 | 0 | ++I; |
125 | 0 | unsigned char PrivacyFlags = 0; |
126 | 0 | StringRef MatchedStr; |
127 | |
|
128 | 0 | do { |
129 | 0 | StringRef Str(I, E - I); |
130 | 0 | std::string Match = "^[[:space:]]*" |
131 | 0 | "(private|public|sensitive|mask\\.[^[:space:],}]*)" |
132 | 0 | "[[:space:]]*(,|})"; |
133 | 0 | llvm::Regex R(Match); |
134 | 0 | SmallVector<StringRef, 2> Matches; |
135 | |
|
136 | 0 | if (R.match(Str, &Matches)) { |
137 | 0 | MatchedStr = Matches[1]; |
138 | 0 | I += Matches[0].size(); |
139 | | |
140 | | // Set the privacy flag if the privacy annotation in the |
141 | | // comma-delimited segment is at least as strict as the privacy |
142 | | // annotations in previous comma-delimited segments. |
143 | 0 | if (MatchedStr.starts_with("mask")) { |
144 | 0 | StringRef MaskType = MatchedStr.substr(sizeof("mask.") - 1); |
145 | 0 | unsigned Size = MaskType.size(); |
146 | 0 | if (Warn && (Size == 0 || Size > 8)) |
147 | 0 | H.handleInvalidMaskType(MaskType); |
148 | 0 | FS.setMaskType(MaskType); |
149 | 0 | } else if (MatchedStr.equals("sensitive")) |
150 | 0 | PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsSensitive; |
151 | 0 | else if (PrivacyFlags != |
152 | 0 | clang::analyze_os_log::OSLogBufferItem::IsSensitive && |
153 | 0 | MatchedStr.equals("private")) |
154 | 0 | PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate; |
155 | 0 | else if (PrivacyFlags == 0 && MatchedStr.equals("public")) |
156 | 0 | PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic; |
157 | 0 | } else { |
158 | 0 | size_t CommaOrBracePos = |
159 | 0 | Str.find_if([](char c) { return c == ',' || c == '}'; }); |
160 | |
|
161 | 0 | if (CommaOrBracePos == StringRef::npos) { |
162 | | // Neither a comma nor the closing brace was found. |
163 | 0 | if (Warn) |
164 | 0 | H.HandleIncompleteSpecifier(Start, E - Start); |
165 | 0 | return true; |
166 | 0 | } |
167 | | |
168 | 0 | I += CommaOrBracePos + 1; |
169 | 0 | } |
170 | | // Continue until the closing brace is found. |
171 | 0 | } while (*(I - 1) == ','); |
172 | | |
173 | | // Set the privacy flag. |
174 | 0 | switch (PrivacyFlags) { |
175 | 0 | case 0: |
176 | 0 | break; |
177 | 0 | case clang::analyze_os_log::OSLogBufferItem::IsPrivate: |
178 | 0 | FS.setIsPrivate(MatchedStr.data()); |
179 | 0 | break; |
180 | 0 | case clang::analyze_os_log::OSLogBufferItem::IsPublic: |
181 | 0 | FS.setIsPublic(MatchedStr.data()); |
182 | 0 | break; |
183 | 0 | case clang::analyze_os_log::OSLogBufferItem::IsSensitive: |
184 | 0 | FS.setIsSensitive(MatchedStr.data()); |
185 | 0 | break; |
186 | 0 | default: |
187 | 0 | llvm_unreachable("Unexpected privacy flag value"); |
188 | 0 | } |
189 | 0 | } |
190 | | |
191 | | // Look for flags (if any). |
192 | 0 | bool hasMore = true; |
193 | 0 | for ( ; I != E; ++I) { |
194 | 0 | switch (*I) { |
195 | 0 | default: hasMore = false; break; |
196 | 0 | case '\'': |
197 | | // FIXME: POSIX specific. Always accept? |
198 | 0 | FS.setHasThousandsGrouping(I); |
199 | 0 | break; |
200 | 0 | case '-': FS.setIsLeftJustified(I); break; |
201 | 0 | case '+': FS.setHasPlusPrefix(I); break; |
202 | 0 | case ' ': FS.setHasSpacePrefix(I); break; |
203 | 0 | case '#': FS.setHasAlternativeForm(I); break; |
204 | 0 | case '0': FS.setHasLeadingZeros(I); break; |
205 | 0 | } |
206 | 0 | if (!hasMore) |
207 | 0 | break; |
208 | 0 | } |
209 | | |
210 | 0 | if (I == E) { |
211 | | // No more characters left? |
212 | 0 | if (Warn) |
213 | 0 | H.HandleIncompleteSpecifier(Start, E - Start); |
214 | 0 | return true; |
215 | 0 | } |
216 | | |
217 | | // Look for the field width (if any). |
218 | 0 | if (ParseFieldWidth(H, FS, Start, I, E, |
219 | 0 | FS.usesPositionalArg() ? nullptr : &argIndex)) |
220 | 0 | return true; |
221 | | |
222 | 0 | if (I == E) { |
223 | | // No more characters left? |
224 | 0 | if (Warn) |
225 | 0 | H.HandleIncompleteSpecifier(Start, E - Start); |
226 | 0 | return true; |
227 | 0 | } |
228 | | |
229 | | // Look for the precision (if any). |
230 | 0 | if (*I == '.') { |
231 | 0 | ++I; |
232 | 0 | if (I == E) { |
233 | 0 | if (Warn) |
234 | 0 | H.HandleIncompleteSpecifier(Start, E - Start); |
235 | 0 | return true; |
236 | 0 | } |
237 | | |
238 | 0 | if (ParsePrecision(H, FS, Start, I, E, |
239 | 0 | FS.usesPositionalArg() ? nullptr : &argIndex)) |
240 | 0 | return true; |
241 | | |
242 | 0 | if (I == E) { |
243 | | // No more characters left? |
244 | 0 | if (Warn) |
245 | 0 | H.HandleIncompleteSpecifier(Start, E - Start); |
246 | 0 | return true; |
247 | 0 | } |
248 | 0 | } |
249 | | |
250 | 0 | if (ParseVectorModifier(H, FS, I, E, LO)) |
251 | 0 | return true; |
252 | | |
253 | | // Look for the length modifier. |
254 | 0 | if (ParseLengthModifier(FS, I, E, LO) && I == E) { |
255 | | // No more characters left? |
256 | 0 | if (Warn) |
257 | 0 | H.HandleIncompleteSpecifier(Start, E - Start); |
258 | 0 | return true; |
259 | 0 | } |
260 | | |
261 | | // Look for the Objective-C modifier flags, if any. |
262 | | // We parse these here, even if they don't apply to |
263 | | // the conversion specifier, and then emit an error |
264 | | // later if the conversion specifier isn't '@'. This |
265 | | // enables better recovery, and we don't know if |
266 | | // these flags are applicable until later. |
267 | 0 | const char *ObjCModifierFlagsStart = nullptr, |
268 | 0 | *ObjCModifierFlagsEnd = nullptr; |
269 | 0 | if (*I == '[') { |
270 | 0 | ObjCModifierFlagsStart = I; |
271 | 0 | ++I; |
272 | 0 | auto flagStart = I; |
273 | 0 | for (;; ++I) { |
274 | 0 | ObjCModifierFlagsEnd = I; |
275 | 0 | if (I == E) { |
276 | 0 | if (Warn) |
277 | 0 | H.HandleIncompleteSpecifier(Start, E - Start); |
278 | 0 | return true; |
279 | 0 | } |
280 | | // Did we find the closing ']'? |
281 | 0 | if (*I == ']') { |
282 | 0 | if (ParseObjCFlags(H, FS, flagStart, I, Warn)) |
283 | 0 | return true; |
284 | 0 | ++I; |
285 | 0 | break; |
286 | 0 | } |
287 | | // There are no separators defined yet for multiple |
288 | | // Objective-C modifier flags. When those are |
289 | | // defined, this is the place to check. |
290 | 0 | } |
291 | 0 | } |
292 | | |
293 | 0 | if (*I == '\0') { |
294 | | // Detect spurious null characters, which are likely errors. |
295 | 0 | H.HandleNullChar(I); |
296 | 0 | return true; |
297 | 0 | } |
298 | | |
299 | | // Finally, look for the conversion specifier. |
300 | 0 | const char *conversionPosition = I++; |
301 | 0 | ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; |
302 | 0 | switch (*conversionPosition) { |
303 | 0 | default: |
304 | 0 | break; |
305 | | // C99: 7.19.6.1 (section 8). |
306 | 0 | case '%': k = ConversionSpecifier::PercentArg; break; |
307 | 0 | case 'A': k = ConversionSpecifier::AArg; break; |
308 | 0 | case 'E': k = ConversionSpecifier::EArg; break; |
309 | 0 | case 'F': k = ConversionSpecifier::FArg; break; |
310 | 0 | case 'G': k = ConversionSpecifier::GArg; break; |
311 | 0 | case 'X': k = ConversionSpecifier::XArg; break; |
312 | 0 | case 'a': k = ConversionSpecifier::aArg; break; |
313 | 0 | case 'c': k = ConversionSpecifier::cArg; break; |
314 | 0 | case 'd': k = ConversionSpecifier::dArg; break; |
315 | 0 | case 'e': k = ConversionSpecifier::eArg; break; |
316 | 0 | case 'f': k = ConversionSpecifier::fArg; break; |
317 | 0 | case 'g': k = ConversionSpecifier::gArg; break; |
318 | 0 | case 'i': k = ConversionSpecifier::iArg; break; |
319 | 0 | case 'n': |
320 | | // Not handled, but reserved in OpenCL. |
321 | 0 | if (!LO.OpenCL) |
322 | 0 | k = ConversionSpecifier::nArg; |
323 | 0 | break; |
324 | 0 | case 'o': k = ConversionSpecifier::oArg; break; |
325 | 0 | case 'p': k = ConversionSpecifier::pArg; break; |
326 | 0 | case 's': k = ConversionSpecifier::sArg; break; |
327 | 0 | case 'u': k = ConversionSpecifier::uArg; break; |
328 | 0 | case 'x': k = ConversionSpecifier::xArg; break; |
329 | | // C23. |
330 | 0 | case 'b': |
331 | 0 | if (isFreeBSDKPrintf) |
332 | 0 | k = ConversionSpecifier::FreeBSDbArg; // int followed by char * |
333 | 0 | else |
334 | 0 | k = ConversionSpecifier::bArg; |
335 | 0 | break; |
336 | 0 | case 'B': k = ConversionSpecifier::BArg; break; |
337 | | // POSIX specific. |
338 | 0 | case 'C': k = ConversionSpecifier::CArg; break; |
339 | 0 | case 'S': k = ConversionSpecifier::SArg; break; |
340 | | // Apple extension for os_log |
341 | 0 | case 'P': |
342 | 0 | k = ConversionSpecifier::PArg; |
343 | 0 | break; |
344 | | // Objective-C. |
345 | 0 | case '@': k = ConversionSpecifier::ObjCObjArg; break; |
346 | | // Glibc specific. |
347 | 0 | case 'm': k = ConversionSpecifier::PrintErrno; break; |
348 | 0 | case 'r': |
349 | 0 | if (isFreeBSDKPrintf) |
350 | 0 | k = ConversionSpecifier::FreeBSDrArg; // int |
351 | 0 | break; |
352 | 0 | case 'y': |
353 | 0 | if (isFreeBSDKPrintf) |
354 | 0 | k = ConversionSpecifier::FreeBSDyArg; // int |
355 | 0 | break; |
356 | | // Apple-specific. |
357 | 0 | case 'D': |
358 | 0 | if (isFreeBSDKPrintf) |
359 | 0 | k = ConversionSpecifier::FreeBSDDArg; // void * followed by char * |
360 | 0 | else if (Target.getTriple().isOSDarwin()) |
361 | 0 | k = ConversionSpecifier::DArg; |
362 | 0 | break; |
363 | 0 | case 'O': |
364 | 0 | if (Target.getTriple().isOSDarwin()) |
365 | 0 | k = ConversionSpecifier::OArg; |
366 | 0 | break; |
367 | 0 | case 'U': |
368 | 0 | if (Target.getTriple().isOSDarwin()) |
369 | 0 | k = ConversionSpecifier::UArg; |
370 | 0 | break; |
371 | | // MS specific. |
372 | 0 | case 'Z': |
373 | 0 | if (Target.getTriple().isOSMSVCRT()) |
374 | 0 | k = ConversionSpecifier::ZArg; |
375 | 0 | break; |
376 | 0 | } |
377 | | |
378 | | // Check to see if we used the Objective-C modifier flags with |
379 | | // a conversion specifier other than '@'. |
380 | 0 | if (k != ConversionSpecifier::ObjCObjArg && |
381 | 0 | k != ConversionSpecifier::InvalidSpecifier && |
382 | 0 | ObjCModifierFlagsStart) { |
383 | 0 | H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart, |
384 | 0 | ObjCModifierFlagsEnd + 1, |
385 | 0 | conversionPosition); |
386 | 0 | return true; |
387 | 0 | } |
388 | | |
389 | 0 | PrintfConversionSpecifier CS(conversionPosition, k); |
390 | 0 | FS.setConversionSpecifier(CS); |
391 | 0 | if (CS.consumesDataArgument() && !FS.usesPositionalArg()) |
392 | 0 | FS.setArgIndex(argIndex++); |
393 | | // FreeBSD kernel specific. |
394 | 0 | if (k == ConversionSpecifier::FreeBSDbArg || |
395 | 0 | k == ConversionSpecifier::FreeBSDDArg) |
396 | 0 | argIndex++; |
397 | |
|
398 | 0 | if (k == ConversionSpecifier::InvalidSpecifier) { |
399 | 0 | unsigned Len = I - Start; |
400 | 0 | if (ParseUTF8InvalidSpecifier(Start, E, Len)) { |
401 | 0 | CS.setEndScanList(Start + Len); |
402 | 0 | FS.setConversionSpecifier(CS); |
403 | 0 | } |
404 | | // Assume the conversion takes one argument. |
405 | 0 | return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len); |
406 | 0 | } |
407 | 0 | return PrintfSpecifierResult(Start, FS); |
408 | 0 | } |
409 | | |
410 | | bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, |
411 | | const char *I, |
412 | | const char *E, |
413 | | const LangOptions &LO, |
414 | | const TargetInfo &Target, |
415 | 0 | bool isFreeBSDKPrintf) { |
416 | |
|
417 | 0 | unsigned argIndex = 0; |
418 | | |
419 | | // Keep looking for a format specifier until we have exhausted the string. |
420 | 0 | while (I != E) { |
421 | 0 | const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, |
422 | 0 | LO, Target, true, |
423 | 0 | isFreeBSDKPrintf); |
424 | | // Did a fail-stop error of any kind occur when parsing the specifier? |
425 | | // If so, don't do any more processing. |
426 | 0 | if (FSR.shouldStop()) |
427 | 0 | return true; |
428 | | // Did we exhaust the string or encounter an error that |
429 | | // we can recover from? |
430 | 0 | if (!FSR.hasValue()) |
431 | 0 | continue; |
432 | | // We have a format specifier. Pass it to the callback. |
433 | 0 | if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(), |
434 | 0 | I - FSR.getStart(), Target)) |
435 | 0 | return true; |
436 | 0 | } |
437 | 0 | assert(I == E && "Format string not exhausted"); |
438 | 0 | return false; |
439 | 0 | } |
440 | | |
441 | | bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I, |
442 | | const char *E, |
443 | | const LangOptions &LO, |
444 | 0 | const TargetInfo &Target) { |
445 | |
|
446 | 0 | unsigned argIndex = 0; |
447 | | |
448 | | // Keep looking for a %s format specifier until we have exhausted the string. |
449 | 0 | FormatStringHandler H; |
450 | 0 | while (I != E) { |
451 | 0 | const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, |
452 | 0 | LO, Target, false, |
453 | 0 | false); |
454 | | // Did a fail-stop error of any kind occur when parsing the specifier? |
455 | | // If so, don't do any more processing. |
456 | 0 | if (FSR.shouldStop()) |
457 | 0 | return false; |
458 | | // Did we exhaust the string or encounter an error that |
459 | | // we can recover from? |
460 | 0 | if (!FSR.hasValue()) |
461 | 0 | continue; |
462 | 0 | const analyze_printf::PrintfSpecifier &FS = FSR.getValue(); |
463 | | // Return true if this a %s format specifier. |
464 | 0 | if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg) |
465 | 0 | return true; |
466 | 0 | } |
467 | 0 | return false; |
468 | 0 | } |
469 | | |
470 | | bool clang::analyze_format_string::parseFormatStringHasFormattingSpecifiers( |
471 | | const char *Begin, const char *End, const LangOptions &LO, |
472 | 0 | const TargetInfo &Target) { |
473 | 0 | unsigned ArgIndex = 0; |
474 | | // Keep looking for a formatting specifier until we have exhausted the string. |
475 | 0 | FormatStringHandler H; |
476 | 0 | while (Begin != End) { |
477 | 0 | const PrintfSpecifierResult &FSR = |
478 | 0 | ParsePrintfSpecifier(H, Begin, End, ArgIndex, LO, Target, false, false); |
479 | 0 | if (FSR.shouldStop()) |
480 | 0 | break; |
481 | 0 | if (FSR.hasValue()) |
482 | 0 | return true; |
483 | 0 | } |
484 | 0 | return false; |
485 | 0 | } |
486 | | |
487 | | //===----------------------------------------------------------------------===// |
488 | | // Methods on PrintfSpecifier. |
489 | | //===----------------------------------------------------------------------===// |
490 | | |
491 | | ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, |
492 | 0 | bool IsObjCLiteral) const { |
493 | 0 | if (CS.getKind() == ConversionSpecifier::cArg) |
494 | 0 | switch (LM.getKind()) { |
495 | 0 | case LengthModifier::None: |
496 | 0 | return Ctx.IntTy; |
497 | 0 | case LengthModifier::AsLong: |
498 | 0 | case LengthModifier::AsWide: |
499 | 0 | return ArgType(ArgType::WIntTy, "wint_t"); |
500 | 0 | case LengthModifier::AsShort: |
501 | 0 | if (Ctx.getTargetInfo().getTriple().isOSMSVCRT()) |
502 | 0 | return Ctx.IntTy; |
503 | 0 | [[fallthrough]]; |
504 | 0 | default: |
505 | 0 | return ArgType::Invalid(); |
506 | 0 | } |
507 | | |
508 | 0 | if (CS.isIntArg()) |
509 | 0 | switch (LM.getKind()) { |
510 | 0 | case LengthModifier::AsLongDouble: |
511 | | // GNU extension. |
512 | 0 | return Ctx.LongLongTy; |
513 | 0 | case LengthModifier::None: |
514 | 0 | case LengthModifier::AsShortLong: |
515 | 0 | return Ctx.IntTy; |
516 | 0 | case LengthModifier::AsInt32: |
517 | 0 | return ArgType(Ctx.IntTy, "__int32"); |
518 | 0 | case LengthModifier::AsChar: |
519 | 0 | return ArgType::AnyCharTy; |
520 | 0 | case LengthModifier::AsShort: return Ctx.ShortTy; |
521 | 0 | case LengthModifier::AsLong: return Ctx.LongTy; |
522 | 0 | case LengthModifier::AsLongLong: |
523 | 0 | case LengthModifier::AsQuad: |
524 | 0 | return Ctx.LongLongTy; |
525 | 0 | case LengthModifier::AsInt64: |
526 | 0 | return ArgType(Ctx.LongLongTy, "__int64"); |
527 | 0 | case LengthModifier::AsIntMax: |
528 | 0 | return ArgType(Ctx.getIntMaxType(), "intmax_t"); |
529 | 0 | case LengthModifier::AsSizeT: |
530 | 0 | return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(), "ssize_t")); |
531 | 0 | case LengthModifier::AsInt3264: |
532 | 0 | return Ctx.getTargetInfo().getTriple().isArch64Bit() |
533 | 0 | ? ArgType(Ctx.LongLongTy, "__int64") |
534 | 0 | : ArgType(Ctx.IntTy, "__int32"); |
535 | 0 | case LengthModifier::AsPtrDiff: |
536 | 0 | return ArgType::makePtrdiffT( |
537 | 0 | ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); |
538 | 0 | case LengthModifier::AsAllocate: |
539 | 0 | case LengthModifier::AsMAllocate: |
540 | 0 | case LengthModifier::AsWide: |
541 | 0 | return ArgType::Invalid(); |
542 | 0 | } |
543 | | |
544 | 0 | if (CS.isUIntArg()) |
545 | 0 | switch (LM.getKind()) { |
546 | 0 | case LengthModifier::AsLongDouble: |
547 | | // GNU extension. |
548 | 0 | return Ctx.UnsignedLongLongTy; |
549 | 0 | case LengthModifier::None: |
550 | 0 | case LengthModifier::AsShortLong: |
551 | 0 | return Ctx.UnsignedIntTy; |
552 | 0 | case LengthModifier::AsInt32: |
553 | 0 | return ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); |
554 | 0 | case LengthModifier::AsChar: return Ctx.UnsignedCharTy; |
555 | 0 | case LengthModifier::AsShort: return Ctx.UnsignedShortTy; |
556 | 0 | case LengthModifier::AsLong: return Ctx.UnsignedLongTy; |
557 | 0 | case LengthModifier::AsLongLong: |
558 | 0 | case LengthModifier::AsQuad: |
559 | 0 | return Ctx.UnsignedLongLongTy; |
560 | 0 | case LengthModifier::AsInt64: |
561 | 0 | return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"); |
562 | 0 | case LengthModifier::AsIntMax: |
563 | 0 | return ArgType(Ctx.getUIntMaxType(), "uintmax_t"); |
564 | 0 | case LengthModifier::AsSizeT: |
565 | 0 | return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t")); |
566 | 0 | case LengthModifier::AsInt3264: |
567 | 0 | return Ctx.getTargetInfo().getTriple().isArch64Bit() |
568 | 0 | ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64") |
569 | 0 | : ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); |
570 | 0 | case LengthModifier::AsPtrDiff: |
571 | 0 | return ArgType::makePtrdiffT( |
572 | 0 | ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t")); |
573 | 0 | case LengthModifier::AsAllocate: |
574 | 0 | case LengthModifier::AsMAllocate: |
575 | 0 | case LengthModifier::AsWide: |
576 | 0 | return ArgType::Invalid(); |
577 | 0 | } |
578 | | |
579 | 0 | if (CS.isDoubleArg()) { |
580 | 0 | if (!VectorNumElts.isInvalid()) { |
581 | 0 | switch (LM.getKind()) { |
582 | 0 | case LengthModifier::AsShort: |
583 | 0 | return Ctx.HalfTy; |
584 | 0 | case LengthModifier::AsShortLong: |
585 | 0 | return Ctx.FloatTy; |
586 | 0 | case LengthModifier::AsLong: |
587 | 0 | default: |
588 | 0 | return Ctx.DoubleTy; |
589 | 0 | } |
590 | 0 | } |
591 | | |
592 | 0 | if (LM.getKind() == LengthModifier::AsLongDouble) |
593 | 0 | return Ctx.LongDoubleTy; |
594 | 0 | return Ctx.DoubleTy; |
595 | 0 | } |
596 | | |
597 | 0 | if (CS.getKind() == ConversionSpecifier::nArg) { |
598 | 0 | switch (LM.getKind()) { |
599 | 0 | case LengthModifier::None: |
600 | 0 | return ArgType::PtrTo(Ctx.IntTy); |
601 | 0 | case LengthModifier::AsChar: |
602 | 0 | return ArgType::PtrTo(Ctx.SignedCharTy); |
603 | 0 | case LengthModifier::AsShort: |
604 | 0 | return ArgType::PtrTo(Ctx.ShortTy); |
605 | 0 | case LengthModifier::AsLong: |
606 | 0 | return ArgType::PtrTo(Ctx.LongTy); |
607 | 0 | case LengthModifier::AsLongLong: |
608 | 0 | case LengthModifier::AsQuad: |
609 | 0 | return ArgType::PtrTo(Ctx.LongLongTy); |
610 | 0 | case LengthModifier::AsIntMax: |
611 | 0 | return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); |
612 | 0 | case LengthModifier::AsSizeT: |
613 | 0 | return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t")); |
614 | 0 | case LengthModifier::AsPtrDiff: |
615 | 0 | return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); |
616 | 0 | case LengthModifier::AsLongDouble: |
617 | 0 | return ArgType(); // FIXME: Is this a known extension? |
618 | 0 | case LengthModifier::AsAllocate: |
619 | 0 | case LengthModifier::AsMAllocate: |
620 | 0 | case LengthModifier::AsInt32: |
621 | 0 | case LengthModifier::AsInt3264: |
622 | 0 | case LengthModifier::AsInt64: |
623 | 0 | case LengthModifier::AsWide: |
624 | 0 | return ArgType::Invalid(); |
625 | 0 | case LengthModifier::AsShortLong: |
626 | 0 | llvm_unreachable("only used for OpenCL which doesn not handle nArg"); |
627 | 0 | } |
628 | 0 | } |
629 | | |
630 | 0 | switch (CS.getKind()) { |
631 | 0 | case ConversionSpecifier::sArg: |
632 | 0 | if (LM.getKind() == LengthModifier::AsWideChar) { |
633 | 0 | if (IsObjCLiteral) |
634 | 0 | return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), |
635 | 0 | "const unichar *"); |
636 | 0 | return ArgType(ArgType::WCStrTy, "wchar_t *"); |
637 | 0 | } |
638 | 0 | if (LM.getKind() == LengthModifier::AsWide) |
639 | 0 | return ArgType(ArgType::WCStrTy, "wchar_t *"); |
640 | 0 | return ArgType::CStrTy; |
641 | 0 | case ConversionSpecifier::SArg: |
642 | 0 | if (IsObjCLiteral) |
643 | 0 | return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), |
644 | 0 | "const unichar *"); |
645 | 0 | if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() && |
646 | 0 | LM.getKind() == LengthModifier::AsShort) |
647 | 0 | return ArgType::CStrTy; |
648 | 0 | return ArgType(ArgType::WCStrTy, "wchar_t *"); |
649 | 0 | case ConversionSpecifier::CArg: |
650 | 0 | if (IsObjCLiteral) |
651 | 0 | return ArgType(Ctx.UnsignedShortTy, "unichar"); |
652 | 0 | if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() && |
653 | 0 | LM.getKind() == LengthModifier::AsShort) |
654 | 0 | return Ctx.IntTy; |
655 | 0 | return ArgType(Ctx.WideCharTy, "wchar_t"); |
656 | 0 | case ConversionSpecifier::pArg: |
657 | 0 | case ConversionSpecifier::PArg: |
658 | 0 | return ArgType::CPointerTy; |
659 | 0 | case ConversionSpecifier::ObjCObjArg: |
660 | 0 | return ArgType::ObjCPointerTy; |
661 | 0 | default: |
662 | 0 | break; |
663 | 0 | } |
664 | | |
665 | | // FIXME: Handle other cases. |
666 | 0 | return ArgType(); |
667 | 0 | } |
668 | | |
669 | | |
670 | | ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, |
671 | 0 | bool IsObjCLiteral) const { |
672 | 0 | const PrintfConversionSpecifier &CS = getConversionSpecifier(); |
673 | |
|
674 | 0 | if (!CS.consumesDataArgument()) |
675 | 0 | return ArgType::Invalid(); |
676 | | |
677 | 0 | ArgType ScalarTy = getScalarArgType(Ctx, IsObjCLiteral); |
678 | 0 | if (!ScalarTy.isValid() || VectorNumElts.isInvalid()) |
679 | 0 | return ScalarTy; |
680 | | |
681 | 0 | return ScalarTy.makeVectorType(Ctx, VectorNumElts.getConstantAmount()); |
682 | 0 | } |
683 | | |
684 | | bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, |
685 | 0 | ASTContext &Ctx, bool IsObjCLiteral) { |
686 | | // %n is different from other conversion specifiers; don't try to fix it. |
687 | 0 | if (CS.getKind() == ConversionSpecifier::nArg) |
688 | 0 | return false; |
689 | | |
690 | | // Handle Objective-C objects first. Note that while the '%@' specifier will |
691 | | // not warn for structure pointer or void pointer arguments (because that's |
692 | | // how CoreFoundation objects are implemented), we only show a fixit for '%@' |
693 | | // if we know it's an object (block, id, class, or __attribute__((NSObject))). |
694 | 0 | if (QT->isObjCRetainableType()) { |
695 | 0 | if (!IsObjCLiteral) |
696 | 0 | return false; |
697 | | |
698 | 0 | CS.setKind(ConversionSpecifier::ObjCObjArg); |
699 | | |
700 | | // Disable irrelevant flags |
701 | 0 | HasThousandsGrouping = false; |
702 | 0 | HasPlusPrefix = false; |
703 | 0 | HasSpacePrefix = false; |
704 | 0 | HasAlternativeForm = false; |
705 | 0 | HasLeadingZeroes = false; |
706 | 0 | Precision.setHowSpecified(OptionalAmount::NotSpecified); |
707 | 0 | LM.setKind(LengthModifier::None); |
708 | |
|
709 | 0 | return true; |
710 | 0 | } |
711 | | |
712 | | // Handle strings next (char *, wchar_t *) |
713 | 0 | if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { |
714 | 0 | CS.setKind(ConversionSpecifier::sArg); |
715 | | |
716 | | // Disable irrelevant flags |
717 | 0 | HasAlternativeForm = false; |
718 | 0 | HasLeadingZeroes = false; |
719 | | |
720 | | // Set the long length modifier for wide characters |
721 | 0 | if (QT->getPointeeType()->isWideCharType()) |
722 | 0 | LM.setKind(LengthModifier::AsWideChar); |
723 | 0 | else |
724 | 0 | LM.setKind(LengthModifier::None); |
725 | |
|
726 | 0 | return true; |
727 | 0 | } |
728 | | |
729 | | // If it's an enum, get its underlying type. |
730 | 0 | if (const EnumType *ETy = QT->getAs<EnumType>()) |
731 | 0 | QT = ETy->getDecl()->getIntegerType(); |
732 | |
|
733 | 0 | const BuiltinType *BT = QT->getAs<BuiltinType>(); |
734 | 0 | if (!BT) { |
735 | 0 | const VectorType *VT = QT->getAs<VectorType>(); |
736 | 0 | if (VT) { |
737 | 0 | QT = VT->getElementType(); |
738 | 0 | BT = QT->getAs<BuiltinType>(); |
739 | 0 | VectorNumElts = OptionalAmount(VT->getNumElements()); |
740 | 0 | } |
741 | 0 | } |
742 | | |
743 | | // We can only work with builtin types. |
744 | 0 | if (!BT) |
745 | 0 | return false; |
746 | | |
747 | | // Set length modifier |
748 | 0 | switch (BT->getKind()) { |
749 | 0 | case BuiltinType::Bool: |
750 | 0 | case BuiltinType::WChar_U: |
751 | 0 | case BuiltinType::WChar_S: |
752 | 0 | case BuiltinType::Char8: // FIXME: Treat like 'char'? |
753 | 0 | case BuiltinType::Char16: |
754 | 0 | case BuiltinType::Char32: |
755 | 0 | case BuiltinType::UInt128: |
756 | 0 | case BuiltinType::Int128: |
757 | 0 | case BuiltinType::Half: |
758 | 0 | case BuiltinType::BFloat16: |
759 | 0 | case BuiltinType::Float16: |
760 | 0 | case BuiltinType::Float128: |
761 | 0 | case BuiltinType::Ibm128: |
762 | 0 | case BuiltinType::ShortAccum: |
763 | 0 | case BuiltinType::Accum: |
764 | 0 | case BuiltinType::LongAccum: |
765 | 0 | case BuiltinType::UShortAccum: |
766 | 0 | case BuiltinType::UAccum: |
767 | 0 | case BuiltinType::ULongAccum: |
768 | 0 | case BuiltinType::ShortFract: |
769 | 0 | case BuiltinType::Fract: |
770 | 0 | case BuiltinType::LongFract: |
771 | 0 | case BuiltinType::UShortFract: |
772 | 0 | case BuiltinType::UFract: |
773 | 0 | case BuiltinType::ULongFract: |
774 | 0 | case BuiltinType::SatShortAccum: |
775 | 0 | case BuiltinType::SatAccum: |
776 | 0 | case BuiltinType::SatLongAccum: |
777 | 0 | case BuiltinType::SatUShortAccum: |
778 | 0 | case BuiltinType::SatUAccum: |
779 | 0 | case BuiltinType::SatULongAccum: |
780 | 0 | case BuiltinType::SatShortFract: |
781 | 0 | case BuiltinType::SatFract: |
782 | 0 | case BuiltinType::SatLongFract: |
783 | 0 | case BuiltinType::SatUShortFract: |
784 | 0 | case BuiltinType::SatUFract: |
785 | 0 | case BuiltinType::SatULongFract: |
786 | | // Various types which are non-trivial to correct. |
787 | 0 | return false; |
788 | | |
789 | 0 | #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ |
790 | 0 | case BuiltinType::Id: |
791 | 0 | #include "clang/Basic/OpenCLImageTypes.def" |
792 | 0 | #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ |
793 | 0 | case BuiltinType::Id: |
794 | 0 | #include "clang/Basic/OpenCLExtensionTypes.def" |
795 | 0 | #define SVE_TYPE(Name, Id, SingletonId) \ |
796 | 0 | case BuiltinType::Id: |
797 | 0 | #include "clang/Basic/AArch64SVEACLETypes.def" |
798 | 0 | #define PPC_VECTOR_TYPE(Name, Id, Size) \ |
799 | 0 | case BuiltinType::Id: |
800 | 0 | #include "clang/Basic/PPCTypes.def" |
801 | 0 | #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: |
802 | 0 | #include "clang/Basic/RISCVVTypes.def" |
803 | 0 | #define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id: |
804 | 0 | #include "clang/Basic/WebAssemblyReferenceTypes.def" |
805 | 0 | #define SIGNED_TYPE(Id, SingletonId) |
806 | 0 | #define UNSIGNED_TYPE(Id, SingletonId) |
807 | 0 | #define FLOATING_TYPE(Id, SingletonId) |
808 | 0 | #define BUILTIN_TYPE(Id, SingletonId) \ |
809 | 0 | case BuiltinType::Id: |
810 | 0 | #include "clang/AST/BuiltinTypes.def" |
811 | | // Misc other stuff which doesn't make sense here. |
812 | 0 | return false; |
813 | | |
814 | 0 | case BuiltinType::UInt: |
815 | 0 | case BuiltinType::Int: |
816 | 0 | case BuiltinType::Float: |
817 | 0 | LM.setKind(VectorNumElts.isInvalid() ? |
818 | 0 | LengthModifier::None : LengthModifier::AsShortLong); |
819 | 0 | break; |
820 | 0 | case BuiltinType::Double: |
821 | 0 | LM.setKind(VectorNumElts.isInvalid() ? |
822 | 0 | LengthModifier::None : LengthModifier::AsLong); |
823 | 0 | break; |
824 | 0 | case BuiltinType::Char_U: |
825 | 0 | case BuiltinType::UChar: |
826 | 0 | case BuiltinType::Char_S: |
827 | 0 | case BuiltinType::SChar: |
828 | 0 | LM.setKind(LengthModifier::AsChar); |
829 | 0 | break; |
830 | | |
831 | 0 | case BuiltinType::Short: |
832 | 0 | case BuiltinType::UShort: |
833 | 0 | LM.setKind(LengthModifier::AsShort); |
834 | 0 | break; |
835 | | |
836 | 0 | case BuiltinType::Long: |
837 | 0 | case BuiltinType::ULong: |
838 | 0 | LM.setKind(LengthModifier::AsLong); |
839 | 0 | break; |
840 | | |
841 | 0 | case BuiltinType::LongLong: |
842 | 0 | case BuiltinType::ULongLong: |
843 | 0 | LM.setKind(LengthModifier::AsLongLong); |
844 | 0 | break; |
845 | | |
846 | 0 | case BuiltinType::LongDouble: |
847 | 0 | LM.setKind(LengthModifier::AsLongDouble); |
848 | 0 | break; |
849 | 0 | } |
850 | | |
851 | | // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. |
852 | 0 | if (LangOpt.C99 || LangOpt.CPlusPlus11) |
853 | 0 | namedTypeToLengthModifier(QT, LM); |
854 | | |
855 | | // If fixing the length modifier was enough, we might be done. |
856 | 0 | if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) { |
857 | | // If we're going to offer a fix anyway, make sure the sign matches. |
858 | 0 | switch (CS.getKind()) { |
859 | 0 | case ConversionSpecifier::uArg: |
860 | 0 | case ConversionSpecifier::UArg: |
861 | 0 | if (QT->isSignedIntegerType()) |
862 | 0 | CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg); |
863 | 0 | break; |
864 | 0 | case ConversionSpecifier::dArg: |
865 | 0 | case ConversionSpecifier::DArg: |
866 | 0 | case ConversionSpecifier::iArg: |
867 | 0 | if (QT->isUnsignedIntegerType() && !HasPlusPrefix) |
868 | 0 | CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg); |
869 | 0 | break; |
870 | 0 | default: |
871 | | // Other specifiers do not have signed/unsigned variants. |
872 | 0 | break; |
873 | 0 | } |
874 | | |
875 | 0 | const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral); |
876 | 0 | if (ATR.isValid() && ATR.matchesType(Ctx, QT)) |
877 | 0 | return true; |
878 | 0 | } |
879 | | |
880 | | // Set conversion specifier and disable any flags which do not apply to it. |
881 | | // Let typedefs to char fall through to int, as %c is silly for uint8_t. |
882 | 0 | if (!QT->getAs<TypedefType>() && QT->isCharType()) { |
883 | 0 | CS.setKind(ConversionSpecifier::cArg); |
884 | 0 | LM.setKind(LengthModifier::None); |
885 | 0 | Precision.setHowSpecified(OptionalAmount::NotSpecified); |
886 | 0 | HasAlternativeForm = false; |
887 | 0 | HasLeadingZeroes = false; |
888 | 0 | HasPlusPrefix = false; |
889 | 0 | } |
890 | | // Test for Floating type first as LongDouble can pass isUnsignedIntegerType |
891 | 0 | else if (QT->isRealFloatingType()) { |
892 | 0 | CS.setKind(ConversionSpecifier::fArg); |
893 | 0 | } else if (QT->isSignedIntegerType()) { |
894 | 0 | CS.setKind(ConversionSpecifier::dArg); |
895 | 0 | HasAlternativeForm = false; |
896 | 0 | } else if (QT->isUnsignedIntegerType()) { |
897 | 0 | CS.setKind(ConversionSpecifier::uArg); |
898 | 0 | HasAlternativeForm = false; |
899 | 0 | HasPlusPrefix = false; |
900 | 0 | } else { |
901 | 0 | llvm_unreachable("Unexpected type"); |
902 | 0 | } |
903 | |
|
904 | 0 | return true; |
905 | 0 | } |
906 | | |
907 | 0 | void PrintfSpecifier::toString(raw_ostream &os) const { |
908 | | // Whilst some features have no defined order, we are using the order |
909 | | // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1) |
910 | 0 | os << "%"; |
911 | | |
912 | | // Positional args |
913 | 0 | if (usesPositionalArg()) { |
914 | 0 | os << getPositionalArgIndex() << "$"; |
915 | 0 | } |
916 | | |
917 | | // Conversion flags |
918 | 0 | if (IsLeftJustified) os << "-"; |
919 | 0 | if (HasPlusPrefix) os << "+"; |
920 | 0 | if (HasSpacePrefix) os << " "; |
921 | 0 | if (HasAlternativeForm) os << "#"; |
922 | 0 | if (HasLeadingZeroes) os << "0"; |
923 | | |
924 | | // Minimum field width |
925 | 0 | FieldWidth.toString(os); |
926 | | // Precision |
927 | 0 | Precision.toString(os); |
928 | | |
929 | | // Vector modifier |
930 | 0 | if (!VectorNumElts.isInvalid()) |
931 | 0 | os << 'v' << VectorNumElts.getConstantAmount(); |
932 | | |
933 | | // Length modifier |
934 | 0 | os << LM.toString(); |
935 | | // Conversion specifier |
936 | 0 | os << CS.toString(); |
937 | 0 | } |
938 | | |
939 | 0 | bool PrintfSpecifier::hasValidPlusPrefix() const { |
940 | 0 | if (!HasPlusPrefix) |
941 | 0 | return true; |
942 | | |
943 | | // The plus prefix only makes sense for signed conversions |
944 | 0 | switch (CS.getKind()) { |
945 | 0 | case ConversionSpecifier::dArg: |
946 | 0 | case ConversionSpecifier::DArg: |
947 | 0 | case ConversionSpecifier::iArg: |
948 | 0 | case ConversionSpecifier::fArg: |
949 | 0 | case ConversionSpecifier::FArg: |
950 | 0 | case ConversionSpecifier::eArg: |
951 | 0 | case ConversionSpecifier::EArg: |
952 | 0 | case ConversionSpecifier::gArg: |
953 | 0 | case ConversionSpecifier::GArg: |
954 | 0 | case ConversionSpecifier::aArg: |
955 | 0 | case ConversionSpecifier::AArg: |
956 | 0 | case ConversionSpecifier::FreeBSDrArg: |
957 | 0 | case ConversionSpecifier::FreeBSDyArg: |
958 | 0 | return true; |
959 | | |
960 | 0 | default: |
961 | 0 | return false; |
962 | 0 | } |
963 | 0 | } |
964 | | |
965 | 0 | bool PrintfSpecifier::hasValidAlternativeForm() const { |
966 | 0 | if (!HasAlternativeForm) |
967 | 0 | return true; |
968 | | |
969 | | // Alternate form flag only valid with the bBoxXaAeEfFgG conversions |
970 | 0 | switch (CS.getKind()) { |
971 | 0 | case ConversionSpecifier::bArg: |
972 | 0 | case ConversionSpecifier::BArg: |
973 | 0 | case ConversionSpecifier::oArg: |
974 | 0 | case ConversionSpecifier::OArg: |
975 | 0 | case ConversionSpecifier::xArg: |
976 | 0 | case ConversionSpecifier::XArg: |
977 | 0 | case ConversionSpecifier::aArg: |
978 | 0 | case ConversionSpecifier::AArg: |
979 | 0 | case ConversionSpecifier::eArg: |
980 | 0 | case ConversionSpecifier::EArg: |
981 | 0 | case ConversionSpecifier::fArg: |
982 | 0 | case ConversionSpecifier::FArg: |
983 | 0 | case ConversionSpecifier::gArg: |
984 | 0 | case ConversionSpecifier::GArg: |
985 | 0 | case ConversionSpecifier::FreeBSDrArg: |
986 | 0 | case ConversionSpecifier::FreeBSDyArg: |
987 | 0 | return true; |
988 | | |
989 | 0 | default: |
990 | 0 | return false; |
991 | 0 | } |
992 | 0 | } |
993 | | |
994 | 0 | bool PrintfSpecifier::hasValidLeadingZeros() const { |
995 | 0 | if (!HasLeadingZeroes) |
996 | 0 | return true; |
997 | | |
998 | | // Leading zeroes flag only valid with the bBdiouxXaAeEfFgG conversions |
999 | 0 | switch (CS.getKind()) { |
1000 | 0 | case ConversionSpecifier::bArg: |
1001 | 0 | case ConversionSpecifier::BArg: |
1002 | 0 | case ConversionSpecifier::dArg: |
1003 | 0 | case ConversionSpecifier::DArg: |
1004 | 0 | case ConversionSpecifier::iArg: |
1005 | 0 | case ConversionSpecifier::oArg: |
1006 | 0 | case ConversionSpecifier::OArg: |
1007 | 0 | case ConversionSpecifier::uArg: |
1008 | 0 | case ConversionSpecifier::UArg: |
1009 | 0 | case ConversionSpecifier::xArg: |
1010 | 0 | case ConversionSpecifier::XArg: |
1011 | 0 | case ConversionSpecifier::aArg: |
1012 | 0 | case ConversionSpecifier::AArg: |
1013 | 0 | case ConversionSpecifier::eArg: |
1014 | 0 | case ConversionSpecifier::EArg: |
1015 | 0 | case ConversionSpecifier::fArg: |
1016 | 0 | case ConversionSpecifier::FArg: |
1017 | 0 | case ConversionSpecifier::gArg: |
1018 | 0 | case ConversionSpecifier::GArg: |
1019 | 0 | case ConversionSpecifier::FreeBSDrArg: |
1020 | 0 | case ConversionSpecifier::FreeBSDyArg: |
1021 | 0 | return true; |
1022 | | |
1023 | 0 | default: |
1024 | 0 | return false; |
1025 | 0 | } |
1026 | 0 | } |
1027 | | |
1028 | 0 | bool PrintfSpecifier::hasValidSpacePrefix() const { |
1029 | 0 | if (!HasSpacePrefix) |
1030 | 0 | return true; |
1031 | | |
1032 | | // The space prefix only makes sense for signed conversions |
1033 | 0 | switch (CS.getKind()) { |
1034 | 0 | case ConversionSpecifier::dArg: |
1035 | 0 | case ConversionSpecifier::DArg: |
1036 | 0 | case ConversionSpecifier::iArg: |
1037 | 0 | case ConversionSpecifier::fArg: |
1038 | 0 | case ConversionSpecifier::FArg: |
1039 | 0 | case ConversionSpecifier::eArg: |
1040 | 0 | case ConversionSpecifier::EArg: |
1041 | 0 | case ConversionSpecifier::gArg: |
1042 | 0 | case ConversionSpecifier::GArg: |
1043 | 0 | case ConversionSpecifier::aArg: |
1044 | 0 | case ConversionSpecifier::AArg: |
1045 | 0 | case ConversionSpecifier::FreeBSDrArg: |
1046 | 0 | case ConversionSpecifier::FreeBSDyArg: |
1047 | 0 | return true; |
1048 | | |
1049 | 0 | default: |
1050 | 0 | return false; |
1051 | 0 | } |
1052 | 0 | } |
1053 | | |
1054 | 0 | bool PrintfSpecifier::hasValidLeftJustified() const { |
1055 | 0 | if (!IsLeftJustified) |
1056 | 0 | return true; |
1057 | | |
1058 | | // The left justified flag is valid for all conversions except n |
1059 | 0 | switch (CS.getKind()) { |
1060 | 0 | case ConversionSpecifier::nArg: |
1061 | 0 | return false; |
1062 | | |
1063 | 0 | default: |
1064 | 0 | return true; |
1065 | 0 | } |
1066 | 0 | } |
1067 | | |
1068 | 0 | bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const { |
1069 | 0 | if (!HasThousandsGrouping) |
1070 | 0 | return true; |
1071 | | |
1072 | 0 | switch (CS.getKind()) { |
1073 | 0 | case ConversionSpecifier::dArg: |
1074 | 0 | case ConversionSpecifier::DArg: |
1075 | 0 | case ConversionSpecifier::iArg: |
1076 | 0 | case ConversionSpecifier::uArg: |
1077 | 0 | case ConversionSpecifier::UArg: |
1078 | 0 | case ConversionSpecifier::fArg: |
1079 | 0 | case ConversionSpecifier::FArg: |
1080 | 0 | case ConversionSpecifier::gArg: |
1081 | 0 | case ConversionSpecifier::GArg: |
1082 | 0 | return true; |
1083 | 0 | default: |
1084 | 0 | return false; |
1085 | 0 | } |
1086 | 0 | } |
1087 | | |
1088 | 0 | bool PrintfSpecifier::hasValidPrecision() const { |
1089 | 0 | if (Precision.getHowSpecified() == OptionalAmount::NotSpecified) |
1090 | 0 | return true; |
1091 | | |
1092 | | // Precision is only valid with the bBdiouxXaAeEfFgGsP conversions |
1093 | 0 | switch (CS.getKind()) { |
1094 | 0 | case ConversionSpecifier::bArg: |
1095 | 0 | case ConversionSpecifier::BArg: |
1096 | 0 | case ConversionSpecifier::dArg: |
1097 | 0 | case ConversionSpecifier::DArg: |
1098 | 0 | case ConversionSpecifier::iArg: |
1099 | 0 | case ConversionSpecifier::oArg: |
1100 | 0 | case ConversionSpecifier::OArg: |
1101 | 0 | case ConversionSpecifier::uArg: |
1102 | 0 | case ConversionSpecifier::UArg: |
1103 | 0 | case ConversionSpecifier::xArg: |
1104 | 0 | case ConversionSpecifier::XArg: |
1105 | 0 | case ConversionSpecifier::aArg: |
1106 | 0 | case ConversionSpecifier::AArg: |
1107 | 0 | case ConversionSpecifier::eArg: |
1108 | 0 | case ConversionSpecifier::EArg: |
1109 | 0 | case ConversionSpecifier::fArg: |
1110 | 0 | case ConversionSpecifier::FArg: |
1111 | 0 | case ConversionSpecifier::gArg: |
1112 | 0 | case ConversionSpecifier::GArg: |
1113 | 0 | case ConversionSpecifier::sArg: |
1114 | 0 | case ConversionSpecifier::FreeBSDrArg: |
1115 | 0 | case ConversionSpecifier::FreeBSDyArg: |
1116 | 0 | case ConversionSpecifier::PArg: |
1117 | 0 | return true; |
1118 | | |
1119 | 0 | default: |
1120 | 0 | return false; |
1121 | 0 | } |
1122 | 0 | } |
1123 | 0 | bool PrintfSpecifier::hasValidFieldWidth() const { |
1124 | 0 | if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified) |
1125 | 0 | return true; |
1126 | | |
1127 | | // The field width is valid for all conversions except n |
1128 | 0 | switch (CS.getKind()) { |
1129 | 0 | case ConversionSpecifier::nArg: |
1130 | 0 | return false; |
1131 | | |
1132 | 0 | default: |
1133 | 0 | return true; |
1134 | 0 | } |
1135 | 0 | } |