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