blob: 558d38af0c6e94672d846df8f9dcf210d85ad35b [file] [log] [blame]
Ted Kremenek8f0a1c72010-01-27 23:43:25 +00001//= PrintfFormatStrings.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/PrintfFormatString.h"
Ted Kremenek33567d22010-01-29 22:59:32 +000016#include "clang/AST/ASTContext.h"
Tom Care3bfc5f42010-06-09 04:11:11 +000017#include "clang/AST/Type.h"
18#include "llvm/Support/raw_ostream.h"
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000019
Ted Kremenek33567d22010-01-29 22:59:32 +000020using clang::analyze_printf::ArgTypeResult;
Ted Kremenekefaff192010-02-27 01:41:03 +000021using clang::analyze_printf::FormatSpecifier;
Ted Kremenek74d56a12010-02-04 20:46:58 +000022using clang::analyze_printf::FormatStringHandler;
Ted Kremenekefaff192010-02-27 01:41:03 +000023using clang::analyze_printf::OptionalAmount;
24using clang::analyze_printf::PositionContext;
Tom Care3bfc5f42010-06-09 04:11:11 +000025using clang::analyze_printf::ConversionSpecifier;
26using clang::analyze_printf::LengthModifier;
Ted Kremenekefaff192010-02-27 01:41:03 +000027
Ted Kremenek808015a2010-01-29 03:16:21 +000028using namespace clang;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000029
30namespace {
31class FormatSpecifierResult {
32 FormatSpecifier FS;
33 const char *Start;
Ted Kremenek26ac2e02010-01-29 02:40:24 +000034 bool Stop;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000035public:
Ted Kremenek26ac2e02010-01-29 02:40:24 +000036 FormatSpecifierResult(bool stop = false)
37 : Start(0), Stop(stop) {}
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000038 FormatSpecifierResult(const char *start,
Ted Kremenekd2dcece2010-01-28 02:02:59 +000039 const FormatSpecifier &fs)
Ted Kremenek26ac2e02010-01-29 02:40:24 +000040 : FS(fs), Start(start), Stop(false) {}
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000041
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000042 const char *getStart() const { return Start; }
Ted Kremenek26ac2e02010-01-29 02:40:24 +000043 bool shouldStop() const { return Stop; }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000044 bool hasValue() const { return Start != 0; }
45 const FormatSpecifier &getValue() const {
46 assert(hasValue());
47 return FS;
48 }
Ted Kremenekd2dcece2010-01-28 02:02:59 +000049 const FormatSpecifier &getValue() { return FS; }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000050};
51} // end anonymous namespace
52
53template <typename T>
54class UpdateOnReturn {
55 T &ValueToUpdate;
56 const T &ValueToCopy;
57public:
58 UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
59 : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000060
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000061 ~UpdateOnReturn() {
62 ValueToUpdate = ValueToCopy;
63 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000064};
65
66//===----------------------------------------------------------------------===//
67// Methods for parsing format strings.
68//===----------------------------------------------------------------------===//
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000069
Ted Kremenekefaff192010-02-27 01:41:03 +000070static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000071 const char *I = Beg;
72 UpdateOnReturn <const char*> UpdateBeg(Beg, I);
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000073
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000074 unsigned accumulator = 0;
Ted Kremenekd49d8772010-03-01 19:22:33 +000075 bool hasDigits = false;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000076
77 for ( ; I != E; ++I) {
78 char c = *I;
79 if (c >= '0' && c <= '9') {
Ted Kremenekd49d8772010-03-01 19:22:33 +000080 hasDigits = true;
Ted Kremenekfdb703a2010-03-25 03:59:09 +000081 accumulator = (accumulator * 10) + (c - '0');
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000082 continue;
83 }
84
Ted Kremenekd49d8772010-03-01 19:22:33 +000085 if (hasDigits)
Tom Caree4ee9662010-06-17 19:00:27 +000086 return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg,
87 false);
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000088
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000089 break;
90 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000091
92 return OptionalAmount();
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000093}
94
Ted Kremenekefaff192010-02-27 01:41:03 +000095static OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
96 unsigned &argIndex) {
97 if (*Beg == '*') {
98 ++Beg;
Tom Caree4ee9662010-06-17 19:00:27 +000099 return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
Ted Kremenekefaff192010-02-27 01:41:03 +0000100 }
101
102 return ParseAmount(Beg, E);
103}
104
105static OptionalAmount ParsePositionAmount(FormatStringHandler &H,
106 const char *Start,
107 const char *&Beg, const char *E,
108 PositionContext p) {
109 if (*Beg == '*') {
110 const char *I = Beg + 1;
111 const OptionalAmount &Amt = ParseAmount(I, E);
112
113 if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
114 H.HandleInvalidPosition(Beg, I - Beg, p);
115 return OptionalAmount(false);
116 }
117
118 if (I== E) {
119 // No more characters left?
120 H.HandleIncompleteFormatSpecifier(Start, E - Start);
121 return OptionalAmount(false);
122 }
123
Ted Kremenekd49d8772010-03-01 19:22:33 +0000124 assert(Amt.getHowSpecified() == OptionalAmount::Constant);
125
Ted Kremenekefaff192010-02-27 01:41:03 +0000126 if (*I == '$') {
Tom Care3bfc5f42010-06-09 04:11:11 +0000127 // Handle positional arguments
128
Ted Kremenekd49d8772010-03-01 19:22:33 +0000129 // Special case: '*0$', since this is an easy mistake.
130 if (Amt.getConstantAmount() == 0) {
131 H.HandleZeroPosition(Beg, I - Beg + 1);
132 return OptionalAmount(false);
133 }
134
Ted Kremenekefaff192010-02-27 01:41:03 +0000135 const char *Tmp = Beg;
136 Beg = ++I;
Ted Kremenekd49d8772010-03-01 19:22:33 +0000137
Ted Kremenekefaff192010-02-27 01:41:03 +0000138 return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,
Tom Caree4ee9662010-06-17 19:00:27 +0000139 Tmp, 0, true);
Ted Kremenekefaff192010-02-27 01:41:03 +0000140 }
141
142 H.HandleInvalidPosition(Beg, I - Beg, p);
143 return OptionalAmount(false);
144 }
145
146 return ParseAmount(Beg, E);
147}
148
149static bool ParsePrecision(FormatStringHandler &H, FormatSpecifier &FS,
150 const char *Start, const char *&Beg, const char *E,
151 unsigned *argIndex) {
152 if (argIndex) {
153 FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
154 }
155 else {
156 const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
157 analyze_printf::PrecisionPos);
158 if (Amt.isInvalid())
159 return true;
160 FS.setPrecision(Amt);
161 }
162 return false;
163}
164
165static bool ParseFieldWidth(FormatStringHandler &H, FormatSpecifier &FS,
166 const char *Start, const char *&Beg, const char *E,
167 unsigned *argIndex) {
168 // FIXME: Support negative field widths.
169 if (argIndex) {
170 FS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
171 }
172 else {
173 const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
174 analyze_printf::FieldWidthPos);
175 if (Amt.isInvalid())
176 return true;
177 FS.setFieldWidth(Amt);
178 }
179 return false;
180}
181
Ted Kremenekefaff192010-02-27 01:41:03 +0000182static bool ParseArgPosition(FormatStringHandler &H,
183 FormatSpecifier &FS, const char *Start,
184 const char *&Beg, const char *E) {
185
186 using namespace clang::analyze_printf;
187 const char *I = Beg;
188
189 const OptionalAmount &Amt = ParseAmount(I, E);
190
191 if (I == E) {
192 // No more characters left?
193 H.HandleIncompleteFormatSpecifier(Start, E - Start);
194 return true;
195 }
196
197 if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
Ted Kremenekd49d8772010-03-01 19:22:33 +0000198 // Special case: '%0$', since this is an easy mistake.
199 if (Amt.getConstantAmount() == 0) {
200 H.HandleZeroPosition(Start, I - Start);
201 return true;
202 }
203
Ted Kremenekefaff192010-02-27 01:41:03 +0000204 FS.setArgIndex(Amt.getConstantAmount() - 1);
205 FS.setUsesPositionalArg();
206 // Update the caller's pointer if we decided to consume
207 // these characters.
208 Beg = I;
209 return false;
210 }
211
Ted Kremenekefaff192010-02-27 01:41:03 +0000212 return false;
213}
214
Ted Kremenek808015a2010-01-29 03:16:21 +0000215static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
Ted Kremenek74d56a12010-02-04 20:46:58 +0000216 const char *&Beg,
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000217 const char *E,
218 unsigned &argIndex) {
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000219
Ted Kremenek4b220fa2010-01-29 02:13:53 +0000220 using namespace clang::analyze_printf;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000221
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000222 const char *I = Beg;
Ted Kremenekc7ae51a2010-01-28 00:02:05 +0000223 const char *Start = 0;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000224 UpdateOnReturn <const char*> UpdateBeg(Beg, I);
225
226 // Look for a '%' character that indicates the start of a format specifier.
Ted Kremeneke729acb2010-01-28 23:56:52 +0000227 for ( ; I != E ; ++I) {
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000228 char c = *I;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000229 if (c == '\0') {
230 // Detect spurious null characters, which are likely errors.
231 H.HandleNullChar(I);
232 return true;
233 }
234 if (c == '%') {
Ted Kremeneke729acb2010-01-28 23:56:52 +0000235 Start = I++; // Record the start of the format specifier.
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000236 break;
237 }
238 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000239
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000240 // No format specifier found?
241 if (!Start)
242 return false;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000243
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000244 if (I == E) {
245 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000246 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000247 return true;
248 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000249
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000250 FormatSpecifier FS;
Ted Kremenekefaff192010-02-27 01:41:03 +0000251 if (ParseArgPosition(H, FS, Start, I, E))
252 return true;
253
254 if (I == E) {
255 // No more characters left?
256 H.HandleIncompleteFormatSpecifier(Start, E - Start);
257 return true;
258 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000259
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000260 // Look for flags (if any).
261 bool hasMore = true;
262 for ( ; I != E; ++I) {
263 switch (*I) {
264 default: hasMore = false; break;
Tom Caree4ee9662010-06-17 19:00:27 +0000265 case '-': FS.setIsLeftJustified(I); break;
266 case '+': FS.setHasPlusPrefix(I); break;
267 case ' ': FS.setHasSpacePrefix(I); break;
268 case '#': FS.setHasAlternativeForm(I); break;
269 case '0': FS.setHasLeadingZeros(I); break;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000270 }
271 if (!hasMore)
272 break;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000273 }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000274
275 if (I == E) {
276 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000277 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000278 return true;
279 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000280
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000281 // Look for the field width (if any).
Ted Kremenekefaff192010-02-27 01:41:03 +0000282 if (ParseFieldWidth(H, FS, Start, I, E,
283 FS.usesPositionalArg() ? 0 : &argIndex))
284 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000285
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000286 if (I == E) {
287 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000288 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000289 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000290 }
291
292 // Look for the precision (if any).
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000293 if (*I == '.') {
Ted Kremenek808015a2010-01-29 03:16:21 +0000294 ++I;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000295 if (I == E) {
Ted Kremenek808015a2010-01-29 03:16:21 +0000296 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000297 return true;
298 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000299
Ted Kremenekefaff192010-02-27 01:41:03 +0000300 if (ParsePrecision(H, FS, Start, I, E,
301 FS.usesPositionalArg() ? 0 : &argIndex))
302 return true;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000303
304 if (I == E) {
305 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000306 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000307 return true;
308 }
309 }
310
311 // Look for the length modifier.
Tom Care3bfc5f42010-06-09 04:11:11 +0000312 LengthModifier::Kind lmKind = LengthModifier::None;
313 const char *lmPosition = I;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000314 switch (*I) {
315 default:
316 break;
317 case 'h':
318 ++I;
Tom Care3bfc5f42010-06-09 04:11:11 +0000319 lmKind = (I != E && *I == 'h') ?
320 ++I, LengthModifier::AsChar : LengthModifier::AsShort;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000321 break;
322 case 'l':
323 ++I;
Tom Care3bfc5f42010-06-09 04:11:11 +0000324 lmKind = (I != E && *I == 'l') ?
325 ++I, LengthModifier::AsLongLong : LengthModifier::AsLong;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000326 break;
Tom Care3bfc5f42010-06-09 04:11:11 +0000327 case 'j': lmKind = LengthModifier::AsIntMax; ++I; break;
328 case 'z': lmKind = LengthModifier::AsSizeT; ++I; break;
329 case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break;
330 case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
331 case 'q': lmKind = LengthModifier::AsLongLong; ++I; break;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000332 }
Tom Care3bfc5f42010-06-09 04:11:11 +0000333 LengthModifier lm(lmPosition, lmKind);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000334 FS.setLengthModifier(lm);
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000335
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000336 if (I == E) {
337 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000338 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000339 return true;
340 }
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000341
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000342 if (*I == '\0') {
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000343 // Detect spurious null characters, which are likely errors.
344 H.HandleNullChar(I);
345 return true;
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000346 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000347
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000348 // Finally, look for the conversion specifier.
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000349 const char *conversionPosition = I++;
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000350 ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000351 switch (*conversionPosition) {
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000352 default:
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000353 break;
Ted Kremenekc7cbb9b2010-01-28 00:55:28 +0000354 // C99: 7.19.6.1 (section 8).
Ted Kremenek87260c72010-02-24 00:05:54 +0000355 case '%': k = ConversionSpecifier::PercentArg; break;
356 case 'A': k = ConversionSpecifier::AArg; break;
357 case 'E': k = ConversionSpecifier::EArg; break;
358 case 'F': k = ConversionSpecifier::FArg; break;
359 case 'G': k = ConversionSpecifier::GArg; break;
360 case 'X': k = ConversionSpecifier::XArg; break;
361 case 'a': k = ConversionSpecifier::aArg; break;
362 case 'c': k = ConversionSpecifier::IntAsCharArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000363 case 'd': k = ConversionSpecifier::dArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000364 case 'e': k = ConversionSpecifier::eArg; break;
365 case 'f': k = ConversionSpecifier::fArg; break;
366 case 'g': k = ConversionSpecifier::gArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000367 case 'i': k = ConversionSpecifier::iArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000368 case 'n': k = ConversionSpecifier::OutIntPtrArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000369 case 'o': k = ConversionSpecifier::oArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000370 case 'p': k = ConversionSpecifier::VoidPtrArg; break;
371 case 's': k = ConversionSpecifier::CStrArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000372 case 'u': k = ConversionSpecifier::uArg; break;
373 case 'x': k = ConversionSpecifier::xArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000374 // Mac OS X (unicode) specific
375 case 'C': k = ConversionSpecifier::CArg; break;
376 case 'S': k = ConversionSpecifier::UnicodeStrArg; break;
Ted Kremenekc7cbb9b2010-01-28 00:55:28 +0000377 // Objective-C.
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000378 case '@': k = ConversionSpecifier::ObjCObjArg; break;
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000379 // Glibc specific.
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000380 case 'm': k = ConversionSpecifier::PrintErrno; break;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000381 }
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000382 ConversionSpecifier CS(conversionPosition, k);
383 FS.setConversionSpecifier(CS);
Ted Kremenekefaff192010-02-27 01:41:03 +0000384 if (CS.consumesDataArgument() && !FS.usesPositionalArg())
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000385 FS.setArgIndex(argIndex++);
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000386
387 if (k == ConversionSpecifier::InvalidSpecifier) {
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000388 // Assume the conversion takes one argument.
389 return !H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg);
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000390 }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000391 return FormatSpecifierResult(Start, FS);
392}
393
Ted Kremenek74d56a12010-02-04 20:46:58 +0000394bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H,
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000395 const char *I, const char *E) {
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000396
397 unsigned argIndex = 0;
398
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000399 // Keep looking for a format specifier until we have exhausted the string.
400 while (I != E) {
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000401 const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E, argIndex);
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000402 // Did a fail-stop error of any kind occur when parsing the specifier?
403 // If so, don't do any more processing.
404 if (FSR.shouldStop())
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000405 return true;;
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000406 // Did we exhaust the string or encounter an error that
407 // we can recover from?
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000408 if (!FSR.hasValue())
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000409 continue;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000410 // We have a format specifier. Pass it to the callback.
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000411 if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(),
412 I - FSR.getStart()))
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000413 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000414 }
415 assert(I == E && "Format string not exhausted");
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000416 return false;
417}
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000418
419FormatStringHandler::~FormatStringHandler() {}
Ted Kremenek33567d22010-01-29 22:59:32 +0000420
421//===----------------------------------------------------------------------===//
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000422// Methods on ArgTypeResult.
423//===----------------------------------------------------------------------===//
424
425bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
Ted Kremenek13927a42010-06-16 21:23:04 +0000426 switch (K) {
427 case InvalidTy:
428 assert(false && "ArgTypeResult must be valid");
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000429 return true;
430
Ted Kremenek13927a42010-06-16 21:23:04 +0000431 case UnknownTy:
432 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000433
Ted Kremenek13927a42010-06-16 21:23:04 +0000434 case SpecificTy: {
435 argTy = C.getCanonicalType(argTy).getUnqualifiedType();
436 if (T == argTy)
437 return true;
438 if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
439 switch (BT->getKind()) {
440 default:
441 break;
442 case BuiltinType::Char_S:
443 case BuiltinType::SChar:
444 return T == C.UnsignedCharTy;
445 case BuiltinType::Char_U:
446 case BuiltinType::UChar:
447 return T == C.SignedCharTy;
448 case BuiltinType::Short:
449 return T == C.UnsignedShortTy;
450 case BuiltinType::UShort:
451 return T == C.ShortTy;
452 case BuiltinType::Int:
453 return T == C.UnsignedIntTy;
454 case BuiltinType::UInt:
455 return T == C.IntTy;
456 case BuiltinType::Long:
457 return T == C.UnsignedLongTy;
458 case BuiltinType::ULong:
459 return T == C.LongTy;
460 case BuiltinType::LongLong:
461 return T == C.UnsignedLongLongTy;
462 case BuiltinType::ULongLong:
463 return T == C.LongLongTy;
464 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000465 return false;
Ted Kremenek13927a42010-06-16 21:23:04 +0000466 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000467
Ted Kremenek13927a42010-06-16 21:23:04 +0000468 case CStrTy: {
469 const PointerType *PT = argTy->getAs<PointerType>();
470 if (!PT)
471 return false;
472 QualType pointeeTy = PT->getPointeeType();
473 if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
474 switch (BT->getKind()) {
475 case BuiltinType::Void:
476 case BuiltinType::Char_U:
477 case BuiltinType::UChar:
478 case BuiltinType::Char_S:
479 case BuiltinType::SChar:
480 return true;
481 default:
482 break;
483 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000484
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000485 return false;
Ted Kremenek13927a42010-06-16 21:23:04 +0000486 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000487
Ted Kremenek13927a42010-06-16 21:23:04 +0000488 case WCStrTy: {
489 const PointerType *PT = argTy->getAs<PointerType>();
490 if (!PT)
491 return false;
492 QualType pointeeTy =
493 C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
494 return pointeeTy == C.getWCharType();
495 }
Ted Kremenek87260c72010-02-24 00:05:54 +0000496
Ted Kremenek13927a42010-06-16 21:23:04 +0000497 case CPointerTy:
498 return argTy->getAs<PointerType>() != NULL ||
499 argTy->getAs<ObjCObjectPointerType>() != NULL;
500
501 case ObjCPointerTy:
502 return argTy->getAs<ObjCObjectPointerType>() != NULL;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000503 }
504
Ted Kremenek13927a42010-06-16 21:23:04 +0000505 // FIXME: Should be unreachable, but Clang is currently emitting
506 // a warning.
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000507 return false;
508}
509
510QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
Ted Kremenek13927a42010-06-16 21:23:04 +0000511 switch (K) {
512 case InvalidTy:
513 assert(false && "No representative type for Invalid ArgTypeResult");
514 // Fall-through.
515 case UnknownTy:
516 return QualType();
517 case SpecificTy:
518 return T;
519 case CStrTy:
520 return C.getPointerType(C.CharTy);
521 case WCStrTy:
522 return C.getPointerType(C.getWCharType());
523 case ObjCPointerTy:
524 return C.ObjCBuiltinIdTy;
525 case CPointerTy:
526 return C.VoidPtrTy;
527 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000528
Ted Kremenek13927a42010-06-16 21:23:04 +0000529 // FIXME: Should be unreachable, but Clang is currently emitting
530 // a warning.
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000531 return QualType();
532}
533
534//===----------------------------------------------------------------------===//
535// Methods on OptionalAmount.
536//===----------------------------------------------------------------------===//
537
538ArgTypeResult OptionalAmount::getArgType(ASTContext &Ctx) const {
539 return Ctx.IntTy;
540}
541
542//===----------------------------------------------------------------------===//
Tom Care3bfc5f42010-06-09 04:11:11 +0000543// Methods on ConversionSpecifier.
544//===----------------------------------------------------------------------===//
545const char *ConversionSpecifier::toString() const {
546 switch (kind) {
547 case dArg: return "d";
548 case iArg: return "i";
549 case oArg: return "o";
550 case uArg: return "u";
551 case xArg: return "x";
552 case XArg: return "X";
553 case fArg: return "f";
554 case FArg: return "F";
555 case eArg: return "e";
556 case EArg: return "E";
557 case gArg: return "g";
558 case GArg: return "G";
559 case aArg: return "a";
560 case AArg: return "A";
561 case IntAsCharArg: return "c";
562 case CStrArg: return "s";
563 case VoidPtrArg: return "p";
564 case OutIntPtrArg: return "n";
565 case PercentArg: return "%";
566 case InvalidSpecifier: return NULL;
567
568 // MacOS X unicode extensions.
569 case CArg: return "C";
570 case UnicodeStrArg: return "S";
571
572 // Objective-C specific specifiers.
573 case ObjCObjArg: return "@";
574
575 // GlibC specific specifiers.
576 case PrintErrno: return "m";
577 }
578 return NULL;
579}
580
581//===----------------------------------------------------------------------===//
582// Methods on LengthModifier.
583//===----------------------------------------------------------------------===//
584
585const char *LengthModifier::toString() const {
586 switch (kind) {
587 case AsChar:
588 return "hh";
589 case AsShort:
590 return "h";
591 case AsLong: // or AsWideChar
592 return "l";
593 case AsLongLong:
594 return "ll";
595 case AsIntMax:
596 return "j";
597 case AsSizeT:
598 return "z";
599 case AsPtrDiff:
600 return "t";
601 case AsLongDouble:
602 return "L";
603 case None:
604 return "";
605 }
606 return NULL;
607}
608
609//===----------------------------------------------------------------------===//
610// Methods on OptionalAmount.
611//===----------------------------------------------------------------------===//
612
613void OptionalAmount::toString(llvm::raw_ostream &os) const {
614 switch (hs) {
615 case Invalid:
616 case NotSpecified:
617 return;
618 case Arg:
Tom Care4c602192010-06-18 03:02:16 +0000619 if (UsesDotPrefix)
620 os << ".";
Tom Care3bfc5f42010-06-09 04:11:11 +0000621 if (usesPositionalArg())
Tom Caree4ee9662010-06-17 19:00:27 +0000622 os << "*" << getPositionalArgIndex() << "$";
Tom Care3bfc5f42010-06-09 04:11:11 +0000623 else
Tom Caree4ee9662010-06-17 19:00:27 +0000624 os << "*";
Tom Care3bfc5f42010-06-09 04:11:11 +0000625 break;
626 case Constant:
Tom Care4c602192010-06-18 03:02:16 +0000627 if (UsesDotPrefix)
628 os << ".";
Tom Caree4ee9662010-06-17 19:00:27 +0000629 os << amt;
Tom Care3bfc5f42010-06-09 04:11:11 +0000630 break;
631 }
632}
633
634//===----------------------------------------------------------------------===//
Ted Kremenek33567d22010-01-29 22:59:32 +0000635// Methods on FormatSpecifier.
636//===----------------------------------------------------------------------===//
637
638ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const {
639 if (!CS.consumesDataArgument())
640 return ArgTypeResult::Invalid();
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000641
Ted Kremenek33567d22010-01-29 22:59:32 +0000642 if (CS.isIntArg())
Tom Care3bfc5f42010-06-09 04:11:11 +0000643 switch (LM.getKind()) {
644 case LengthModifier::AsLongDouble:
Ted Kremenek33567d22010-01-29 22:59:32 +0000645 return ArgTypeResult::Invalid();
Tom Care3bfc5f42010-06-09 04:11:11 +0000646 case LengthModifier::None: return Ctx.IntTy;
647 case LengthModifier::AsChar: return Ctx.SignedCharTy;
648 case LengthModifier::AsShort: return Ctx.ShortTy;
649 case LengthModifier::AsLong: return Ctx.LongTy;
650 case LengthModifier::AsLongLong: return Ctx.LongLongTy;
651 case LengthModifier::AsIntMax:
Ted Kremenek33567d22010-01-29 22:59:32 +0000652 // FIXME: Return unknown for now.
653 return ArgTypeResult();
Tom Care3bfc5f42010-06-09 04:11:11 +0000654 case LengthModifier::AsSizeT: return Ctx.getSizeType();
655 case LengthModifier::AsPtrDiff: return Ctx.getPointerDiffType();
Ted Kremenek33567d22010-01-29 22:59:32 +0000656 }
657
658 if (CS.isUIntArg())
Tom Care3bfc5f42010-06-09 04:11:11 +0000659 switch (LM.getKind()) {
660 case LengthModifier::AsLongDouble:
Ted Kremenek33567d22010-01-29 22:59:32 +0000661 return ArgTypeResult::Invalid();
Tom Care3bfc5f42010-06-09 04:11:11 +0000662 case LengthModifier::None: return Ctx.UnsignedIntTy;
663 case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
664 case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
665 case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
666 case LengthModifier::AsLongLong: return Ctx.UnsignedLongLongTy;
667 case LengthModifier::AsIntMax:
Ted Kremenek33567d22010-01-29 22:59:32 +0000668 // FIXME: Return unknown for now.
669 return ArgTypeResult();
Tom Care3bfc5f42010-06-09 04:11:11 +0000670 case LengthModifier::AsSizeT:
Ted Kremenek33567d22010-01-29 22:59:32 +0000671 // FIXME: How to get the corresponding unsigned
672 // version of size_t?
673 return ArgTypeResult();
Tom Care3bfc5f42010-06-09 04:11:11 +0000674 case LengthModifier::AsPtrDiff:
Ted Kremenek33567d22010-01-29 22:59:32 +0000675 // FIXME: How to get the corresponding unsigned
676 // version of ptrdiff_t?
677 return ArgTypeResult();
678 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000679
Ted Kremenekf911eba2010-02-01 23:23:50 +0000680 if (CS.isDoubleArg()) {
Tom Care3bfc5f42010-06-09 04:11:11 +0000681 if (LM.getKind() == LengthModifier::AsLongDouble)
Ted Kremenekf911eba2010-02-01 23:23:50 +0000682 return Ctx.LongDoubleTy;
Ted Kremenekc9a89fe2010-01-30 01:02:18 +0000683 return Ctx.DoubleTy;
Ted Kremenekf911eba2010-02-01 23:23:50 +0000684 }
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000685
Ted Kremenek87260c72010-02-24 00:05:54 +0000686 switch (CS.getKind()) {
687 case ConversionSpecifier::CStrArg:
Tom Care3bfc5f42010-06-09 04:11:11 +0000688 return ArgTypeResult(LM.getKind() == LengthModifier::AsWideChar ?
689 ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy);
Ted Kremenek87260c72010-02-24 00:05:54 +0000690 case ConversionSpecifier::UnicodeStrArg:
691 // FIXME: This appears to be Mac OS X specific.
692 return ArgTypeResult::WCStrTy;
693 case ConversionSpecifier::CArg:
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000694 return Ctx.WCharTy;
Ted Kremenek13927a42010-06-16 21:23:04 +0000695 case ConversionSpecifier::VoidPtrArg:
696 return ArgTypeResult::CPointerTy;
Ted Kremenek87260c72010-02-24 00:05:54 +0000697 default:
698 break;
699 }
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000700
Ted Kremenek33567d22010-01-29 22:59:32 +0000701 // FIXME: Handle other cases.
Ted Kremenek40888ad2010-01-29 23:00:35 +0000702 return ArgTypeResult();
Ted Kremenek33567d22010-01-29 22:59:32 +0000703}
704
Tom Care3bfc5f42010-06-09 04:11:11 +0000705bool FormatSpecifier::fixType(QualType QT) {
706 // Handle strings first (char *, wchar_t *)
707 if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
708 CS.setKind(ConversionSpecifier::CStrArg);
709
Tom Care876e9942010-06-11 04:22:02 +0000710 // Disable irrelevant flags
711 HasAlternativeForm = 0;
712 HasLeadingZeroes = 0;
713
Tom Care3bfc5f42010-06-09 04:11:11 +0000714 // Set the long length modifier for wide characters
715 if (QT->getPointeeType()->isWideCharType())
716 LM.setKind(LengthModifier::AsWideChar);
717
718 return true;
719 }
720
721 // We can only work with builtin types.
722 if (!QT->isBuiltinType())
723 return false;
724
725 // Everything else should be a base type
726 const BuiltinType *BT = QT->getAs<BuiltinType>();
Tom Care876e9942010-06-11 04:22:02 +0000727
Tom Care3bfc5f42010-06-09 04:11:11 +0000728 // Set length modifier
729 switch (BT->getKind()) {
730 default:
Tom Care876e9942010-06-11 04:22:02 +0000731 // The rest of the conversions are either optional or for non-builtin types
732 LM.setKind(LengthModifier::None);
Tom Care3bfc5f42010-06-09 04:11:11 +0000733 break;
Tom Care876e9942010-06-11 04:22:02 +0000734
Tom Care3bfc5f42010-06-09 04:11:11 +0000735 case BuiltinType::WChar:
736 case BuiltinType::Long:
737 case BuiltinType::ULong:
738 LM.setKind(LengthModifier::AsLong);
739 break;
740
741 case BuiltinType::LongLong:
742 case BuiltinType::ULongLong:
743 LM.setKind(LengthModifier::AsLongLong);
744 break;
745
746 case BuiltinType::LongDouble:
747 LM.setKind(LengthModifier::AsLongDouble);
748 break;
749 }
750
751 // Set conversion specifier and disable any flags which do not apply to it.
752 if (QT->isAnyCharacterType()) {
753 CS.setKind(ConversionSpecifier::IntAsCharArg);
754 Precision.setHowSpecified(OptionalAmount::NotSpecified);
755 HasAlternativeForm = 0;
756 HasLeadingZeroes = 0;
Tom Caree4ee9662010-06-17 19:00:27 +0000757 HasPlusPrefix = 0;
Tom Care3bfc5f42010-06-09 04:11:11 +0000758 }
759 // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
Douglas Gregor0c293ea2010-06-22 23:07:26 +0000760 else if (QT->isRealFloatingType()) {
Tom Care3bfc5f42010-06-09 04:11:11 +0000761 CS.setKind(ConversionSpecifier::fArg);
762 }
763 else if (QT->isPointerType()) {
764 CS.setKind(ConversionSpecifier::VoidPtrArg);
765 Precision.setHowSpecified(OptionalAmount::NotSpecified);
766 HasAlternativeForm = 0;
767 HasLeadingZeroes = 0;
Tom Caree4ee9662010-06-17 19:00:27 +0000768 HasPlusPrefix = 0;
Tom Care3bfc5f42010-06-09 04:11:11 +0000769 }
770 else if (QT->isSignedIntegerType()) {
771 CS.setKind(ConversionSpecifier::dArg);
772 HasAlternativeForm = 0;
773 }
Douglas Gregorc8c4b402010-06-09 05:25:34 +0000774 else if (QT->isUnsignedIntegerType()) {
Tom Care3bfc5f42010-06-09 04:11:11 +0000775 CS.setKind(ConversionSpecifier::uArg);
776 HasAlternativeForm = 0;
Tom Caree4ee9662010-06-17 19:00:27 +0000777 HasPlusPrefix = 0;
Tom Care3bfc5f42010-06-09 04:11:11 +0000778 }
779 else {
780 return false;
781 }
782
783 return true;
784}
785
786void FormatSpecifier::toString(llvm::raw_ostream &os) const {
787 // Whilst some features have no defined order, we are using the order
788 // appearing in the C99 standard (ISO/IEC 9899:1999 (E) ¤7.19.6.1)
789 os << "%";
790
791 // Positional args
792 if (usesPositionalArg()) {
793 os << getPositionalArgIndex() << "$";
794 }
795
796 // Conversion flags
797 if (IsLeftJustified) os << "-";
798 if (HasPlusPrefix) os << "+";
799 if (HasSpacePrefix) os << " ";
800 if (HasAlternativeForm) os << "#";
801 if (HasLeadingZeroes) os << "0";
802
803 // Minimum field width
804 FieldWidth.toString(os);
805 // Precision
806 Precision.toString(os);
807 // Length modifier
808 os << LM.toString();
809 // Conversion specifier
810 os << CS.toString();
811}
Tom Caree4ee9662010-06-17 19:00:27 +0000812
813bool FormatSpecifier::hasValidPlusPrefix() const {
814 if (!HasPlusPrefix)
815 return true;
816
817 // The plus prefix only makes sense for signed conversions
818 switch (CS.getKind()) {
819 case ConversionSpecifier::dArg:
820 case ConversionSpecifier::iArg:
821 case ConversionSpecifier::fArg:
822 case ConversionSpecifier::FArg:
823 case ConversionSpecifier::eArg:
824 case ConversionSpecifier::EArg:
825 case ConversionSpecifier::gArg:
826 case ConversionSpecifier::GArg:
827 case ConversionSpecifier::aArg:
828 case ConversionSpecifier::AArg:
829 return true;
830
831 default:
832 return false;
833 }
834}
835
836bool FormatSpecifier::hasValidAlternativeForm() const {
837 if (!HasAlternativeForm)
838 return true;
839
840 // Alternate form flag only valid with the oxaAeEfFgG conversions
841 switch (CS.getKind()) {
842 case ConversionSpecifier::oArg:
843 case ConversionSpecifier::xArg:
844 case ConversionSpecifier::aArg:
845 case ConversionSpecifier::AArg:
846 case ConversionSpecifier::eArg:
847 case ConversionSpecifier::EArg:
848 case ConversionSpecifier::fArg:
849 case ConversionSpecifier::FArg:
850 case ConversionSpecifier::gArg:
851 case ConversionSpecifier::GArg:
852 return true;
853
854 default:
855 return false;
856 }
857}
858
859bool FormatSpecifier::hasValidLeadingZeros() const {
860 if (!HasLeadingZeroes)
861 return true;
862
863 // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
864 switch (CS.getKind()) {
865 case ConversionSpecifier::dArg:
866 case ConversionSpecifier::iArg:
867 case ConversionSpecifier::oArg:
868 case ConversionSpecifier::uArg:
869 case ConversionSpecifier::xArg:
870 case ConversionSpecifier::XArg:
871 case ConversionSpecifier::aArg:
872 case ConversionSpecifier::AArg:
873 case ConversionSpecifier::eArg:
874 case ConversionSpecifier::EArg:
875 case ConversionSpecifier::fArg:
876 case ConversionSpecifier::FArg:
877 case ConversionSpecifier::gArg:
878 case ConversionSpecifier::GArg:
879 return true;
880
881 default:
882 return false;
883 }
884}
885
886bool FormatSpecifier::hasValidSpacePrefix() const {
887 if (!HasSpacePrefix)
888 return true;
889
890 // The space prefix only makes sense for signed conversions
891 switch (CS.getKind()) {
892 case ConversionSpecifier::dArg:
893 case ConversionSpecifier::iArg:
894 case ConversionSpecifier::fArg:
895 case ConversionSpecifier::FArg:
896 case ConversionSpecifier::eArg:
897 case ConversionSpecifier::EArg:
898 case ConversionSpecifier::gArg:
899 case ConversionSpecifier::GArg:
900 case ConversionSpecifier::aArg:
901 case ConversionSpecifier::AArg:
902 return true;
903
904 default:
905 return false;
906 }
907}
908
909bool FormatSpecifier::hasValidLeftJustified() const {
910 if (!IsLeftJustified)
911 return true;
912
913 // The left justified flag is valid for all conversions except n
914 switch (CS.getKind()) {
915 case ConversionSpecifier::OutIntPtrArg:
916 return false;
917
918 default:
919 return true;
920 }
921}
922
923bool FormatSpecifier::hasValidLengthModifier() const {
924 switch (LM.getKind()) {
925 case LengthModifier::None:
926 return true;
927
928 // Handle most integer flags
929 case LengthModifier::AsChar:
930 case LengthModifier::AsShort:
931 case LengthModifier::AsLongLong:
932 case LengthModifier::AsIntMax:
933 case LengthModifier::AsSizeT:
934 case LengthModifier::AsPtrDiff:
935 switch (CS.getKind()) {
936 case ConversionSpecifier::dArg:
937 case ConversionSpecifier::iArg:
938 case ConversionSpecifier::oArg:
939 case ConversionSpecifier::uArg:
940 case ConversionSpecifier::xArg:
941 case ConversionSpecifier::XArg:
942 case ConversionSpecifier::OutIntPtrArg:
943 return true;
944 default:
945 return false;
946 }
947
948 // Handle 'l' flag
949 case LengthModifier::AsLong:
950 switch (CS.getKind()) {
951 case ConversionSpecifier::dArg:
952 case ConversionSpecifier::iArg:
953 case ConversionSpecifier::oArg:
954 case ConversionSpecifier::uArg:
955 case ConversionSpecifier::xArg:
956 case ConversionSpecifier::XArg:
957 case ConversionSpecifier::aArg:
958 case ConversionSpecifier::AArg:
959 case ConversionSpecifier::fArg:
960 case ConversionSpecifier::FArg:
961 case ConversionSpecifier::eArg:
962 case ConversionSpecifier::EArg:
963 case ConversionSpecifier::gArg:
964 case ConversionSpecifier::GArg:
965 case ConversionSpecifier::OutIntPtrArg:
966 case ConversionSpecifier::IntAsCharArg:
967 case ConversionSpecifier::CStrArg:
968 return true;
969 default:
970 return false;
971 }
972
973 case LengthModifier::AsLongDouble:
974 switch (CS.getKind()) {
975 case ConversionSpecifier::aArg:
976 case ConversionSpecifier::AArg:
977 case ConversionSpecifier::fArg:
978 case ConversionSpecifier::FArg:
979 case ConversionSpecifier::eArg:
980 case ConversionSpecifier::EArg:
981 case ConversionSpecifier::gArg:
982 case ConversionSpecifier::GArg:
983 return true;
984 default:
985 return false;
986 }
987 }
988 return false;
989}
990
991bool FormatSpecifier::hasValidPrecision() const {
992 if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
993 return true;
994
995 // Precision is only valid with the diouxXaAeEfFgGs conversions
996 switch (CS.getKind()) {
997 case ConversionSpecifier::dArg:
998 case ConversionSpecifier::iArg:
999 case ConversionSpecifier::oArg:
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::CStrArg:
1012 return true;
1013
1014 default:
1015 return false;
1016 }
1017}
1018bool FormatSpecifier::hasValidFieldWidth() const {
1019 if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
1020 return true;
1021
1022 // The field width is valid for all conversions except n
1023 switch (CS.getKind()) {
1024 case ConversionSpecifier::OutIntPtrArg:
1025 return false;
1026
1027 default:
1028 return true;
1029 }
1030}