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