blob: de84af6a55ec8e2a5001d905cbacaec423fd8e35 [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 Care3bfc5f42010-06-09 04:11:11 +000086 return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, 0);
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000087
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000088 break;
89 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000090
91 return OptionalAmount();
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000092}
93
Ted Kremenekefaff192010-02-27 01:41:03 +000094static OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
95 unsigned &argIndex) {
96 if (*Beg == '*') {
97 ++Beg;
Tom Care3bfc5f42010-06-09 04:11:11 +000098 return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0);
Ted Kremenekefaff192010-02-27 01:41:03 +000099 }
100
101 return ParseAmount(Beg, E);
102}
103
104static OptionalAmount ParsePositionAmount(FormatStringHandler &H,
105 const char *Start,
106 const char *&Beg, const char *E,
107 PositionContext p) {
108 if (*Beg == '*') {
109 const char *I = Beg + 1;
110 const OptionalAmount &Amt = ParseAmount(I, E);
111
112 if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
113 H.HandleInvalidPosition(Beg, I - Beg, p);
114 return OptionalAmount(false);
115 }
116
117 if (I== E) {
118 // No more characters left?
119 H.HandleIncompleteFormatSpecifier(Start, E - Start);
120 return OptionalAmount(false);
121 }
122
Ted Kremenekd49d8772010-03-01 19:22:33 +0000123 assert(Amt.getHowSpecified() == OptionalAmount::Constant);
124
Ted Kremenekefaff192010-02-27 01:41:03 +0000125 if (*I == '$') {
Tom Care3bfc5f42010-06-09 04:11:11 +0000126 // Handle positional arguments
127
Ted Kremenekd49d8772010-03-01 19:22:33 +0000128 // Special case: '*0$', since this is an easy mistake.
129 if (Amt.getConstantAmount() == 0) {
130 H.HandleZeroPosition(Beg, I - Beg + 1);
131 return OptionalAmount(false);
132 }
133
Ted Kremenekefaff192010-02-27 01:41:03 +0000134 const char *Tmp = Beg;
135 Beg = ++I;
Ted Kremenekd49d8772010-03-01 19:22:33 +0000136
Ted Kremenekefaff192010-02-27 01:41:03 +0000137 return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,
Tom Care3bfc5f42010-06-09 04:11:11 +0000138 Tmp, 1);
Ted Kremenekefaff192010-02-27 01:41:03 +0000139 }
140
141 H.HandleInvalidPosition(Beg, I - Beg, p);
142 return OptionalAmount(false);
143 }
144
145 return ParseAmount(Beg, E);
146}
147
148static bool ParsePrecision(FormatStringHandler &H, FormatSpecifier &FS,
149 const char *Start, const char *&Beg, const char *E,
150 unsigned *argIndex) {
151 if (argIndex) {
152 FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
153 }
154 else {
155 const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
156 analyze_printf::PrecisionPos);
157 if (Amt.isInvalid())
158 return true;
159 FS.setPrecision(Amt);
160 }
161 return false;
162}
163
164static bool ParseFieldWidth(FormatStringHandler &H, FormatSpecifier &FS,
165 const char *Start, const char *&Beg, const char *E,
166 unsigned *argIndex) {
167 // FIXME: Support negative field widths.
168 if (argIndex) {
169 FS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
170 }
171 else {
172 const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
173 analyze_printf::FieldWidthPos);
174 if (Amt.isInvalid())
175 return true;
176 FS.setFieldWidth(Amt);
177 }
178 return false;
179}
180
Ted Kremenekefaff192010-02-27 01:41:03 +0000181static bool ParseArgPosition(FormatStringHandler &H,
182 FormatSpecifier &FS, const char *Start,
183 const char *&Beg, const char *E) {
184
185 using namespace clang::analyze_printf;
186 const char *I = Beg;
187
188 const OptionalAmount &Amt = ParseAmount(I, E);
189
190 if (I == E) {
191 // No more characters left?
192 H.HandleIncompleteFormatSpecifier(Start, E - Start);
193 return true;
194 }
195
196 if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
Ted Kremenekd49d8772010-03-01 19:22:33 +0000197 // Special case: '%0$', since this is an easy mistake.
198 if (Amt.getConstantAmount() == 0) {
199 H.HandleZeroPosition(Start, I - Start);
200 return true;
201 }
202
Ted Kremenekefaff192010-02-27 01:41:03 +0000203 FS.setArgIndex(Amt.getConstantAmount() - 1);
204 FS.setUsesPositionalArg();
205 // Update the caller's pointer if we decided to consume
206 // these characters.
207 Beg = I;
208 return false;
209 }
210
Ted Kremenekefaff192010-02-27 01:41:03 +0000211 return false;
212}
213
Ted Kremenek808015a2010-01-29 03:16:21 +0000214static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
Ted Kremenek74d56a12010-02-04 20:46:58 +0000215 const char *&Beg,
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000216 const char *E,
217 unsigned &argIndex) {
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000218
Ted Kremenek4b220fa2010-01-29 02:13:53 +0000219 using namespace clang::analyze_printf;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000220
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000221 const char *I = Beg;
Ted Kremenekc7ae51a2010-01-28 00:02:05 +0000222 const char *Start = 0;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000223 UpdateOnReturn <const char*> UpdateBeg(Beg, I);
224
225 // Look for a '%' character that indicates the start of a format specifier.
Ted Kremeneke729acb2010-01-28 23:56:52 +0000226 for ( ; I != E ; ++I) {
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000227 char c = *I;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000228 if (c == '\0') {
229 // Detect spurious null characters, which are likely errors.
230 H.HandleNullChar(I);
231 return true;
232 }
233 if (c == '%') {
Ted Kremeneke729acb2010-01-28 23:56:52 +0000234 Start = I++; // Record the start of the format specifier.
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000235 break;
236 }
237 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000238
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000239 // No format specifier found?
240 if (!Start)
241 return false;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000242
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000243 if (I == E) {
244 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000245 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000246 return true;
247 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000248
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000249 FormatSpecifier FS;
Ted Kremenekefaff192010-02-27 01:41:03 +0000250 if (ParseArgPosition(H, FS, Start, I, E))
251 return true;
252
253 if (I == E) {
254 // No more characters left?
255 H.HandleIncompleteFormatSpecifier(Start, E - Start);
256 return true;
257 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000258
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000259 // Look for flags (if any).
260 bool hasMore = true;
261 for ( ; I != E; ++I) {
262 switch (*I) {
263 default: hasMore = false; break;
264 case '-': FS.setIsLeftJustified(); break;
265 case '+': FS.setHasPlusPrefix(); break;
266 case ' ': FS.setHasSpacePrefix(); break;
267 case '#': FS.setHasAlternativeForm(); break;
268 case '0': FS.setHasLeadingZeros(); break;
269 }
270 if (!hasMore)
271 break;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000272 }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000273
274 if (I == E) {
275 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000276 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000277 return true;
278 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000279
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000280 // Look for the field width (if any).
Ted Kremenekefaff192010-02-27 01:41:03 +0000281 if (ParseFieldWidth(H, FS, Start, I, E,
282 FS.usesPositionalArg() ? 0 : &argIndex))
283 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000284
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000285 if (I == E) {
286 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000287 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000288 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000289 }
290
291 // Look for the precision (if any).
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000292 if (*I == '.') {
Ted Kremenek808015a2010-01-29 03:16:21 +0000293 ++I;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000294 if (I == E) {
Ted Kremenek808015a2010-01-29 03:16:21 +0000295 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000296 return true;
297 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000298
Ted Kremenekefaff192010-02-27 01:41:03 +0000299 if (ParsePrecision(H, FS, Start, I, E,
300 FS.usesPositionalArg() ? 0 : &argIndex))
301 return true;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000302
303 if (I == E) {
304 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000305 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000306 return true;
307 }
308 }
309
310 // Look for the length modifier.
Tom Care3bfc5f42010-06-09 04:11:11 +0000311 LengthModifier::Kind lmKind = LengthModifier::None;
312 const char *lmPosition = I;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000313 switch (*I) {
314 default:
315 break;
316 case 'h':
317 ++I;
Tom Care3bfc5f42010-06-09 04:11:11 +0000318 lmKind = (I != E && *I == 'h') ?
319 ++I, LengthModifier::AsChar : LengthModifier::AsShort;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000320 break;
321 case 'l':
322 ++I;
Tom Care3bfc5f42010-06-09 04:11:11 +0000323 lmKind = (I != E && *I == 'l') ?
324 ++I, LengthModifier::AsLongLong : LengthModifier::AsLong;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000325 break;
Tom Care3bfc5f42010-06-09 04:11:11 +0000326 case 'j': lmKind = LengthModifier::AsIntMax; ++I; break;
327 case 'z': lmKind = LengthModifier::AsSizeT; ++I; break;
328 case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break;
329 case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
330 case 'q': lmKind = LengthModifier::AsLongLong; ++I; break;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000331 }
Tom Care3bfc5f42010-06-09 04:11:11 +0000332 LengthModifier lm(lmPosition, lmKind);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000333 FS.setLengthModifier(lm);
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000334
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000335 if (I == E) {
336 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000337 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000338 return true;
339 }
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000340
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000341 if (*I == '\0') {
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000342 // Detect spurious null characters, which are likely errors.
343 H.HandleNullChar(I);
344 return true;
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000345 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000346
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000347 // Finally, look for the conversion specifier.
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000348 const char *conversionPosition = I++;
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000349 ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000350 switch (*conversionPosition) {
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000351 default:
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000352 break;
Ted Kremenekc7cbb9b2010-01-28 00:55:28 +0000353 // C99: 7.19.6.1 (section 8).
Ted Kremenek87260c72010-02-24 00:05:54 +0000354 case '%': k = ConversionSpecifier::PercentArg; break;
355 case 'A': k = ConversionSpecifier::AArg; break;
356 case 'E': k = ConversionSpecifier::EArg; break;
357 case 'F': k = ConversionSpecifier::FArg; break;
358 case 'G': k = ConversionSpecifier::GArg; break;
359 case 'X': k = ConversionSpecifier::XArg; break;
360 case 'a': k = ConversionSpecifier::aArg; break;
361 case 'c': k = ConversionSpecifier::IntAsCharArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000362 case 'd': k = ConversionSpecifier::dArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000363 case 'e': k = ConversionSpecifier::eArg; break;
364 case 'f': k = ConversionSpecifier::fArg; break;
365 case 'g': k = ConversionSpecifier::gArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000366 case 'i': k = ConversionSpecifier::iArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000367 case 'n': k = ConversionSpecifier::OutIntPtrArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000368 case 'o': k = ConversionSpecifier::oArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000369 case 'p': k = ConversionSpecifier::VoidPtrArg; break;
370 case 's': k = ConversionSpecifier::CStrArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000371 case 'u': k = ConversionSpecifier::uArg; break;
372 case 'x': k = ConversionSpecifier::xArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000373 // Mac OS X (unicode) specific
374 case 'C': k = ConversionSpecifier::CArg; break;
375 case 'S': k = ConversionSpecifier::UnicodeStrArg; break;
Ted Kremenekc7cbb9b2010-01-28 00:55:28 +0000376 // Objective-C.
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000377 case '@': k = ConversionSpecifier::ObjCObjArg; break;
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000378 // Glibc specific.
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000379 case 'm': k = ConversionSpecifier::PrintErrno; break;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000380 }
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000381 ConversionSpecifier CS(conversionPosition, k);
382 FS.setConversionSpecifier(CS);
Ted Kremenekefaff192010-02-27 01:41:03 +0000383 if (CS.consumesDataArgument() && !FS.usesPositionalArg())
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000384 FS.setArgIndex(argIndex++);
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000385
386 if (k == ConversionSpecifier::InvalidSpecifier) {
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000387 // Assume the conversion takes one argument.
388 return !H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg);
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000389 }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000390 return FormatSpecifierResult(Start, FS);
391}
392
Ted Kremenek74d56a12010-02-04 20:46:58 +0000393bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H,
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000394 const char *I, const char *E) {
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000395
396 unsigned argIndex = 0;
397
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000398 // Keep looking for a format specifier until we have exhausted the string.
399 while (I != E) {
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000400 const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E, argIndex);
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000401 // Did a fail-stop error of any kind occur when parsing the specifier?
402 // If so, don't do any more processing.
403 if (FSR.shouldStop())
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000404 return true;;
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000405 // Did we exhaust the string or encounter an error that
406 // we can recover from?
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000407 if (!FSR.hasValue())
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000408 continue;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000409 // We have a format specifier. Pass it to the callback.
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000410 if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(),
411 I - FSR.getStart()))
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000412 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000413 }
414 assert(I == E && "Format string not exhausted");
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000415 return false;
416}
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000417
418FormatStringHandler::~FormatStringHandler() {}
Ted Kremenek33567d22010-01-29 22:59:32 +0000419
420//===----------------------------------------------------------------------===//
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000421// Methods on ArgTypeResult.
422//===----------------------------------------------------------------------===//
423
424bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
Ted Kremenek13927a42010-06-16 21:23:04 +0000425 switch (K) {
426 case InvalidTy:
427 assert(false && "ArgTypeResult must be valid");
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000428 return true;
429
Ted Kremenek13927a42010-06-16 21:23:04 +0000430 case UnknownTy:
431 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000432
Ted Kremenek13927a42010-06-16 21:23:04 +0000433 case SpecificTy: {
434 argTy = C.getCanonicalType(argTy).getUnqualifiedType();
435 if (T == argTy)
436 return true;
437 if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
438 switch (BT->getKind()) {
439 default:
440 break;
441 case BuiltinType::Char_S:
442 case BuiltinType::SChar:
443 return T == C.UnsignedCharTy;
444 case BuiltinType::Char_U:
445 case BuiltinType::UChar:
446 return T == C.SignedCharTy;
447 case BuiltinType::Short:
448 return T == C.UnsignedShortTy;
449 case BuiltinType::UShort:
450 return T == C.ShortTy;
451 case BuiltinType::Int:
452 return T == C.UnsignedIntTy;
453 case BuiltinType::UInt:
454 return T == C.IntTy;
455 case BuiltinType::Long:
456 return T == C.UnsignedLongTy;
457 case BuiltinType::ULong:
458 return T == C.LongTy;
459 case BuiltinType::LongLong:
460 return T == C.UnsignedLongLongTy;
461 case BuiltinType::ULongLong:
462 return T == C.LongLongTy;
463 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000464 return false;
Ted Kremenek13927a42010-06-16 21:23:04 +0000465 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000466
Ted Kremenek13927a42010-06-16 21:23:04 +0000467 case CStrTy: {
468 const PointerType *PT = argTy->getAs<PointerType>();
469 if (!PT)
470 return false;
471 QualType pointeeTy = PT->getPointeeType();
472 if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
473 switch (BT->getKind()) {
474 case BuiltinType::Void:
475 case BuiltinType::Char_U:
476 case BuiltinType::UChar:
477 case BuiltinType::Char_S:
478 case BuiltinType::SChar:
479 return true;
480 default:
481 break;
482 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000483
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000484 return false;
Ted Kremenek13927a42010-06-16 21:23:04 +0000485 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000486
Ted Kremenek13927a42010-06-16 21:23:04 +0000487 case WCStrTy: {
488 const PointerType *PT = argTy->getAs<PointerType>();
489 if (!PT)
490 return false;
491 QualType pointeeTy =
492 C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
493 return pointeeTy == C.getWCharType();
494 }
Ted Kremenek87260c72010-02-24 00:05:54 +0000495
Ted Kremenek13927a42010-06-16 21:23:04 +0000496 case CPointerTy:
497 return argTy->getAs<PointerType>() != NULL ||
498 argTy->getAs<ObjCObjectPointerType>() != NULL;
499
500 case ObjCPointerTy:
501 return argTy->getAs<ObjCObjectPointerType>() != NULL;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000502 }
503
Ted Kremenek13927a42010-06-16 21:23:04 +0000504 // FIXME: Should be unreachable, but Clang is currently emitting
505 // a warning.
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000506 return false;
507}
508
509QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
Ted Kremenek13927a42010-06-16 21:23:04 +0000510 switch (K) {
511 case InvalidTy:
512 assert(false && "No representative type for Invalid ArgTypeResult");
513 // Fall-through.
514 case UnknownTy:
515 return QualType();
516 case SpecificTy:
517 return T;
518 case CStrTy:
519 return C.getPointerType(C.CharTy);
520 case WCStrTy:
521 return C.getPointerType(C.getWCharType());
522 case ObjCPointerTy:
523 return C.ObjCBuiltinIdTy;
524 case CPointerTy:
525 return C.VoidPtrTy;
526 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000527
Ted Kremenek13927a42010-06-16 21:23:04 +0000528 // FIXME: Should be unreachable, but Clang is currently emitting
529 // a warning.
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000530 return QualType();
531}
532
533//===----------------------------------------------------------------------===//
534// Methods on OptionalAmount.
535//===----------------------------------------------------------------------===//
536
537ArgTypeResult OptionalAmount::getArgType(ASTContext &Ctx) const {
538 return Ctx.IntTy;
539}
540
541//===----------------------------------------------------------------------===//
Tom Care3bfc5f42010-06-09 04:11:11 +0000542// Methods on ConversionSpecifier.
543//===----------------------------------------------------------------------===//
544const char *ConversionSpecifier::toString() const {
545 switch (kind) {
546 case dArg: return "d";
547 case iArg: return "i";
548 case oArg: return "o";
549 case uArg: return "u";
550 case xArg: return "x";
551 case XArg: return "X";
552 case fArg: return "f";
553 case FArg: return "F";
554 case eArg: return "e";
555 case EArg: return "E";
556 case gArg: return "g";
557 case GArg: return "G";
558 case aArg: return "a";
559 case AArg: return "A";
560 case IntAsCharArg: return "c";
561 case CStrArg: return "s";
562 case VoidPtrArg: return "p";
563 case OutIntPtrArg: return "n";
564 case PercentArg: return "%";
565 case InvalidSpecifier: return NULL;
566
567 // MacOS X unicode extensions.
568 case CArg: return "C";
569 case UnicodeStrArg: return "S";
570
571 // Objective-C specific specifiers.
572 case ObjCObjArg: return "@";
573
574 // GlibC specific specifiers.
575 case PrintErrno: return "m";
576 }
577 return NULL;
578}
579
580//===----------------------------------------------------------------------===//
581// Methods on LengthModifier.
582//===----------------------------------------------------------------------===//
583
584const char *LengthModifier::toString() const {
585 switch (kind) {
586 case AsChar:
587 return "hh";
588 case AsShort:
589 return "h";
590 case AsLong: // or AsWideChar
591 return "l";
592 case AsLongLong:
593 return "ll";
594 case AsIntMax:
595 return "j";
596 case AsSizeT:
597 return "z";
598 case AsPtrDiff:
599 return "t";
600 case AsLongDouble:
601 return "L";
602 case None:
603 return "";
604 }
605 return NULL;
606}
607
608//===----------------------------------------------------------------------===//
609// Methods on OptionalAmount.
610//===----------------------------------------------------------------------===//
611
612void OptionalAmount::toString(llvm::raw_ostream &os) const {
613 switch (hs) {
614 case Invalid:
615 case NotSpecified:
616 return;
617 case Arg:
618 if (usesPositionalArg())
619 os << ".*" << getPositionalArgIndex() << "$";
620 else
621 os << ".*";
622 break;
623 case Constant:
624 os << "." << amt;
625 break;
626 }
627}
628
629//===----------------------------------------------------------------------===//
Ted Kremenek33567d22010-01-29 22:59:32 +0000630// Methods on FormatSpecifier.
631//===----------------------------------------------------------------------===//
632
633ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const {
634 if (!CS.consumesDataArgument())
635 return ArgTypeResult::Invalid();
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000636
Ted Kremenek33567d22010-01-29 22:59:32 +0000637 if (CS.isIntArg())
Tom Care3bfc5f42010-06-09 04:11:11 +0000638 switch (LM.getKind()) {
639 case LengthModifier::AsLongDouble:
Ted Kremenek33567d22010-01-29 22:59:32 +0000640 return ArgTypeResult::Invalid();
Tom Care3bfc5f42010-06-09 04:11:11 +0000641 case LengthModifier::None: return Ctx.IntTy;
642 case LengthModifier::AsChar: return Ctx.SignedCharTy;
643 case LengthModifier::AsShort: return Ctx.ShortTy;
644 case LengthModifier::AsLong: return Ctx.LongTy;
645 case LengthModifier::AsLongLong: return Ctx.LongLongTy;
646 case LengthModifier::AsIntMax:
Ted Kremenek33567d22010-01-29 22:59:32 +0000647 // FIXME: Return unknown for now.
648 return ArgTypeResult();
Tom Care3bfc5f42010-06-09 04:11:11 +0000649 case LengthModifier::AsSizeT: return Ctx.getSizeType();
650 case LengthModifier::AsPtrDiff: return Ctx.getPointerDiffType();
Ted Kremenek33567d22010-01-29 22:59:32 +0000651 }
652
653 if (CS.isUIntArg())
Tom Care3bfc5f42010-06-09 04:11:11 +0000654 switch (LM.getKind()) {
655 case LengthModifier::AsLongDouble:
Ted Kremenek33567d22010-01-29 22:59:32 +0000656 return ArgTypeResult::Invalid();
Tom Care3bfc5f42010-06-09 04:11:11 +0000657 case LengthModifier::None: return Ctx.UnsignedIntTy;
658 case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
659 case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
660 case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
661 case LengthModifier::AsLongLong: return Ctx.UnsignedLongLongTy;
662 case LengthModifier::AsIntMax:
Ted Kremenek33567d22010-01-29 22:59:32 +0000663 // FIXME: Return unknown for now.
664 return ArgTypeResult();
Tom Care3bfc5f42010-06-09 04:11:11 +0000665 case LengthModifier::AsSizeT:
Ted Kremenek33567d22010-01-29 22:59:32 +0000666 // FIXME: How to get the corresponding unsigned
667 // version of size_t?
668 return ArgTypeResult();
Tom Care3bfc5f42010-06-09 04:11:11 +0000669 case LengthModifier::AsPtrDiff:
Ted Kremenek33567d22010-01-29 22:59:32 +0000670 // FIXME: How to get the corresponding unsigned
671 // version of ptrdiff_t?
672 return ArgTypeResult();
673 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000674
Ted Kremenekf911eba2010-02-01 23:23:50 +0000675 if (CS.isDoubleArg()) {
Tom Care3bfc5f42010-06-09 04:11:11 +0000676 if (LM.getKind() == LengthModifier::AsLongDouble)
Ted Kremenekf911eba2010-02-01 23:23:50 +0000677 return Ctx.LongDoubleTy;
Ted Kremenekc9a89fe2010-01-30 01:02:18 +0000678 return Ctx.DoubleTy;
Ted Kremenekf911eba2010-02-01 23:23:50 +0000679 }
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000680
Ted Kremenek87260c72010-02-24 00:05:54 +0000681 switch (CS.getKind()) {
682 case ConversionSpecifier::CStrArg:
Tom Care3bfc5f42010-06-09 04:11:11 +0000683 return ArgTypeResult(LM.getKind() == LengthModifier::AsWideChar ?
684 ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy);
Ted Kremenek87260c72010-02-24 00:05:54 +0000685 case ConversionSpecifier::UnicodeStrArg:
686 // FIXME: This appears to be Mac OS X specific.
687 return ArgTypeResult::WCStrTy;
688 case ConversionSpecifier::CArg:
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000689 return Ctx.WCharTy;
Ted Kremenek13927a42010-06-16 21:23:04 +0000690 case ConversionSpecifier::VoidPtrArg:
691 return ArgTypeResult::CPointerTy;
Ted Kremenek87260c72010-02-24 00:05:54 +0000692 default:
693 break;
694 }
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000695
Ted Kremenek33567d22010-01-29 22:59:32 +0000696 // FIXME: Handle other cases.
Ted Kremenek40888ad2010-01-29 23:00:35 +0000697 return ArgTypeResult();
Ted Kremenek33567d22010-01-29 22:59:32 +0000698}
699
Tom Care3bfc5f42010-06-09 04:11:11 +0000700bool FormatSpecifier::fixType(QualType QT) {
701 // Handle strings first (char *, wchar_t *)
702 if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
703 CS.setKind(ConversionSpecifier::CStrArg);
704
Tom Care876e9942010-06-11 04:22:02 +0000705 // Disable irrelevant flags
706 HasAlternativeForm = 0;
707 HasLeadingZeroes = 0;
708
Tom Care3bfc5f42010-06-09 04:11:11 +0000709 // Set the long length modifier for wide characters
710 if (QT->getPointeeType()->isWideCharType())
711 LM.setKind(LengthModifier::AsWideChar);
712
713 return true;
714 }
715
716 // We can only work with builtin types.
717 if (!QT->isBuiltinType())
718 return false;
719
720 // Everything else should be a base type
721 const BuiltinType *BT = QT->getAs<BuiltinType>();
Tom Care876e9942010-06-11 04:22:02 +0000722
Tom Care3bfc5f42010-06-09 04:11:11 +0000723 // Set length modifier
724 switch (BT->getKind()) {
725 default:
Tom Care876e9942010-06-11 04:22:02 +0000726 // The rest of the conversions are either optional or for non-builtin types
727 LM.setKind(LengthModifier::None);
Tom Care3bfc5f42010-06-09 04:11:11 +0000728 break;
Tom Care876e9942010-06-11 04:22:02 +0000729
Tom Care3bfc5f42010-06-09 04:11:11 +0000730 case BuiltinType::WChar:
731 case BuiltinType::Long:
732 case BuiltinType::ULong:
733 LM.setKind(LengthModifier::AsLong);
734 break;
735
736 case BuiltinType::LongLong:
737 case BuiltinType::ULongLong:
738 LM.setKind(LengthModifier::AsLongLong);
739 break;
740
741 case BuiltinType::LongDouble:
742 LM.setKind(LengthModifier::AsLongDouble);
743 break;
744 }
745
746 // Set conversion specifier and disable any flags which do not apply to it.
747 if (QT->isAnyCharacterType()) {
748 CS.setKind(ConversionSpecifier::IntAsCharArg);
749 Precision.setHowSpecified(OptionalAmount::NotSpecified);
750 HasAlternativeForm = 0;
751 HasLeadingZeroes = 0;
752 }
753 // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
754 else if (QT->isFloatingType()) {
755 CS.setKind(ConversionSpecifier::fArg);
756 }
757 else if (QT->isPointerType()) {
758 CS.setKind(ConversionSpecifier::VoidPtrArg);
759 Precision.setHowSpecified(OptionalAmount::NotSpecified);
760 HasAlternativeForm = 0;
761 HasLeadingZeroes = 0;
762 }
763 else if (QT->isSignedIntegerType()) {
764 CS.setKind(ConversionSpecifier::dArg);
765 HasAlternativeForm = 0;
766 }
Douglas Gregorc8c4b402010-06-09 05:25:34 +0000767 else if (QT->isUnsignedIntegerType()) {
Tom Care3bfc5f42010-06-09 04:11:11 +0000768 CS.setKind(ConversionSpecifier::uArg);
769 HasAlternativeForm = 0;
770 }
771 else {
772 return false;
773 }
774
775 return true;
776}
777
778void FormatSpecifier::toString(llvm::raw_ostream &os) const {
779 // Whilst some features have no defined order, we are using the order
780 // appearing in the C99 standard (ISO/IEC 9899:1999 (E) ยค7.19.6.1)
781 os << "%";
782
783 // Positional args
784 if (usesPositionalArg()) {
785 os << getPositionalArgIndex() << "$";
786 }
787
788 // Conversion flags
789 if (IsLeftJustified) os << "-";
790 if (HasPlusPrefix) os << "+";
791 if (HasSpacePrefix) os << " ";
792 if (HasAlternativeForm) os << "#";
793 if (HasLeadingZeroes) os << "0";
794
795 // Minimum field width
796 FieldWidth.toString(os);
797 // Precision
798 Precision.toString(os);
799 // Length modifier
800 os << LM.toString();
801 // Conversion specifier
802 os << CS.toString();
803}