/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==// |
2 | | // |
3 | | // The LLVM Compiler Infrastructure |
4 | | // |
5 | | // This file is distributed under the University of Illinois Open Source |
6 | | // License. See LICENSE.TXT for details. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | // |
10 | | // Handling of format string in printf and friends. The structure of format |
11 | | // strings for fprintf() are described in C99 7.19.6.1. |
12 | | // |
13 | | //===----------------------------------------------------------------------===// |
14 | | |
15 | | #include "clang/Analysis/Analyses/FormatString.h" |
16 | | #include "FormatStringParsing.h" |
17 | | #include "clang/Basic/TargetInfo.h" |
18 | | |
19 | | using clang::analyze_format_string::ArgType; |
20 | | using clang::analyze_format_string::FormatStringHandler; |
21 | | using clang::analyze_format_string::LengthModifier; |
22 | | using clang::analyze_format_string::OptionalAmount; |
23 | | using clang::analyze_format_string::ConversionSpecifier; |
24 | | using clang::analyze_printf::PrintfSpecifier; |
25 | | |
26 | | using namespace clang; |
27 | | |
28 | | typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier> |
29 | | PrintfSpecifierResult; |
30 | | |
31 | | //===----------------------------------------------------------------------===// |
32 | | // Methods for parsing format strings. |
33 | | //===----------------------------------------------------------------------===// |
34 | | |
35 | | using analyze_format_string::ParseNonPositionAmount; |
36 | | |
37 | | static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, |
38 | | const char *Start, const char *&Beg, const char *E, |
39 | 3.98k | unsigned *argIndex) { |
40 | 3.98k | if (argIndex3.98k ) { |
41 | 3.98k | FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex)); |
42 | 3.98k | } else { |
43 | 8 | const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, |
44 | 8 | analyze_format_string::PrecisionPos); |
45 | 8 | if (Amt.isInvalid()) |
46 | 0 | return true; |
47 | 8 | FS.setPrecision(Amt); |
48 | 8 | } |
49 | 3.98k | return false; |
50 | 3.98k | } |
51 | | |
52 | | static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS, |
53 | 17 | const char *FlagBeg, const char *E, bool Warn) { |
54 | 17 | StringRef Flag(FlagBeg, E - FlagBeg); |
55 | 17 | // Currently there is only one flag. |
56 | 17 | if (Flag == "tt"17 ) { |
57 | 13 | FS.setHasObjCTechnicalTerm(FlagBeg); |
58 | 13 | return false; |
59 | 13 | } |
60 | 4 | // Handle either the case of no flag or an invalid flag. |
61 | 4 | if (4 Warn4 ) { |
62 | 2 | if (Flag == "") |
63 | 1 | H.HandleEmptyObjCModifierFlag(FlagBeg, E - FlagBeg); |
64 | 2 | else |
65 | 1 | H.HandleInvalidObjCModifierFlag(FlagBeg, E - FlagBeg); |
66 | 2 | } |
67 | 17 | return true; |
68 | 17 | } |
69 | | |
70 | | static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, |
71 | | const char *&Beg, |
72 | | const char *E, |
73 | | unsigned &argIndex, |
74 | | const LangOptions &LO, |
75 | | const TargetInfo &Target, |
76 | | bool Warn, |
77 | 178k | bool isFreeBSDKPrintf) { |
78 | 178k | |
79 | 178k | using namespace clang::analyze_format_string; |
80 | 178k | using namespace clang::analyze_printf; |
81 | 178k | |
82 | 178k | const char *I = Beg; |
83 | 178k | const char *Start = nullptr; |
84 | 178k | UpdateOnReturn <const char*> UpdateBeg(Beg, I); |
85 | 178k | |
86 | 178k | // Look for a '%' character that indicates the start of a format specifier. |
87 | 1.19M | for ( ; I != E1.19M ; ++I1.01M ) { |
88 | 1.12M | char c = *I; |
89 | 1.12M | if (c == '\0'1.12M ) { |
90 | 18 | // Detect spurious null characters, which are likely errors. |
91 | 18 | H.HandleNullChar(I); |
92 | 18 | return true; |
93 | 18 | } |
94 | 1.12M | if (1.12M c == '%'1.12M ) { |
95 | 105k | Start = I++; // Record the start of the format specifier. |
96 | 105k | break; |
97 | 105k | } |
98 | 1.12M | } |
99 | 178k | |
100 | 178k | // No format specifier found? |
101 | 178k | if (178k !Start178k ) |
102 | 72.6k | return false; |
103 | 105k | |
104 | 105k | if (105k I == E105k ) { |
105 | 17 | // No more characters left? |
106 | 17 | if (Warn) |
107 | 17 | H.HandleIncompleteSpecifier(Start, E - Start); |
108 | 17 | return true; |
109 | 17 | } |
110 | 105k | |
111 | 105k | PrintfSpecifier FS; |
112 | 105k | if (ParseArgPosition(H, FS, Start, I, E)) |
113 | 6 | return true; |
114 | 105k | |
115 | 105k | if (105k I == E105k ) { |
116 | 0 | // No more characters left? |
117 | 0 | if (Warn) |
118 | 0 | H.HandleIncompleteSpecifier(Start, E - Start); |
119 | 0 | return true; |
120 | 0 | } |
121 | 105k | |
122 | 105k | const char *OSLogVisibilityFlagsStart = nullptr, |
123 | 105k | *OSLogVisibilityFlagsEnd = nullptr; |
124 | 105k | if (*I == '{'105k ) { |
125 | 15 | OSLogVisibilityFlagsStart = I++; |
126 | 15 | // Find the end of the modifier. |
127 | 114 | while (I != E && 114 *I != '}'114 ) { |
128 | 99 | I++; |
129 | 99 | } |
130 | 15 | if (I == E15 ) { |
131 | 0 | if (Warn) |
132 | 0 | H.HandleIncompleteSpecifier(Start, E - Start); |
133 | 0 | return true; |
134 | 0 | } |
135 | 15 | assert(*I == '}'); |
136 | 15 | OSLogVisibilityFlagsEnd = I++; |
137 | 15 | |
138 | 15 | // Just see if 'private' or 'public' is the first word. os_log itself will |
139 | 15 | // do any further parsing. |
140 | 15 | const char *P = OSLogVisibilityFlagsStart + 1; |
141 | 15 | while (P < OSLogVisibilityFlagsEnd && 15 isspace(*P)15 ) |
142 | 0 | P++; |
143 | 15 | const char *WordStart = P; |
144 | 114 | while (P < OSLogVisibilityFlagsEnd && 114 (isalnum(*P) || 99 *P == '_'0 )) |
145 | 99 | P++; |
146 | 15 | const char *WordEnd = P; |
147 | 15 | StringRef Word(WordStart, WordEnd - WordStart); |
148 | 15 | if (Word == "private"15 ) { |
149 | 9 | FS.setIsPrivate(WordStart); |
150 | 15 | } else if (6 Word == "public"6 ) { |
151 | 6 | FS.setIsPublic(WordStart); |
152 | 6 | } |
153 | 15 | } |
154 | 105k | |
155 | 105k | // Look for flags (if any). |
156 | 105k | bool hasMore = true; |
157 | 125k | for ( ; I != E125k ; ++I19.1k ) { |
158 | 125k | switch (*I) { |
159 | 105k | default: hasMore = false; break; |
160 | 14 | case '\'': |
161 | 14 | // FIXME: POSIX specific. Always accept? |
162 | 14 | FS.setHasThousandsGrouping(I); |
163 | 14 | break; |
164 | 340 | case '-': FS.setIsLeftJustified(I); break; |
165 | 57 | case '+': FS.setHasPlusPrefix(I); break; |
166 | 51 | case ' ': FS.setHasSpacePrefix(I); break; |
167 | 53 | case '#': FS.setHasAlternativeForm(I); break; |
168 | 18.6k | case '0': FS.setHasLeadingZeros(I); break; |
169 | 125k | } |
170 | 125k | if (125k !hasMore125k ) |
171 | 105k | break; |
172 | 125k | } |
173 | 105k | |
174 | 105k | if (105k I == E105k ) { |
175 | 0 | // No more characters left? |
176 | 0 | if (Warn) |
177 | 0 | H.HandleIncompleteSpecifier(Start, E - Start); |
178 | 0 | return true; |
179 | 0 | } |
180 | 105k | |
181 | 105k | // Look for the field width (if any). |
182 | 105k | if (105k ParseFieldWidth(H, FS, Start, I, E, |
183 | 105k | FS.usesPositionalArg() ? nullptr55 : &argIndex105k )) |
184 | 2 | return true; |
185 | 105k | |
186 | 105k | if (105k I == E105k ) { |
187 | 0 | // No more characters left? |
188 | 0 | if (Warn) |
189 | 0 | H.HandleIncompleteSpecifier(Start, E - Start); |
190 | 0 | return true; |
191 | 0 | } |
192 | 105k | |
193 | 105k | // Look for the precision (if any). |
194 | 105k | if (105k *I == '.'105k ) { |
195 | 3.99k | ++I; |
196 | 3.99k | if (I == E3.99k ) { |
197 | 6 | if (Warn) |
198 | 6 | H.HandleIncompleteSpecifier(Start, E - Start); |
199 | 6 | return true; |
200 | 6 | } |
201 | 3.98k | |
202 | 3.98k | if (3.98k ParsePrecision(H, FS, Start, I, E, |
203 | 3.98k | FS.usesPositionalArg() ? nullptr8 : &argIndex3.98k )) |
204 | 0 | return true; |
205 | 3.98k | |
206 | 3.98k | if (3.98k I == E3.98k ) { |
207 | 0 | // No more characters left? |
208 | 0 | if (Warn) |
209 | 0 | H.HandleIncompleteSpecifier(Start, E - Start); |
210 | 0 | return true; |
211 | 0 | } |
212 | 105k | } |
213 | 105k | |
214 | 105k | // Look for the length modifier. |
215 | 105k | if (105k ParseLengthModifier(FS, I, E, LO) && 105k I == E26.4k ) { |
216 | 2 | // No more characters left? |
217 | 2 | if (Warn) |
218 | 2 | H.HandleIncompleteSpecifier(Start, E - Start); |
219 | 2 | return true; |
220 | 2 | } |
221 | 105k | |
222 | 105k | // Look for the Objective-C modifier flags, if any. |
223 | 105k | // We parse these here, even if they don't apply to |
224 | 105k | // the conversion specifier, and then emit an error |
225 | 105k | // later if the conversion specifier isn't '@'. This |
226 | 105k | // enables better recovery, and we don't know if |
227 | 105k | // these flags are applicable until later. |
228 | 105k | const char *ObjCModifierFlagsStart = nullptr, |
229 | 105k | *ObjCModifierFlagsEnd = nullptr; |
230 | 105k | if (*I == '['105k ) { |
231 | 21 | ObjCModifierFlagsStart = I; |
232 | 21 | ++I; |
233 | 21 | auto flagStart = I; |
234 | 40 | for (;; ++I40 ) { |
235 | 61 | ObjCModifierFlagsEnd = I; |
236 | 61 | if (I == E61 ) { |
237 | 4 | if (Warn) |
238 | 2 | H.HandleIncompleteSpecifier(Start, E - Start); |
239 | 4 | return true; |
240 | 4 | } |
241 | 57 | // Did we find the closing ']'? |
242 | 57 | if (57 *I == ']'57 ) { |
243 | 17 | if (ParseObjCFlags(H, FS, flagStart, I, Warn)) |
244 | 4 | return true; |
245 | 13 | ++I; |
246 | 13 | break; |
247 | 13 | } |
248 | 61 | // There are no separators defined yet for multiple |
249 | 61 | // Objective-C modifier flags. When those are |
250 | 61 | // defined, this is the place to check. |
251 | 61 | } |
252 | 21 | } |
253 | 105k | |
254 | 105k | if (105k *I == '\0'105k ) { |
255 | 2 | // Detect spurious null characters, which are likely errors. |
256 | 2 | H.HandleNullChar(I); |
257 | 2 | return true; |
258 | 2 | } |
259 | 105k | |
260 | 105k | // Finally, look for the conversion specifier. |
261 | 105k | const char *conversionPosition = I++; |
262 | 105k | ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; |
263 | 105k | switch (*conversionPosition) { |
264 | 32 | default: |
265 | 32 | break; |
266 | 105k | // C99: 7.19.6.1 (section 8). |
267 | 378 | case '%': k = ConversionSpecifier::PercentArg; break; |
268 | 2 | case 'A': k = ConversionSpecifier::AArg; break; |
269 | 2 | case 'E': k = ConversionSpecifier::EArg; break; |
270 | 2 | case 'F': k = ConversionSpecifier::FArg; break; |
271 | 14 | case 'G': k = ConversionSpecifier::GArg; break; |
272 | 129 | case 'X': k = ConversionSpecifier::XArg; break; |
273 | 17 | case 'a': k = ConversionSpecifier::aArg; break; |
274 | 517 | case 'c': k = ConversionSpecifier::cArg; break; |
275 | 13.6k | case 'd': k = ConversionSpecifier::dArg; break; |
276 | 114 | case 'e': k = ConversionSpecifier::eArg; break; |
277 | 8.14k | case 'f': k = ConversionSpecifier::fArg; break; |
278 | 1.63k | case 'g': k = ConversionSpecifier::gArg; break; |
279 | 2.81k | case 'i': k = ConversionSpecifier::iArg; break; |
280 | 72 | case 'n': k = ConversionSpecifier::nArg; break; |
281 | 25 | case 'o': k = ConversionSpecifier::oArg; break; |
282 | 453 | case 'p': k = ConversionSpecifier::pArg; break; |
283 | 52.7k | case 's': k = ConversionSpecifier::sArg; break; |
284 | 5.85k | case 'u': k = ConversionSpecifier::uArg; break; |
285 | 18.8k | case 'x': k = ConversionSpecifier::xArg; break; |
286 | 105k | // POSIX specific. |
287 | 71 | case 'C': k = ConversionSpecifier::CArg; break; |
288 | 31 | case 'S': k = ConversionSpecifier::SArg; break; |
289 | 105k | // Apple extension for os_log |
290 | 17 | case 'P': |
291 | 17 | k = ConversionSpecifier::PArg; |
292 | 17 | break; |
293 | 105k | // Objective-C. |
294 | 225 | case '@': k = ConversionSpecifier::ObjCObjArg; break; |
295 | 105k | // Glibc specific. |
296 | 9 | case 'm': k = ConversionSpecifier::PrintErrno; break; |
297 | 105k | // FreeBSD kernel specific. |
298 | 18 | case 'b': |
299 | 18 | if (isFreeBSDKPrintf) |
300 | 15 | k = ConversionSpecifier::FreeBSDbArg; // int followed by char * |
301 | 18 | break; |
302 | 18 | case 'r': |
303 | 18 | if (isFreeBSDKPrintf) |
304 | 18 | k = ConversionSpecifier::FreeBSDrArg; // int |
305 | 18 | break; |
306 | 22 | case 'y': |
307 | 22 | if (isFreeBSDKPrintf) |
308 | 18 | k = ConversionSpecifier::FreeBSDyArg; // int |
309 | 22 | break; |
310 | 105k | // Apple-specific. |
311 | 60 | case 'D': |
312 | 60 | if (isFreeBSDKPrintf) |
313 | 30 | k = ConversionSpecifier::FreeBSDDArg; // void * followed by char * |
314 | 30 | else if (30 Target.getTriple().isOSDarwin()30 ) |
315 | 22 | k = ConversionSpecifier::DArg; |
316 | 60 | break; |
317 | 22 | case 'O': |
318 | 22 | if (Target.getTriple().isOSDarwin()) |
319 | 14 | k = ConversionSpecifier::OArg; |
320 | 22 | break; |
321 | 22 | case 'U': |
322 | 22 | if (Target.getTriple().isOSDarwin()) |
323 | 14 | k = ConversionSpecifier::UArg; |
324 | 22 | break; |
325 | 105k | // MS specific. |
326 | 10 | case 'Z': |
327 | 10 | if (Target.getTriple().isOSMSVCRT()) |
328 | 6 | k = ConversionSpecifier::ZArg; |
329 | 105k | } |
330 | 105k | |
331 | 105k | // Check to see if we used the Objective-C modifier flags with |
332 | 105k | // a conversion specifier other than '@'. |
333 | 105k | if (105k k != ConversionSpecifier::ObjCObjArg && |
334 | 105k | k != ConversionSpecifier::InvalidSpecifier && |
335 | 105k | ObjCModifierFlagsStart105k ) { |
336 | 2 | H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart, |
337 | 2 | ObjCModifierFlagsEnd + 1, |
338 | 2 | conversionPosition); |
339 | 2 | return true; |
340 | 2 | } |
341 | 105k | |
342 | 105k | PrintfConversionSpecifier CS(conversionPosition, k); |
343 | 105k | FS.setConversionSpecifier(CS); |
344 | 105k | if (CS.consumesDataArgument() && 105k !FS.usesPositionalArg()105k ) |
345 | 105k | FS.setArgIndex(argIndex++); |
346 | 105k | // FreeBSD kernel specific. |
347 | 105k | if (k == ConversionSpecifier::FreeBSDbArg || |
348 | 105k | k == ConversionSpecifier::FreeBSDDArg) |
349 | 45 | argIndex++; |
350 | 105k | |
351 | 105k | if (k == ConversionSpecifier::InvalidSpecifier105k ) { |
352 | 67 | unsigned Len = I - Start; |
353 | 67 | if (ParseUTF8InvalidSpecifier(Start, E, Len)67 ) { |
354 | 12 | CS.setEndScanList(Start + Len); |
355 | 12 | FS.setConversionSpecifier(CS); |
356 | 12 | } |
357 | 67 | // Assume the conversion takes one argument. |
358 | 67 | return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len); |
359 | 67 | } |
360 | 105k | return PrintfSpecifierResult(Start, FS); |
361 | 105k | } |
362 | | |
363 | | bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, |
364 | | const char *I, |
365 | | const char *E, |
366 | | const LangOptions &LO, |
367 | | const TargetInfo &Target, |
368 | 76.2k | bool isFreeBSDKPrintf) { |
369 | 76.2k | |
370 | 76.2k | unsigned argIndex = 0; |
371 | 76.2k | |
372 | 76.2k | // Keep looking for a format specifier until we have exhausted the string. |
373 | 254k | while (I != E254k ) { |
374 | 178k | const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, |
375 | 178k | LO, Target, true, |
376 | 178k | isFreeBSDKPrintf); |
377 | 178k | // Did a fail-stop error of any kind occur when parsing the specifier? |
378 | 178k | // If so, don't do any more processing. |
379 | 178k | if (FSR.shouldStop()) |
380 | 72 | return true; |
381 | 178k | // Did we exhaust the string or encounter an error that |
382 | 178k | // we can recover from? |
383 | 178k | if (178k !FSR.hasValue()178k ) |
384 | 72.6k | continue; |
385 | 105k | // We have a format specifier. Pass it to the callback. |
386 | 105k | if (105k !H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(), |
387 | 105k | I - FSR.getStart())) |
388 | 124 | return true; |
389 | 178k | } |
390 | 76.0k | assert(I == E && "Format string not exhausted"); |
391 | 76.0k | return false; |
392 | 76.2k | } |
393 | | |
394 | | bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I, |
395 | | const char *E, |
396 | | const LangOptions &LO, |
397 | 321 | const TargetInfo &Target) { |
398 | 321 | |
399 | 321 | unsigned argIndex = 0; |
400 | 321 | |
401 | 321 | // Keep looking for a %s format specifier until we have exhausted the string. |
402 | 321 | FormatStringHandler H; |
403 | 611 | while (I != E611 ) { |
404 | 354 | const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, |
405 | 354 | LO, Target, false, |
406 | 354 | false); |
407 | 354 | // Did a fail-stop error of any kind occur when parsing the specifier? |
408 | 354 | // If so, don't do any more processing. |
409 | 354 | if (FSR.shouldStop()) |
410 | 5 | return false; |
411 | 349 | // Did we exhaust the string or encounter an error that |
412 | 349 | // we can recover from? |
413 | 349 | if (349 !FSR.hasValue()349 ) |
414 | 58 | continue; |
415 | 291 | const analyze_printf::PrintfSpecifier &FS = FSR.getValue(); |
416 | 291 | // Return true if this a %s format specifier. |
417 | 291 | if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg) |
418 | 59 | return true; |
419 | 354 | } |
420 | 257 | return false; |
421 | 321 | } |
422 | | |
423 | | //===----------------------------------------------------------------------===// |
424 | | // Methods on PrintfSpecifier. |
425 | | //===----------------------------------------------------------------------===// |
426 | | |
427 | | ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, |
428 | 105k | bool IsObjCLiteral) const { |
429 | 105k | const PrintfConversionSpecifier &CS = getConversionSpecifier(); |
430 | 105k | |
431 | 105k | if (!CS.consumesDataArgument()) |
432 | 0 | return ArgType::Invalid(); |
433 | 105k | |
434 | 105k | if (105k CS.getKind() == ConversionSpecifier::cArg105k ) |
435 | 509 | switch (LM.getKind()) { |
436 | 488 | case LengthModifier::None: |
437 | 488 | return Ctx.IntTy; |
438 | 14 | case LengthModifier::AsLong: |
439 | 14 | case LengthModifier::AsWide: |
440 | 14 | return ArgType(ArgType::WIntTy, "wint_t"); |
441 | 1 | case LengthModifier::AsShort: |
442 | 1 | if (Ctx.getTargetInfo().getTriple().isOSMSVCRT()) |
443 | 1 | return Ctx.IntTy; |
444 | 0 | LLVM_FALLTHROUGH0 ; |
445 | 6 | default: |
446 | 6 | return ArgType::Invalid(); |
447 | 105k | } |
448 | 105k | |
449 | 105k | if (105k CS.isIntArg()105k ) |
450 | 16.5k | switch (LM.getKind()) { |
451 | 17 | case LengthModifier::AsLongDouble: |
452 | 17 | // GNU extension. |
453 | 17 | return Ctx.LongLongTy; |
454 | 13.4k | case LengthModifier::None: |
455 | 13.4k | return Ctx.IntTy; |
456 | 2 | case LengthModifier::AsInt32: |
457 | 2 | return ArgType(Ctx.IntTy, "__int32"); |
458 | 1.16k | case LengthModifier::AsChar: return ArgType::AnyCharTy; |
459 | 754 | case LengthModifier::AsShort: return Ctx.ShortTy; |
460 | 521 | case LengthModifier::AsLong: return Ctx.LongTy; |
461 | 661 | case LengthModifier::AsLongLong: |
462 | 661 | case LengthModifier::AsQuad: |
463 | 661 | return Ctx.LongLongTy; |
464 | 2 | case LengthModifier::AsInt64: |
465 | 2 | return ArgType(Ctx.LongLongTy, "__int64"); |
466 | 5 | case LengthModifier::AsIntMax: |
467 | 5 | return ArgType(Ctx.getIntMaxType(), "intmax_t"); |
468 | 26 | case LengthModifier::AsSizeT: |
469 | 26 | return ArgType(Ctx.getSignedSizeType(), "ssize_t"); |
470 | 4 | case LengthModifier::AsInt3264: |
471 | 4 | return Ctx.getTargetInfo().getTriple().isArch64Bit() |
472 | 1 | ? ArgType(Ctx.LongLongTy, "__int64") |
473 | 3 | : ArgType(Ctx.IntTy, "__int32"); |
474 | 5 | case LengthModifier::AsPtrDiff: |
475 | 5 | return ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"); |
476 | 0 | case LengthModifier::AsAllocate: |
477 | 0 | case LengthModifier::AsMAllocate: |
478 | 0 | case LengthModifier::AsWide: |
479 | 0 | return ArgType::Invalid(); |
480 | 88.5k | } |
481 | 88.5k | |
482 | 88.5k | if (88.5k CS.isUIntArg()88.5k ) |
483 | 25.0k | switch (LM.getKind()) { |
484 | 12 | case LengthModifier::AsLongDouble: |
485 | 12 | // GNU extension. |
486 | 12 | return Ctx.UnsignedLongLongTy; |
487 | 2.51k | case LengthModifier::None: |
488 | 2.51k | return Ctx.UnsignedIntTy; |
489 | 1 | case LengthModifier::AsInt32: |
490 | 1 | return ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); |
491 | 2.20k | case LengthModifier::AsChar: return Ctx.UnsignedCharTy; |
492 | 1.24k | case LengthModifier::AsShort: return Ctx.UnsignedShortTy; |
493 | 760 | case LengthModifier::AsLong: return Ctx.UnsignedLongTy; |
494 | 18.3k | case LengthModifier::AsLongLong: |
495 | 18.3k | case LengthModifier::AsQuad: |
496 | 18.3k | return Ctx.UnsignedLongLongTy; |
497 | 1 | case LengthModifier::AsInt64: |
498 | 1 | return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"); |
499 | 5 | case LengthModifier::AsIntMax: |
500 | 5 | return ArgType(Ctx.getUIntMaxType(), "uintmax_t"); |
501 | 48 | case LengthModifier::AsSizeT: |
502 | 48 | return ArgType(Ctx.getSizeType(), "size_t"); |
503 | 1 | case LengthModifier::AsInt3264: |
504 | 1 | return Ctx.getTargetInfo().getTriple().isArch64Bit() |
505 | 0 | ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64") |
506 | 1 | : ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); |
507 | 0 | case LengthModifier::AsPtrDiff: |
508 | 0 | // FIXME: How to get the corresponding unsigned |
509 | 0 | // version of ptrdiff_t? |
510 | 0 | return ArgType(); |
511 | 0 | case LengthModifier::AsAllocate: |
512 | 0 | case LengthModifier::AsMAllocate: |
513 | 0 | case LengthModifier::AsWide: |
514 | 0 | return ArgType::Invalid(); |
515 | 63.4k | } |
516 | 63.4k | |
517 | 63.4k | if (63.4k CS.isDoubleArg()63.4k ) { |
518 | 9.91k | if (LM.getKind() == LengthModifier::AsLongDouble) |
519 | 31 | return Ctx.LongDoubleTy; |
520 | 9.88k | return Ctx.DoubleTy; |
521 | 9.88k | } |
522 | 53.5k | |
523 | 53.5k | if (53.5k CS.getKind() == ConversionSpecifier::nArg53.5k ) { |
524 | 71 | switch (LM.getKind()) { |
525 | 28 | case LengthModifier::None: |
526 | 28 | return ArgType::PtrTo(Ctx.IntTy); |
527 | 8 | case LengthModifier::AsChar: |
528 | 8 | return ArgType::PtrTo(Ctx.SignedCharTy); |
529 | 6 | case LengthModifier::AsShort: |
530 | 6 | return ArgType::PtrTo(Ctx.ShortTy); |
531 | 6 | case LengthModifier::AsLong: |
532 | 6 | return ArgType::PtrTo(Ctx.LongTy); |
533 | 12 | case LengthModifier::AsLongLong: |
534 | 12 | case LengthModifier::AsQuad: |
535 | 12 | return ArgType::PtrTo(Ctx.LongLongTy); |
536 | 3 | case LengthModifier::AsIntMax: |
537 | 3 | return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); |
538 | 3 | case LengthModifier::AsSizeT: |
539 | 3 | return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t")); |
540 | 3 | case LengthModifier::AsPtrDiff: |
541 | 3 | return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); |
542 | 2 | case LengthModifier::AsLongDouble: |
543 | 2 | return ArgType(); // FIXME: Is this a known extension? |
544 | 0 | case LengthModifier::AsAllocate: |
545 | 0 | case LengthModifier::AsMAllocate: |
546 | 0 | case LengthModifier::AsInt32: |
547 | 0 | case LengthModifier::AsInt3264: |
548 | 0 | case LengthModifier::AsInt64: |
549 | 0 | case LengthModifier::AsWide: |
550 | 0 | return ArgType::Invalid(); |
551 | 53.4k | } |
552 | 53.4k | } |
553 | 53.4k | |
554 | 53.4k | switch (CS.getKind()) { |
555 | 52.8k | case ConversionSpecifier::sArg: |
556 | 52.8k | if (LM.getKind() == LengthModifier::AsWideChar52.8k ) { |
557 | 103 | if (IsObjCLiteral) |
558 | 2 | return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), |
559 | 2 | "const unichar *"); |
560 | 101 | return ArgType(ArgType::WCStrTy, "wchar_t *"); |
561 | 101 | } |
562 | 52.7k | if (52.7k LM.getKind() == LengthModifier::AsWide52.7k ) |
563 | 2 | return ArgType(ArgType::WCStrTy, "wchar_t *"); |
564 | 52.7k | return ArgType::CStrTy; |
565 | 27 | case ConversionSpecifier::SArg: |
566 | 27 | if (IsObjCLiteral) |
567 | 2 | return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), |
568 | 2 | "const unichar *"); |
569 | 25 | if (25 Ctx.getTargetInfo().getTriple().isOSMSVCRT() && |
570 | 8 | LM.getKind() == LengthModifier::AsShort) |
571 | 1 | return ArgType::CStrTy; |
572 | 24 | return ArgType(ArgType::WCStrTy, "wchar_t *"); |
573 | 49 | case ConversionSpecifier::CArg: |
574 | 49 | if (IsObjCLiteral) |
575 | 34 | return ArgType(Ctx.UnsignedShortTy, "unichar"); |
576 | 15 | if (15 Ctx.getTargetInfo().getTriple().isOSMSVCRT() && |
577 | 8 | LM.getKind() == LengthModifier::AsShort) |
578 | 1 | return Ctx.IntTy; |
579 | 14 | return ArgType(Ctx.WideCharTy, "wchar_t"); |
580 | 458 | case ConversionSpecifier::pArg: |
581 | 458 | case ConversionSpecifier::PArg: |
582 | 458 | return ArgType::CPointerTy; |
583 | 112 | case ConversionSpecifier::ObjCObjArg: |
584 | 112 | return ArgType::ObjCPointerTy; |
585 | 6 | default: |
586 | 6 | break; |
587 | 6 | } |
588 | 6 | |
589 | 6 | // FIXME: Handle other cases. |
590 | 6 | return ArgType(); |
591 | 6 | } |
592 | | |
593 | | bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, |
594 | 1.22k | ASTContext &Ctx, bool IsObjCLiteral) { |
595 | 1.22k | // %n is different from other conversion specifiers; don't try to fix it. |
596 | 1.22k | if (CS.getKind() == ConversionSpecifier::nArg) |
597 | 24 | return false; |
598 | 1.20k | |
599 | 1.20k | // Handle Objective-C objects first. Note that while the '%@' specifier will |
600 | 1.20k | // not warn for structure pointer or void pointer arguments (because that's |
601 | 1.20k | // how CoreFoundation objects are implemented), we only show a fixit for '%@' |
602 | 1.20k | // if we know it's an object (block, id, class, or __attribute__((NSObject))). |
603 | 1.20k | if (1.20k QT->isObjCRetainableType()1.20k ) { |
604 | 45 | if (!IsObjCLiteral) |
605 | 19 | return false; |
606 | 26 | |
607 | 26 | CS.setKind(ConversionSpecifier::ObjCObjArg); |
608 | 26 | |
609 | 26 | // Disable irrelevant flags |
610 | 26 | HasThousandsGrouping = false; |
611 | 26 | HasPlusPrefix = false; |
612 | 26 | HasSpacePrefix = false; |
613 | 26 | HasAlternativeForm = false; |
614 | 26 | HasLeadingZeroes = false; |
615 | 26 | Precision.setHowSpecified(OptionalAmount::NotSpecified); |
616 | 26 | LM.setKind(LengthModifier::None); |
617 | 26 | |
618 | 26 | return true; |
619 | 26 | } |
620 | 1.15k | |
621 | 1.15k | // Handle strings next (char *, wchar_t *) |
622 | 1.15k | if (1.15k QT->isPointerType() && 1.15k (QT->getPointeeType()->isAnyCharacterType())400 ) { |
623 | 119 | CS.setKind(ConversionSpecifier::sArg); |
624 | 119 | |
625 | 119 | // Disable irrelevant flags |
626 | 119 | HasAlternativeForm = 0; |
627 | 119 | HasLeadingZeroes = 0; |
628 | 119 | |
629 | 119 | // Set the long length modifier for wide characters |
630 | 119 | if (QT->getPointeeType()->isWideCharType()) |
631 | 0 | LM.setKind(LengthModifier::AsWideChar); |
632 | 119 | else |
633 | 119 | LM.setKind(LengthModifier::None); |
634 | 119 | |
635 | 119 | return true; |
636 | 119 | } |
637 | 1.03k | |
638 | 1.03k | // If it's an enum, get its underlying type. |
639 | 1.03k | if (const EnumType *1.03k ETy1.03k = QT->getAs<EnumType>()) |
640 | 0 | QT = ETy->getDecl()->getIntegerType(); |
641 | 1.03k | |
642 | 1.03k | // We can only work with builtin types. |
643 | 1.03k | const BuiltinType *BT = QT->getAs<BuiltinType>(); |
644 | 1.03k | if (!BT) |
645 | 311 | return false; |
646 | 727 | |
647 | 727 | // Set length modifier |
648 | 727 | switch (BT->getKind()) { |
649 | 0 | case BuiltinType::Bool: |
650 | 0 | case BuiltinType::WChar_U: |
651 | 0 | case BuiltinType::WChar_S: |
652 | 0 | case BuiltinType::Char16: |
653 | 0 | case BuiltinType::Char32: |
654 | 0 | case BuiltinType::UInt128: |
655 | 0 | case BuiltinType::Int128: |
656 | 0 | case BuiltinType::Half: |
657 | 0 | case BuiltinType::Float16: |
658 | 0 | case BuiltinType::Float128: |
659 | 0 | // Various types which are non-trivial to correct. |
660 | 0 | return false; |
661 | 0 |
|
662 | 0 | #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ |
663 | 108 | case BuiltinType::Id: |
664 | 0 | #include "clang/Basic/OpenCLImageTypes.def"0 |
665 | 108 | #define SIGNED_TYPE(Id, SingletonId) |
666 | 108 | #define UNSIGNED_TYPE(Id, SingletonId) |
667 | 108 | #define FLOATING_TYPE(Id, SingletonId) |
668 | 108 | #define BUILTIN_TYPE(Id, SingletonId) \ |
669 | 54 | case BuiltinType::Id: |
670 | 3 | #include "clang/AST/BuiltinTypes.def"3 |
671 | 3 | // Misc other stuff which doesn't make sense here. |
672 | 3 | return false; |
673 | 51 | |
674 | 226 | case BuiltinType::UInt: |
675 | 226 | case BuiltinType::Int: |
676 | 226 | case BuiltinType::Float: |
677 | 226 | case BuiltinType::Double: |
678 | 226 | LM.setKind(LengthModifier::None); |
679 | 226 | break; |
680 | 226 | |
681 | 51 | case BuiltinType::Char_U: |
682 | 51 | case BuiltinType::UChar: |
683 | 51 | case BuiltinType::Char_S: |
684 | 51 | case BuiltinType::SChar: |
685 | 51 | LM.setKind(LengthModifier::AsChar); |
686 | 51 | break; |
687 | 51 | |
688 | 54 | case BuiltinType::Short: |
689 | 54 | case BuiltinType::UShort: |
690 | 54 | LM.setKind(LengthModifier::AsShort); |
691 | 54 | break; |
692 | 54 | |
693 | 350 | case BuiltinType::Long: |
694 | 350 | case BuiltinType::ULong: |
695 | 350 | LM.setKind(LengthModifier::AsLong); |
696 | 350 | break; |
697 | 350 | |
698 | 31 | case BuiltinType::LongLong: |
699 | 31 | case BuiltinType::ULongLong: |
700 | 31 | LM.setKind(LengthModifier::AsLongLong); |
701 | 31 | break; |
702 | 31 | |
703 | 12 | case BuiltinType::LongDouble: |
704 | 12 | LM.setKind(LengthModifier::AsLongDouble); |
705 | 12 | break; |
706 | 724 | } |
707 | 724 | |
708 | 724 | // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. |
709 | 724 | if (724 isa<TypedefType>(QT) && 724 (LangOpt.C99 || 131 LangOpt.CPlusPlus1116 )) |
710 | 121 | namedTypeToLengthModifier(QT, LM); |
711 | 724 | |
712 | 724 | // If fixing the length modifier was enough, we might be done. |
713 | 724 | if (hasValidLengthModifier(Ctx.getTargetInfo())724 ) { |
714 | 659 | // If we're going to offer a fix anyway, make sure the sign matches. |
715 | 659 | switch (CS.getKind()) { |
716 | 125 | case ConversionSpecifier::uArg: |
717 | 125 | case ConversionSpecifier::UArg: |
718 | 125 | if (QT->isSignedIntegerType()) |
719 | 25 | CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg); |
720 | 125 | break; |
721 | 254 | case ConversionSpecifier::dArg: |
722 | 254 | case ConversionSpecifier::DArg: |
723 | 254 | case ConversionSpecifier::iArg: |
724 | 254 | if (QT->isUnsignedIntegerType() && 254 !HasPlusPrefix107 ) |
725 | 104 | CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg); |
726 | 254 | break; |
727 | 280 | default: |
728 | 280 | // Other specifiers do not have signed/unsigned variants. |
729 | 280 | break; |
730 | 659 | } |
731 | 659 | |
732 | 659 | const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral); |
733 | 659 | if (ATR.isValid() && 659 ATR.matchesType(Ctx, QT)659 ) |
734 | 434 | return true; |
735 | 290 | } |
736 | 290 | |
737 | 290 | // Set conversion specifier and disable any flags which do not apply to it. |
738 | 290 | // Let typedefs to char fall through to int, as %c is silly for uint8_t. |
739 | 290 | if (290 !isa<TypedefType>(QT) && 290 QT->isCharType()263 ) { |
740 | 28 | CS.setKind(ConversionSpecifier::cArg); |
741 | 28 | LM.setKind(LengthModifier::None); |
742 | 28 | Precision.setHowSpecified(OptionalAmount::NotSpecified); |
743 | 28 | HasAlternativeForm = 0; |
744 | 28 | HasLeadingZeroes = 0; |
745 | 28 | HasPlusPrefix = 0; |
746 | 28 | } |
747 | 290 | // Test for Floating type first as LongDouble can pass isUnsignedIntegerType |
748 | 262 | else if (262 QT->isRealFloatingType()262 ) { |
749 | 38 | CS.setKind(ConversionSpecifier::fArg); |
750 | 38 | } |
751 | 224 | else if (224 QT->isSignedIntegerType()224 ) { |
752 | 173 | CS.setKind(ConversionSpecifier::dArg); |
753 | 173 | HasAlternativeForm = 0; |
754 | 173 | } |
755 | 51 | else if (51 QT->isUnsignedIntegerType()51 ) { |
756 | 51 | CS.setKind(ConversionSpecifier::uArg); |
757 | 51 | HasAlternativeForm = 0; |
758 | 51 | HasPlusPrefix = 0; |
759 | 51 | } else { |
760 | 0 | llvm_unreachable("Unexpected type"); |
761 | 262 | } |
762 | 290 | |
763 | 290 | return true; |
764 | 290 | } |
765 | | |
766 | 869 | void PrintfSpecifier::toString(raw_ostream &os) const { |
767 | 869 | // Whilst some features have no defined order, we are using the order |
768 | 869 | // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1) |
769 | 869 | os << "%"; |
770 | 869 | |
771 | 869 | // Positional args |
772 | 869 | if (usesPositionalArg()869 ) { |
773 | 7 | os << getPositionalArgIndex() << "$"; |
774 | 7 | } |
775 | 869 | |
776 | 869 | // Conversion flags |
777 | 869 | if (IsLeftJustified869 ) os << "-"0 ; |
778 | 869 | if (HasPlusPrefix869 ) os << "+"3 ; |
779 | 869 | if (HasSpacePrefix869 ) os << " "0 ; |
780 | 869 | if (HasAlternativeForm869 ) os << "#"0 ; |
781 | 869 | if (HasLeadingZeroes869 ) os << "0"23 ; |
782 | 869 | |
783 | 869 | // Minimum field width |
784 | 869 | FieldWidth.toString(os); |
785 | 869 | // Precision |
786 | 869 | Precision.toString(os); |
787 | 869 | // Length modifier |
788 | 869 | os << LM.toString(); |
789 | 869 | // Conversion specifier |
790 | 869 | os << CS.toString(); |
791 | 869 | } |
792 | | |
793 | 105k | bool PrintfSpecifier::hasValidPlusPrefix() const { |
794 | 105k | if (!HasPlusPrefix) |
795 | 105k | return true; |
796 | 57 | |
797 | 57 | // The plus prefix only makes sense for signed conversions |
798 | 57 | switch (CS.getKind()) { |
799 | 52 | case ConversionSpecifier::dArg: |
800 | 52 | case ConversionSpecifier::DArg: |
801 | 52 | case ConversionSpecifier::iArg: |
802 | 52 | case ConversionSpecifier::fArg: |
803 | 52 | case ConversionSpecifier::FArg: |
804 | 52 | case ConversionSpecifier::eArg: |
805 | 52 | case ConversionSpecifier::EArg: |
806 | 52 | case ConversionSpecifier::gArg: |
807 | 52 | case ConversionSpecifier::GArg: |
808 | 52 | case ConversionSpecifier::aArg: |
809 | 52 | case ConversionSpecifier::AArg: |
810 | 52 | case ConversionSpecifier::FreeBSDrArg: |
811 | 52 | case ConversionSpecifier::FreeBSDyArg: |
812 | 52 | return true; |
813 | 52 | |
814 | 5 | default: |
815 | 5 | return false; |
816 | 0 | } |
817 | 0 | } |
818 | | |
819 | 105k | bool PrintfSpecifier::hasValidAlternativeForm() const { |
820 | 105k | if (!HasAlternativeForm) |
821 | 105k | return true; |
822 | 53 | |
823 | 53 | // Alternate form flag only valid with the oxXaAeEfFgG conversions |
824 | 53 | switch (CS.getKind()) { |
825 | 48 | case ConversionSpecifier::oArg: |
826 | 48 | case ConversionSpecifier::OArg: |
827 | 48 | case ConversionSpecifier::xArg: |
828 | 48 | case ConversionSpecifier::XArg: |
829 | 48 | case ConversionSpecifier::aArg: |
830 | 48 | case ConversionSpecifier::AArg: |
831 | 48 | case ConversionSpecifier::eArg: |
832 | 48 | case ConversionSpecifier::EArg: |
833 | 48 | case ConversionSpecifier::fArg: |
834 | 48 | case ConversionSpecifier::FArg: |
835 | 48 | case ConversionSpecifier::gArg: |
836 | 48 | case ConversionSpecifier::GArg: |
837 | 48 | case ConversionSpecifier::FreeBSDrArg: |
838 | 48 | case ConversionSpecifier::FreeBSDyArg: |
839 | 48 | return true; |
840 | 48 | |
841 | 5 | default: |
842 | 5 | return false; |
843 | 0 | } |
844 | 0 | } |
845 | | |
846 | 105k | bool PrintfSpecifier::hasValidLeadingZeros() const { |
847 | 105k | if (!HasLeadingZeroes) |
848 | 86.4k | return true; |
849 | 18.6k | |
850 | 18.6k | // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions |
851 | 18.6k | switch (CS.getKind()) { |
852 | 18.6k | case ConversionSpecifier::dArg: |
853 | 18.6k | case ConversionSpecifier::DArg: |
854 | 18.6k | case ConversionSpecifier::iArg: |
855 | 18.6k | case ConversionSpecifier::oArg: |
856 | 18.6k | case ConversionSpecifier::OArg: |
857 | 18.6k | case ConversionSpecifier::uArg: |
858 | 18.6k | case ConversionSpecifier::UArg: |
859 | 18.6k | case ConversionSpecifier::xArg: |
860 | 18.6k | case ConversionSpecifier::XArg: |
861 | 18.6k | case ConversionSpecifier::aArg: |
862 | 18.6k | case ConversionSpecifier::AArg: |
863 | 18.6k | case ConversionSpecifier::eArg: |
864 | 18.6k | case ConversionSpecifier::EArg: |
865 | 18.6k | case ConversionSpecifier::fArg: |
866 | 18.6k | case ConversionSpecifier::FArg: |
867 | 18.6k | case ConversionSpecifier::gArg: |
868 | 18.6k | case ConversionSpecifier::GArg: |
869 | 18.6k | case ConversionSpecifier::FreeBSDrArg: |
870 | 18.6k | case ConversionSpecifier::FreeBSDyArg: |
871 | 18.6k | return true; |
872 | 18.6k | |
873 | 11 | default: |
874 | 11 | return false; |
875 | 0 | } |
876 | 0 | } |
877 | | |
878 | 105k | bool PrintfSpecifier::hasValidSpacePrefix() const { |
879 | 105k | if (!HasSpacePrefix) |
880 | 105k | return true; |
881 | 39 | |
882 | 39 | // The space prefix only makes sense for signed conversions |
883 | 39 | switch (CS.getKind()) { |
884 | 17 | case ConversionSpecifier::dArg: |
885 | 17 | case ConversionSpecifier::DArg: |
886 | 17 | case ConversionSpecifier::iArg: |
887 | 17 | case ConversionSpecifier::fArg: |
888 | 17 | case ConversionSpecifier::FArg: |
889 | 17 | case ConversionSpecifier::eArg: |
890 | 17 | case ConversionSpecifier::EArg: |
891 | 17 | case ConversionSpecifier::gArg: |
892 | 17 | case ConversionSpecifier::GArg: |
893 | 17 | case ConversionSpecifier::aArg: |
894 | 17 | case ConversionSpecifier::AArg: |
895 | 17 | case ConversionSpecifier::FreeBSDrArg: |
896 | 17 | case ConversionSpecifier::FreeBSDyArg: |
897 | 17 | return true; |
898 | 17 | |
899 | 22 | default: |
900 | 22 | return false; |
901 | 0 | } |
902 | 0 | } |
903 | | |
904 | 105k | bool PrintfSpecifier::hasValidLeftJustified() const { |
905 | 105k | if (!IsLeftJustified) |
906 | 104k | return true; |
907 | 340 | |
908 | 340 | // The left justified flag is valid for all conversions except n |
909 | 340 | switch (CS.getKind()) { |
910 | 2 | case ConversionSpecifier::nArg: |
911 | 2 | return false; |
912 | 340 | |
913 | 338 | default: |
914 | 338 | return true; |
915 | 0 | } |
916 | 0 | } |
917 | | |
918 | 105k | bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const { |
919 | 105k | if (!HasThousandsGrouping) |
920 | 105k | return true; |
921 | 14 | |
922 | 14 | switch (CS.getKind()) { |
923 | 12 | case ConversionSpecifier::dArg: |
924 | 12 | case ConversionSpecifier::DArg: |
925 | 12 | case ConversionSpecifier::iArg: |
926 | 12 | case ConversionSpecifier::uArg: |
927 | 12 | case ConversionSpecifier::UArg: |
928 | 12 | case ConversionSpecifier::fArg: |
929 | 12 | case ConversionSpecifier::FArg: |
930 | 12 | case ConversionSpecifier::gArg: |
931 | 12 | case ConversionSpecifier::GArg: |
932 | 12 | return true; |
933 | 2 | default: |
934 | 2 | return false; |
935 | 0 | } |
936 | 0 | } |
937 | | |
938 | 105k | bool PrintfSpecifier::hasValidPrecision() const { |
939 | 105k | if (Precision.getHowSpecified() == OptionalAmount::NotSpecified) |
940 | 101k | return true; |
941 | 3.95k | |
942 | 3.95k | // Precision is only valid with the diouxXaAeEfFgGsP conversions |
943 | 3.95k | switch (CS.getKind()) { |
944 | 3.93k | case ConversionSpecifier::dArg: |
945 | 3.93k | case ConversionSpecifier::DArg: |
946 | 3.93k | case ConversionSpecifier::iArg: |
947 | 3.93k | case ConversionSpecifier::oArg: |
948 | 3.93k | case ConversionSpecifier::OArg: |
949 | 3.93k | case ConversionSpecifier::uArg: |
950 | 3.93k | case ConversionSpecifier::UArg: |
951 | 3.93k | case ConversionSpecifier::xArg: |
952 | 3.93k | case ConversionSpecifier::XArg: |
953 | 3.93k | case ConversionSpecifier::aArg: |
954 | 3.93k | case ConversionSpecifier::AArg: |
955 | 3.93k | case ConversionSpecifier::eArg: |
956 | 3.93k | case ConversionSpecifier::EArg: |
957 | 3.93k | case ConversionSpecifier::fArg: |
958 | 3.93k | case ConversionSpecifier::FArg: |
959 | 3.93k | case ConversionSpecifier::gArg: |
960 | 3.93k | case ConversionSpecifier::GArg: |
961 | 3.93k | case ConversionSpecifier::sArg: |
962 | 3.93k | case ConversionSpecifier::FreeBSDrArg: |
963 | 3.93k | case ConversionSpecifier::FreeBSDyArg: |
964 | 3.93k | case ConversionSpecifier::PArg: |
965 | 3.93k | return true; |
966 | 3.93k | |
967 | 13 | default: |
968 | 13 | return false; |
969 | 0 | } |
970 | 0 | } |
971 | 105k | bool PrintfSpecifier::hasValidFieldWidth() const { |
972 | 105k | if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified) |
973 | 83.2k | return true; |
974 | 21.7k | |
975 | 21.7k | // The field width is valid for all conversions except n |
976 | 21.7k | switch (CS.getKind()) { |
977 | 2 | case ConversionSpecifier::nArg: |
978 | 2 | return false; |
979 | 21.7k | |
980 | 21.7k | default: |
981 | 21.7k | return true; |
982 | 0 | } |
983 | 0 | } |