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