blob: 99dc22901c75896620e009464c2e7d7ce022ee46 [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 Kremenek4e4b30e2010-02-16 01:46:59 +000042
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000043 const char *getStart() const { return Start; }
Ted Kremenek26ac2e02010-01-29 02:40:24 +000044 bool shouldStop() const { return Stop; }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000045 bool hasValue() const { return Start != 0; }
46 const FormatSpecifier &getValue() const {
47 assert(hasValue());
48 return FS;
49 }
Ted Kremenekd2dcece2010-01-28 02:02:59 +000050 const FormatSpecifier &getValue() { return FS; }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000051};
52} // end anonymous namespace
53
54template <typename T>
55class UpdateOnReturn {
56 T &ValueToUpdate;
57 const T &ValueToCopy;
58public:
59 UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
60 : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000061
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000062 ~UpdateOnReturn() {
63 ValueToUpdate = ValueToCopy;
64 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000065};
66
67//===----------------------------------------------------------------------===//
68// Methods for parsing format strings.
69//===----------------------------------------------------------------------===//
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000070
Ted Kremenekefaff192010-02-27 01:41:03 +000071static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000072 const char *I = Beg;
73 UpdateOnReturn <const char*> UpdateBeg(Beg, I);
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000074
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000075 unsigned accumulator = 0;
Ted Kremenekd49d8772010-03-01 19:22:33 +000076 bool hasDigits = false;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000077
78 for ( ; I != E; ++I) {
79 char c = *I;
80 if (c >= '0' && c <= '9') {
Ted Kremenekd49d8772010-03-01 19:22:33 +000081 hasDigits = true;
Ted Kremenekfdb703a2010-03-25 03:59:09 +000082 accumulator = (accumulator * 10) + (c - '0');
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000083 continue;
84 }
85
Ted Kremenekd49d8772010-03-01 19:22:33 +000086 if (hasDigits)
Tom Care3bfc5f42010-06-09 04:11:11 +000087 return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, 0);
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 Care3bfc5f42010-06-09 04:11:11 +000099 return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0);
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 Care3bfc5f42010-06-09 04:11:11 +0000139 Tmp, 1);
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
182
183static bool ParseArgPosition(FormatStringHandler &H,
184 FormatSpecifier &FS, const char *Start,
185 const char *&Beg, const char *E) {
186
187 using namespace clang::analyze_printf;
188 const char *I = Beg;
189
190 const OptionalAmount &Amt = ParseAmount(I, E);
191
192 if (I == E) {
193 // No more characters left?
194 H.HandleIncompleteFormatSpecifier(Start, E - Start);
195 return true;
196 }
197
198 if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
Ted Kremenekd49d8772010-03-01 19:22:33 +0000199 // Special case: '%0$', since this is an easy mistake.
200 if (Amt.getConstantAmount() == 0) {
201 H.HandleZeroPosition(Start, I - Start);
202 return true;
203 }
204
Ted Kremenekefaff192010-02-27 01:41:03 +0000205 FS.setArgIndex(Amt.getConstantAmount() - 1);
206 FS.setUsesPositionalArg();
207 // Update the caller's pointer if we decided to consume
208 // these characters.
209 Beg = I;
210 return false;
211 }
212
Ted Kremenekefaff192010-02-27 01:41:03 +0000213 return false;
214}
215
Ted Kremenek808015a2010-01-29 03:16:21 +0000216static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
Ted Kremenek74d56a12010-02-04 20:46:58 +0000217 const char *&Beg,
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000218 const char *E,
219 unsigned &argIndex) {
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000220
Ted Kremenek4b220fa2010-01-29 02:13:53 +0000221 using namespace clang::analyze_printf;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000222
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000223 const char *I = Beg;
Ted Kremenekc7ae51a2010-01-28 00:02:05 +0000224 const char *Start = 0;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000225 UpdateOnReturn <const char*> UpdateBeg(Beg, I);
226
227 // Look for a '%' character that indicates the start of a format specifier.
Ted Kremeneke729acb2010-01-28 23:56:52 +0000228 for ( ; I != E ; ++I) {
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000229 char c = *I;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000230 if (c == '\0') {
231 // Detect spurious null characters, which are likely errors.
232 H.HandleNullChar(I);
233 return true;
234 }
235 if (c == '%') {
Ted Kremeneke729acb2010-01-28 23:56:52 +0000236 Start = I++; // Record the start of the format specifier.
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000237 break;
238 }
239 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000240
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000241 // No format specifier found?
242 if (!Start)
243 return false;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000244
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000245 if (I == E) {
246 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000247 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000248 return true;
249 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000250
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000251 FormatSpecifier FS;
Ted Kremenekefaff192010-02-27 01:41:03 +0000252 if (ParseArgPosition(H, FS, Start, I, E))
253 return true;
254
255 if (I == E) {
256 // No more characters left?
257 H.HandleIncompleteFormatSpecifier(Start, E - Start);
258 return true;
259 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000260
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000261 // Look for flags (if any).
262 bool hasMore = true;
263 for ( ; I != E; ++I) {
264 switch (*I) {
265 default: hasMore = false; break;
266 case '-': FS.setIsLeftJustified(); break;
267 case '+': FS.setHasPlusPrefix(); break;
268 case ' ': FS.setHasSpacePrefix(); break;
269 case '#': FS.setHasAlternativeForm(); break;
270 case '0': FS.setHasLeadingZeros(); break;
271 }
272 if (!hasMore)
273 break;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000274 }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000275
276 if (I == E) {
277 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000278 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000279 return true;
280 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000281
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000282 // Look for the field width (if any).
Ted Kremenekefaff192010-02-27 01:41:03 +0000283 if (ParseFieldWidth(H, FS, Start, I, E,
284 FS.usesPositionalArg() ? 0 : &argIndex))
285 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000286
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000287 if (I == E) {
288 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000289 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000290 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000291 }
292
293 // Look for the precision (if any).
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000294 if (*I == '.') {
Ted Kremenek808015a2010-01-29 03:16:21 +0000295 ++I;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000296 if (I == E) {
Ted Kremenek808015a2010-01-29 03:16:21 +0000297 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000298 return true;
299 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000300
Ted Kremenekefaff192010-02-27 01:41:03 +0000301 if (ParsePrecision(H, FS, Start, I, E,
302 FS.usesPositionalArg() ? 0 : &argIndex))
303 return true;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000304
305 if (I == E) {
306 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000307 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000308 return true;
309 }
310 }
311
312 // Look for the length modifier.
Tom Care3bfc5f42010-06-09 04:11:11 +0000313 LengthModifier::Kind lmKind = LengthModifier::None;
314 const char *lmPosition = I;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000315 switch (*I) {
316 default:
317 break;
318 case 'h':
319 ++I;
Tom Care3bfc5f42010-06-09 04:11:11 +0000320 lmKind = (I != E && *I == 'h') ?
321 ++I, LengthModifier::AsChar : LengthModifier::AsShort;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000322 break;
323 case 'l':
324 ++I;
Tom Care3bfc5f42010-06-09 04:11:11 +0000325 lmKind = (I != E && *I == 'l') ?
326 ++I, LengthModifier::AsLongLong : LengthModifier::AsLong;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000327 break;
Tom Care3bfc5f42010-06-09 04:11:11 +0000328 case 'j': lmKind = LengthModifier::AsIntMax; ++I; break;
329 case 'z': lmKind = LengthModifier::AsSizeT; ++I; break;
330 case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break;
331 case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
332 case 'q': lmKind = LengthModifier::AsLongLong; ++I; break;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000333 }
Tom Care3bfc5f42010-06-09 04:11:11 +0000334 LengthModifier lm(lmPosition, lmKind);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000335 FS.setLengthModifier(lm);
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000336
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000337 if (I == E) {
338 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000339 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000340 return true;
341 }
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000342
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000343 if (*I == '\0') {
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000344 // Detect spurious null characters, which are likely errors.
345 H.HandleNullChar(I);
346 return true;
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000347 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000348
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000349 // Finally, look for the conversion specifier.
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000350 const char *conversionPosition = I++;
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000351 ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000352 switch (*conversionPosition) {
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000353 default:
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000354 break;
Ted Kremenekc7cbb9b2010-01-28 00:55:28 +0000355 // C99: 7.19.6.1 (section 8).
Ted Kremenek87260c72010-02-24 00:05:54 +0000356 case '%': k = ConversionSpecifier::PercentArg; break;
357 case 'A': k = ConversionSpecifier::AArg; break;
358 case 'E': k = ConversionSpecifier::EArg; break;
359 case 'F': k = ConversionSpecifier::FArg; break;
360 case 'G': k = ConversionSpecifier::GArg; break;
361 case 'X': k = ConversionSpecifier::XArg; break;
362 case 'a': k = ConversionSpecifier::aArg; break;
363 case 'c': k = ConversionSpecifier::IntAsCharArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000364 case 'd': k = ConversionSpecifier::dArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000365 case 'e': k = ConversionSpecifier::eArg; break;
366 case 'f': k = ConversionSpecifier::fArg; break;
367 case 'g': k = ConversionSpecifier::gArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000368 case 'i': k = ConversionSpecifier::iArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000369 case 'n': k = ConversionSpecifier::OutIntPtrArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000370 case 'o': k = ConversionSpecifier::oArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000371 case 'p': k = ConversionSpecifier::VoidPtrArg; break;
372 case 's': k = ConversionSpecifier::CStrArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000373 case 'u': k = ConversionSpecifier::uArg; break;
374 case 'x': k = ConversionSpecifier::xArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000375 // Mac OS X (unicode) specific
376 case 'C': k = ConversionSpecifier::CArg; break;
377 case 'S': k = ConversionSpecifier::UnicodeStrArg; break;
Ted Kremenekc7cbb9b2010-01-28 00:55:28 +0000378 // Objective-C.
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000379 case '@': k = ConversionSpecifier::ObjCObjArg; break;
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000380 // Glibc specific.
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000381 case 'm': k = ConversionSpecifier::PrintErrno; break;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000382 }
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000383 ConversionSpecifier CS(conversionPosition, k);
384 FS.setConversionSpecifier(CS);
Ted Kremenekefaff192010-02-27 01:41:03 +0000385 if (CS.consumesDataArgument() && !FS.usesPositionalArg())
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000386 FS.setArgIndex(argIndex++);
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000387
388 if (k == ConversionSpecifier::InvalidSpecifier) {
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000389 // Assume the conversion takes one argument.
390 return !H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg);
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000391 }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000392 return FormatSpecifierResult(Start, FS);
393}
394
Ted Kremenek74d56a12010-02-04 20:46:58 +0000395bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H,
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000396 const char *I, const char *E) {
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000397
398 unsigned argIndex = 0;
399
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000400 // Keep looking for a format specifier until we have exhausted the string.
401 while (I != E) {
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000402 const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E, argIndex);
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000403 // Did a fail-stop error of any kind occur when parsing the specifier?
404 // If so, don't do any more processing.
405 if (FSR.shouldStop())
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000406 return true;;
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000407 // Did we exhaust the string or encounter an error that
408 // we can recover from?
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000409 if (!FSR.hasValue())
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000410 continue;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000411 // We have a format specifier. Pass it to the callback.
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000412 if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(),
413 I - FSR.getStart()))
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000414 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000415 }
416 assert(I == E && "Format string not exhausted");
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000417 return false;
418}
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000419
420FormatStringHandler::~FormatStringHandler() {}
Ted Kremenek33567d22010-01-29 22:59:32 +0000421
422//===----------------------------------------------------------------------===//
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000423// Methods on ArgTypeResult.
424//===----------------------------------------------------------------------===//
425
426bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
427 assert(isValid());
428
429 if (K == UnknownTy)
430 return true;
431
432 if (K == SpecificTy) {
433 argTy = C.getCanonicalType(argTy).getUnqualifiedType();
434
435 if (T == argTy)
436 return true;
437
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 }
465
466 return false;
467 }
468
469 if (K == CStrTy) {
470 const PointerType *PT = argTy->getAs<PointerType>();
471 if (!PT)
472 return false;
473
474 QualType pointeeTy = PT->getPointeeType();
475
476 if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
477 switch (BT->getKind()) {
478 case BuiltinType::Void:
479 case BuiltinType::Char_U:
480 case BuiltinType::UChar:
481 case BuiltinType::Char_S:
482 case BuiltinType::SChar:
483 return true;
484 default:
485 break;
486 }
487
488 return false;
489 }
490
491 if (K == WCStrTy) {
492 const PointerType *PT = argTy->getAs<PointerType>();
493 if (!PT)
494 return false;
495
Ted Kremenek87260c72010-02-24 00:05:54 +0000496 QualType pointeeTy =
497 C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
498
499 return pointeeTy == C.getWCharType();
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000500 }
501
502 return false;
503}
504
505QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
506 assert(isValid());
507 if (K == SpecificTy)
508 return T;
509 if (K == CStrTy)
510 return C.getPointerType(C.CharTy);
511 if (K == WCStrTy)
Ted Kremenek87260c72010-02-24 00:05:54 +0000512 return C.getPointerType(C.getWCharType());
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000513 if (K == ObjCPointerTy)
514 return C.ObjCBuiltinIdTy;
515
516 return QualType();
517}
518
519//===----------------------------------------------------------------------===//
520// Methods on OptionalAmount.
521//===----------------------------------------------------------------------===//
522
523ArgTypeResult OptionalAmount::getArgType(ASTContext &Ctx) const {
524 return Ctx.IntTy;
525}
526
527//===----------------------------------------------------------------------===//
Tom Care3bfc5f42010-06-09 04:11:11 +0000528// Methods on ConversionSpecifier.
529//===----------------------------------------------------------------------===//
530const char *ConversionSpecifier::toString() const {
531 switch (kind) {
532 case dArg: return "d";
533 case iArg: return "i";
534 case oArg: return "o";
535 case uArg: return "u";
536 case xArg: return "x";
537 case XArg: return "X";
538 case fArg: return "f";
539 case FArg: return "F";
540 case eArg: return "e";
541 case EArg: return "E";
542 case gArg: return "g";
543 case GArg: return "G";
544 case aArg: return "a";
545 case AArg: return "A";
546 case IntAsCharArg: return "c";
547 case CStrArg: return "s";
548 case VoidPtrArg: return "p";
549 case OutIntPtrArg: return "n";
550 case PercentArg: return "%";
551 case InvalidSpecifier: return NULL;
552
553 // MacOS X unicode extensions.
554 case CArg: return "C";
555 case UnicodeStrArg: return "S";
556
557 // Objective-C specific specifiers.
558 case ObjCObjArg: return "@";
559
560 // GlibC specific specifiers.
561 case PrintErrno: return "m";
562 }
563 return NULL;
564}
565
566//===----------------------------------------------------------------------===//
567// Methods on LengthModifier.
568//===----------------------------------------------------------------------===//
569
570const char *LengthModifier::toString() const {
571 switch (kind) {
572 case AsChar:
573 return "hh";
574 case AsShort:
575 return "h";
576 case AsLong: // or AsWideChar
577 return "l";
578 case AsLongLong:
579 return "ll";
580 case AsIntMax:
581 return "j";
582 case AsSizeT:
583 return "z";
584 case AsPtrDiff:
585 return "t";
586 case AsLongDouble:
587 return "L";
588 case None:
589 return "";
590 }
591 return NULL;
592}
593
594//===----------------------------------------------------------------------===//
595// Methods on OptionalAmount.
596//===----------------------------------------------------------------------===//
597
598void OptionalAmount::toString(llvm::raw_ostream &os) const {
599 switch (hs) {
600 case Invalid:
601 case NotSpecified:
602 return;
603 case Arg:
604 if (usesPositionalArg())
605 os << ".*" << getPositionalArgIndex() << "$";
606 else
607 os << ".*";
608 break;
609 case Constant:
610 os << "." << amt;
611 break;
612 }
613}
614
615//===----------------------------------------------------------------------===//
Ted Kremenek33567d22010-01-29 22:59:32 +0000616// Methods on FormatSpecifier.
617//===----------------------------------------------------------------------===//
618
619ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const {
620 if (!CS.consumesDataArgument())
621 return ArgTypeResult::Invalid();
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000622
Ted Kremenek33567d22010-01-29 22:59:32 +0000623 if (CS.isIntArg())
Tom Care3bfc5f42010-06-09 04:11:11 +0000624 switch (LM.getKind()) {
625 case LengthModifier::AsLongDouble:
Ted Kremenek33567d22010-01-29 22:59:32 +0000626 return ArgTypeResult::Invalid();
Tom Care3bfc5f42010-06-09 04:11:11 +0000627 case LengthModifier::None: return Ctx.IntTy;
628 case LengthModifier::AsChar: return Ctx.SignedCharTy;
629 case LengthModifier::AsShort: return Ctx.ShortTy;
630 case LengthModifier::AsLong: return Ctx.LongTy;
631 case LengthModifier::AsLongLong: return Ctx.LongLongTy;
632 case LengthModifier::AsIntMax:
Ted Kremenek33567d22010-01-29 22:59:32 +0000633 // FIXME: Return unknown for now.
634 return ArgTypeResult();
Tom Care3bfc5f42010-06-09 04:11:11 +0000635 case LengthModifier::AsSizeT: return Ctx.getSizeType();
636 case LengthModifier::AsPtrDiff: return Ctx.getPointerDiffType();
Ted Kremenek33567d22010-01-29 22:59:32 +0000637 }
638
639 if (CS.isUIntArg())
Tom Care3bfc5f42010-06-09 04:11:11 +0000640 switch (LM.getKind()) {
641 case LengthModifier::AsLongDouble:
Ted Kremenek33567d22010-01-29 22:59:32 +0000642 return ArgTypeResult::Invalid();
Tom Care3bfc5f42010-06-09 04:11:11 +0000643 case LengthModifier::None: return Ctx.UnsignedIntTy;
644 case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
645 case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
646 case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
647 case LengthModifier::AsLongLong: return Ctx.UnsignedLongLongTy;
648 case LengthModifier::AsIntMax:
Ted Kremenek33567d22010-01-29 22:59:32 +0000649 // FIXME: Return unknown for now.
650 return ArgTypeResult();
Tom Care3bfc5f42010-06-09 04:11:11 +0000651 case LengthModifier::AsSizeT:
Ted Kremenek33567d22010-01-29 22:59:32 +0000652 // FIXME: How to get the corresponding unsigned
653 // version of size_t?
654 return ArgTypeResult();
Tom Care3bfc5f42010-06-09 04:11:11 +0000655 case LengthModifier::AsPtrDiff:
Ted Kremenek33567d22010-01-29 22:59:32 +0000656 // FIXME: How to get the corresponding unsigned
657 // version of ptrdiff_t?
658 return ArgTypeResult();
659 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000660
Ted Kremenekf911eba2010-02-01 23:23:50 +0000661 if (CS.isDoubleArg()) {
Tom Care3bfc5f42010-06-09 04:11:11 +0000662 if (LM.getKind() == LengthModifier::AsLongDouble)
Ted Kremenekf911eba2010-02-01 23:23:50 +0000663 return Ctx.LongDoubleTy;
Ted Kremenekc9a89fe2010-01-30 01:02:18 +0000664 return Ctx.DoubleTy;
Ted Kremenekf911eba2010-02-01 23:23:50 +0000665 }
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000666
Ted Kremenek87260c72010-02-24 00:05:54 +0000667 switch (CS.getKind()) {
668 case ConversionSpecifier::CStrArg:
Tom Care3bfc5f42010-06-09 04:11:11 +0000669 return ArgTypeResult(LM.getKind() == LengthModifier::AsWideChar ?
670 ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy);
Ted Kremenek87260c72010-02-24 00:05:54 +0000671 case ConversionSpecifier::UnicodeStrArg:
672 // FIXME: This appears to be Mac OS X specific.
673 return ArgTypeResult::WCStrTy;
674 case ConversionSpecifier::CArg:
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000675 return Ctx.WCharTy;
Ted Kremenek87260c72010-02-24 00:05:54 +0000676 default:
677 break;
678 }
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000679
Ted Kremenek33567d22010-01-29 22:59:32 +0000680 // FIXME: Handle other cases.
Ted Kremenek40888ad2010-01-29 23:00:35 +0000681 return ArgTypeResult();
Ted Kremenek33567d22010-01-29 22:59:32 +0000682}
683
Tom Care3bfc5f42010-06-09 04:11:11 +0000684bool FormatSpecifier::fixType(QualType QT) {
685 // Handle strings first (char *, wchar_t *)
686 if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
687 CS.setKind(ConversionSpecifier::CStrArg);
688
Tom Care876e9942010-06-11 04:22:02 +0000689 // Disable irrelevant flags
690 HasAlternativeForm = 0;
691 HasLeadingZeroes = 0;
692
Tom Care3bfc5f42010-06-09 04:11:11 +0000693 // Set the long length modifier for wide characters
694 if (QT->getPointeeType()->isWideCharType())
695 LM.setKind(LengthModifier::AsWideChar);
696
697 return true;
698 }
699
700 // We can only work with builtin types.
701 if (!QT->isBuiltinType())
702 return false;
703
704 // Everything else should be a base type
705 const BuiltinType *BT = QT->getAs<BuiltinType>();
Tom Care876e9942010-06-11 04:22:02 +0000706
Tom Care3bfc5f42010-06-09 04:11:11 +0000707 // Set length modifier
708 switch (BT->getKind()) {
709 default:
Tom Care876e9942010-06-11 04:22:02 +0000710 // The rest of the conversions are either optional or for non-builtin types
711 LM.setKind(LengthModifier::None);
Tom Care3bfc5f42010-06-09 04:11:11 +0000712 break;
Tom Care876e9942010-06-11 04:22:02 +0000713
Tom Care3bfc5f42010-06-09 04:11:11 +0000714 case BuiltinType::WChar:
715 case BuiltinType::Long:
716 case BuiltinType::ULong:
717 LM.setKind(LengthModifier::AsLong);
718 break;
719
720 case BuiltinType::LongLong:
721 case BuiltinType::ULongLong:
722 LM.setKind(LengthModifier::AsLongLong);
723 break;
724
725 case BuiltinType::LongDouble:
726 LM.setKind(LengthModifier::AsLongDouble);
727 break;
728 }
729
730 // Set conversion specifier and disable any flags which do not apply to it.
731 if (QT->isAnyCharacterType()) {
732 CS.setKind(ConversionSpecifier::IntAsCharArg);
733 Precision.setHowSpecified(OptionalAmount::NotSpecified);
734 HasAlternativeForm = 0;
735 HasLeadingZeroes = 0;
736 }
737 // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
738 else if (QT->isFloatingType()) {
739 CS.setKind(ConversionSpecifier::fArg);
740 }
741 else if (QT->isPointerType()) {
742 CS.setKind(ConversionSpecifier::VoidPtrArg);
743 Precision.setHowSpecified(OptionalAmount::NotSpecified);
744 HasAlternativeForm = 0;
745 HasLeadingZeroes = 0;
746 }
747 else if (QT->isSignedIntegerType()) {
748 CS.setKind(ConversionSpecifier::dArg);
749 HasAlternativeForm = 0;
750 }
Douglas Gregorc8c4b402010-06-09 05:25:34 +0000751 else if (QT->isUnsignedIntegerType()) {
Tom Care3bfc5f42010-06-09 04:11:11 +0000752 CS.setKind(ConversionSpecifier::uArg);
753 HasAlternativeForm = 0;
754 }
755 else {
756 return false;
757 }
758
759 return true;
760}
761
762void FormatSpecifier::toString(llvm::raw_ostream &os) const {
763 // Whilst some features have no defined order, we are using the order
764 // appearing in the C99 standard (ISO/IEC 9899:1999 (E) ยค7.19.6.1)
765 os << "%";
766
767 // Positional args
768 if (usesPositionalArg()) {
769 os << getPositionalArgIndex() << "$";
770 }
771
772 // Conversion flags
773 if (IsLeftJustified) os << "-";
774 if (HasPlusPrefix) os << "+";
775 if (HasSpacePrefix) os << " ";
776 if (HasAlternativeForm) os << "#";
777 if (HasLeadingZeroes) os << "0";
778
779 // Minimum field width
780 FieldWidth.toString(os);
781 // Precision
782 Precision.toString(os);
783 // Length modifier
784 os << LM.toString();
785 // Conversion specifier
786 os << CS.toString();
787}