blob: 6d6b370b3ffe8bc138f2a830a2a16ac8ecc8e1dc [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"
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000017
Ted Kremenek33567d22010-01-29 22:59:32 +000018using clang::analyze_printf::ArgTypeResult;
Ted Kremenekefaff192010-02-27 01:41:03 +000019using clang::analyze_printf::FormatSpecifier;
Ted Kremenek74d56a12010-02-04 20:46:58 +000020using clang::analyze_printf::FormatStringHandler;
Ted Kremenekefaff192010-02-27 01:41:03 +000021using clang::analyze_printf::OptionalAmount;
22using clang::analyze_printf::PositionContext;
23
Ted Kremenek808015a2010-01-29 03:16:21 +000024using namespace clang;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000025
26namespace {
27class FormatSpecifierResult {
28 FormatSpecifier FS;
29 const char *Start;
Ted Kremenek26ac2e02010-01-29 02:40:24 +000030 bool Stop;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000031public:
Ted Kremenek26ac2e02010-01-29 02:40:24 +000032 FormatSpecifierResult(bool stop = false)
33 : Start(0), Stop(stop) {}
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000034 FormatSpecifierResult(const char *start,
Ted Kremenekd2dcece2010-01-28 02:02:59 +000035 const FormatSpecifier &fs)
Ted Kremenek26ac2e02010-01-29 02:40:24 +000036 : FS(fs), Start(start), Stop(false) {}
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000037
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000038
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000039 const char *getStart() const { return Start; }
Ted Kremenek26ac2e02010-01-29 02:40:24 +000040 bool shouldStop() const { return Stop; }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000041 bool hasValue() const { return Start != 0; }
42 const FormatSpecifier &getValue() const {
43 assert(hasValue());
44 return FS;
45 }
Ted Kremenekd2dcece2010-01-28 02:02:59 +000046 const FormatSpecifier &getValue() { return FS; }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000047};
48} // end anonymous namespace
49
50template <typename T>
51class UpdateOnReturn {
52 T &ValueToUpdate;
53 const T &ValueToCopy;
54public:
55 UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
56 : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000057
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000058 ~UpdateOnReturn() {
59 ValueToUpdate = ValueToCopy;
60 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000061};
62
63//===----------------------------------------------------------------------===//
64// Methods for parsing format strings.
65//===----------------------------------------------------------------------===//
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000066
Ted Kremenekefaff192010-02-27 01:41:03 +000067static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000068 const char *I = Beg;
69 UpdateOnReturn <const char*> UpdateBeg(Beg, I);
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000070
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000071 unsigned accumulator = 0;
72
73 for ( ; I != E; ++I) {
74 char c = *I;
75 if (c >= '0' && c <= '9') {
Ted Kremenekefaff192010-02-27 01:41:03 +000076 // Ignore '0' on the first character.
77 if (c == '0' && I == Beg)
78 break;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000079 accumulator += (accumulator * 10) + (c - '0');
80 continue;
81 }
82
Ted Kremenekefaff192010-02-27 01:41:03 +000083 if (accumulator)
Ted Kremenek7f70dc82010-02-26 19:18:41 +000084 return OptionalAmount(OptionalAmount::Constant, accumulator, Beg);
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000085
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000086 break;
87 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000088
89 return OptionalAmount();
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000090}
91
Ted Kremenekefaff192010-02-27 01:41:03 +000092static OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
93 unsigned &argIndex) {
94 if (*Beg == '*') {
95 ++Beg;
96 return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg);
97 }
98
99 return ParseAmount(Beg, E);
100}
101
102static OptionalAmount ParsePositionAmount(FormatStringHandler &H,
103 const char *Start,
104 const char *&Beg, const char *E,
105 PositionContext p) {
106 if (*Beg == '*') {
107 const char *I = Beg + 1;
108 const OptionalAmount &Amt = ParseAmount(I, E);
109
110 if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
111 H.HandleInvalidPosition(Beg, I - Beg, p);
112 return OptionalAmount(false);
113 }
114
115 if (I== E) {
116 // No more characters left?
117 H.HandleIncompleteFormatSpecifier(Start, E - Start);
118 return OptionalAmount(false);
119 }
120
121 if (*I == '$') {
122 const char *Tmp = Beg;
123 Beg = ++I;
124 return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,
125 Tmp);
126 }
127
128 H.HandleInvalidPosition(Beg, I - Beg, p);
129 return OptionalAmount(false);
130 }
131
132 return ParseAmount(Beg, E);
133}
134
135static bool ParsePrecision(FormatStringHandler &H, FormatSpecifier &FS,
136 const char *Start, const char *&Beg, const char *E,
137 unsigned *argIndex) {
138 if (argIndex) {
139 FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
140 }
141 else {
142 const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
143 analyze_printf::PrecisionPos);
144 if (Amt.isInvalid())
145 return true;
146 FS.setPrecision(Amt);
147 }
148 return false;
149}
150
151static bool ParseFieldWidth(FormatStringHandler &H, FormatSpecifier &FS,
152 const char *Start, const char *&Beg, const char *E,
153 unsigned *argIndex) {
154 // FIXME: Support negative field widths.
155 if (argIndex) {
156 FS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
157 }
158 else {
159 const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
160 analyze_printf::FieldWidthPos);
161 if (Amt.isInvalid())
162 return true;
163 FS.setFieldWidth(Amt);
164 }
165 return false;
166}
167
168
169static bool ParseArgPosition(FormatStringHandler &H,
170 FormatSpecifier &FS, const char *Start,
171 const char *&Beg, const char *E) {
172
173 using namespace clang::analyze_printf;
174 const char *I = Beg;
175
176 const OptionalAmount &Amt = ParseAmount(I, E);
177
178 if (I == E) {
179 // No more characters left?
180 H.HandleIncompleteFormatSpecifier(Start, E - Start);
181 return true;
182 }
183
184 if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
185 FS.setArgIndex(Amt.getConstantAmount() - 1);
186 FS.setUsesPositionalArg();
187 // Update the caller's pointer if we decided to consume
188 // these characters.
189 Beg = I;
190 return false;
191 }
192
193 // Special case: '%0$', since this is an easy mistake.
194 if (*I == '0' && (I+1) != E && *(I+1) == '$') {
195 H.HandleZeroPosition(Start, I - Start + 2);
196 return true;
197 }
198
199 return false;
200}
201
Ted Kremenek808015a2010-01-29 03:16:21 +0000202static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
Ted Kremenek74d56a12010-02-04 20:46:58 +0000203 const char *&Beg,
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000204 const char *E,
205 unsigned &argIndex) {
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000206
Ted Kremenek4b220fa2010-01-29 02:13:53 +0000207 using namespace clang::analyze_printf;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000208
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000209 const char *I = Beg;
Ted Kremenekc7ae51a2010-01-28 00:02:05 +0000210 const char *Start = 0;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000211 UpdateOnReturn <const char*> UpdateBeg(Beg, I);
212
213 // Look for a '%' character that indicates the start of a format specifier.
Ted Kremeneke729acb2010-01-28 23:56:52 +0000214 for ( ; I != E ; ++I) {
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000215 char c = *I;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000216 if (c == '\0') {
217 // Detect spurious null characters, which are likely errors.
218 H.HandleNullChar(I);
219 return true;
220 }
221 if (c == '%') {
Ted Kremeneke729acb2010-01-28 23:56:52 +0000222 Start = I++; // Record the start of the format specifier.
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000223 break;
224 }
225 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000226
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000227 // No format specifier found?
228 if (!Start)
229 return false;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000230
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000231 if (I == E) {
232 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000233 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000234 return true;
235 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000236
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000237 FormatSpecifier FS;
Ted Kremenekefaff192010-02-27 01:41:03 +0000238 if (ParseArgPosition(H, FS, Start, I, E))
239 return true;
240
241 if (I == E) {
242 // No more characters left?
243 H.HandleIncompleteFormatSpecifier(Start, E - Start);
244 return true;
245 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000246
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000247 // Look for flags (if any).
248 bool hasMore = true;
249 for ( ; I != E; ++I) {
250 switch (*I) {
251 default: hasMore = false; break;
252 case '-': FS.setIsLeftJustified(); break;
253 case '+': FS.setHasPlusPrefix(); break;
254 case ' ': FS.setHasSpacePrefix(); break;
255 case '#': FS.setHasAlternativeForm(); break;
256 case '0': FS.setHasLeadingZeros(); break;
257 }
258 if (!hasMore)
259 break;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000260 }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000261
262 if (I == E) {
263 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000264 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000265 return true;
266 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000267
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000268 // Look for the field width (if any).
Ted Kremenekefaff192010-02-27 01:41:03 +0000269 if (ParseFieldWidth(H, FS, Start, I, E,
270 FS.usesPositionalArg() ? 0 : &argIndex))
271 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000272
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000273 if (I == E) {
274 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000275 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000276 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000277 }
278
279 // Look for the precision (if any).
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000280 if (*I == '.') {
Ted Kremenek808015a2010-01-29 03:16:21 +0000281 ++I;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000282 if (I == E) {
Ted Kremenek808015a2010-01-29 03:16:21 +0000283 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000284 return true;
285 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000286
Ted Kremenekefaff192010-02-27 01:41:03 +0000287 if (ParsePrecision(H, FS, Start, I, E,
288 FS.usesPositionalArg() ? 0 : &argIndex))
289 return true;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000290
291 if (I == E) {
292 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000293 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000294 return true;
295 }
296 }
297
298 // Look for the length modifier.
299 LengthModifier lm = None;
300 switch (*I) {
301 default:
302 break;
303 case 'h':
304 ++I;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000305 lm = (I != E && *I == 'h') ? ++I, AsChar : AsShort;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000306 break;
307 case 'l':
308 ++I;
309 lm = (I != E && *I == 'l') ? ++I, AsLongLong : AsLong;
310 break;
311 case 'j': lm = AsIntMax; ++I; break;
312 case 'z': lm = AsSizeT; ++I; break;
313 case 't': lm = AsPtrDiff; ++I; break;
314 case 'L': lm = AsLongDouble; ++I; break;
Daniel Dunbar01aefc62010-01-30 15:49:20 +0000315 case 'q': lm = AsLongLong; ++I; break;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000316 }
317 FS.setLengthModifier(lm);
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000318
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000319 if (I == E) {
320 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000321 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000322 return true;
323 }
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000324
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000325 if (*I == '\0') {
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000326 // Detect spurious null characters, which are likely errors.
327 H.HandleNullChar(I);
328 return true;
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000329 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000330
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000331 // Finally, look for the conversion specifier.
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000332 const char *conversionPosition = I++;
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000333 ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000334 switch (*conversionPosition) {
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000335 default:
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000336 break;
Ted Kremenekc7cbb9b2010-01-28 00:55:28 +0000337 // C99: 7.19.6.1 (section 8).
Ted Kremenek87260c72010-02-24 00:05:54 +0000338 case '%': k = ConversionSpecifier::PercentArg; break;
339 case 'A': k = ConversionSpecifier::AArg; break;
340 case 'E': k = ConversionSpecifier::EArg; break;
341 case 'F': k = ConversionSpecifier::FArg; break;
342 case 'G': k = ConversionSpecifier::GArg; break;
343 case 'X': k = ConversionSpecifier::XArg; break;
344 case 'a': k = ConversionSpecifier::aArg; break;
345 case 'c': k = ConversionSpecifier::IntAsCharArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000346 case 'd': k = ConversionSpecifier::dArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000347 case 'e': k = ConversionSpecifier::eArg; break;
348 case 'f': k = ConversionSpecifier::fArg; break;
349 case 'g': k = ConversionSpecifier::gArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000350 case 'i': k = ConversionSpecifier::iArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000351 case 'n': k = ConversionSpecifier::OutIntPtrArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000352 case 'o': k = ConversionSpecifier::oArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000353 case 'p': k = ConversionSpecifier::VoidPtrArg; break;
354 case 's': k = ConversionSpecifier::CStrArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000355 case 'u': k = ConversionSpecifier::uArg; break;
356 case 'x': k = ConversionSpecifier::xArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000357 // Mac OS X (unicode) specific
358 case 'C': k = ConversionSpecifier::CArg; break;
359 case 'S': k = ConversionSpecifier::UnicodeStrArg; break;
Ted Kremenekc7cbb9b2010-01-28 00:55:28 +0000360 // Objective-C.
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000361 case '@': k = ConversionSpecifier::ObjCObjArg; break;
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000362 // Glibc specific.
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000363 case 'm': k = ConversionSpecifier::PrintErrno; break;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000364 }
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000365 ConversionSpecifier CS(conversionPosition, k);
366 FS.setConversionSpecifier(CS);
Ted Kremenekefaff192010-02-27 01:41:03 +0000367 if (CS.consumesDataArgument() && !FS.usesPositionalArg())
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000368 FS.setArgIndex(argIndex++);
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000369
370 if (k == ConversionSpecifier::InvalidSpecifier) {
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000371 // Assume the conversion takes one argument.
372 return !H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg);
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000373 }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000374 return FormatSpecifierResult(Start, FS);
375}
376
Ted Kremenek74d56a12010-02-04 20:46:58 +0000377bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H,
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000378 const char *I, const char *E) {
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000379
380 unsigned argIndex = 0;
381
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000382 // Keep looking for a format specifier until we have exhausted the string.
383 while (I != E) {
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000384 const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E, argIndex);
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000385 // Did a fail-stop error of any kind occur when parsing the specifier?
386 // If so, don't do any more processing.
387 if (FSR.shouldStop())
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000388 return true;;
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000389 // Did we exhaust the string or encounter an error that
390 // we can recover from?
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000391 if (!FSR.hasValue())
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000392 continue;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000393 // We have a format specifier. Pass it to the callback.
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000394 if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(),
395 I - FSR.getStart()))
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000396 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000397 }
398 assert(I == E && "Format string not exhausted");
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000399 return false;
400}
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000401
402FormatStringHandler::~FormatStringHandler() {}
Ted Kremenek33567d22010-01-29 22:59:32 +0000403
404//===----------------------------------------------------------------------===//
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000405// Methods on ArgTypeResult.
406//===----------------------------------------------------------------------===//
407
408bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
409 assert(isValid());
410
411 if (K == UnknownTy)
412 return true;
413
414 if (K == SpecificTy) {
415 argTy = C.getCanonicalType(argTy).getUnqualifiedType();
416
417 if (T == argTy)
418 return true;
419
420 if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
421 switch (BT->getKind()) {
422 default:
423 break;
424 case BuiltinType::Char_S:
425 case BuiltinType::SChar:
426 return T == C.UnsignedCharTy;
427 case BuiltinType::Char_U:
428 case BuiltinType::UChar:
429 return T == C.SignedCharTy;
430 case BuiltinType::Short:
431 return T == C.UnsignedShortTy;
432 case BuiltinType::UShort:
433 return T == C.ShortTy;
434 case BuiltinType::Int:
435 return T == C.UnsignedIntTy;
436 case BuiltinType::UInt:
437 return T == C.IntTy;
438 case BuiltinType::Long:
439 return T == C.UnsignedLongTy;
440 case BuiltinType::ULong:
441 return T == C.LongTy;
442 case BuiltinType::LongLong:
443 return T == C.UnsignedLongLongTy;
444 case BuiltinType::ULongLong:
445 return T == C.LongLongTy;
446 }
447
448 return false;
449 }
450
451 if (K == CStrTy) {
452 const PointerType *PT = argTy->getAs<PointerType>();
453 if (!PT)
454 return false;
455
456 QualType pointeeTy = PT->getPointeeType();
457
458 if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
459 switch (BT->getKind()) {
460 case BuiltinType::Void:
461 case BuiltinType::Char_U:
462 case BuiltinType::UChar:
463 case BuiltinType::Char_S:
464 case BuiltinType::SChar:
465 return true;
466 default:
467 break;
468 }
469
470 return false;
471 }
472
473 if (K == WCStrTy) {
474 const PointerType *PT = argTy->getAs<PointerType>();
475 if (!PT)
476 return false;
477
Ted Kremenek87260c72010-02-24 00:05:54 +0000478 QualType pointeeTy =
479 C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
480
481 return pointeeTy == C.getWCharType();
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000482 }
483
484 return false;
485}
486
487QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
488 assert(isValid());
489 if (K == SpecificTy)
490 return T;
491 if (K == CStrTy)
492 return C.getPointerType(C.CharTy);
493 if (K == WCStrTy)
Ted Kremenek87260c72010-02-24 00:05:54 +0000494 return C.getPointerType(C.getWCharType());
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000495 if (K == ObjCPointerTy)
496 return C.ObjCBuiltinIdTy;
497
498 return QualType();
499}
500
501//===----------------------------------------------------------------------===//
502// Methods on OptionalAmount.
503//===----------------------------------------------------------------------===//
504
505ArgTypeResult OptionalAmount::getArgType(ASTContext &Ctx) const {
506 return Ctx.IntTy;
507}
508
509//===----------------------------------------------------------------------===//
Ted Kremenek33567d22010-01-29 22:59:32 +0000510// Methods on FormatSpecifier.
511//===----------------------------------------------------------------------===//
512
513ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const {
514 if (!CS.consumesDataArgument())
515 return ArgTypeResult::Invalid();
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000516
Ted Kremenek33567d22010-01-29 22:59:32 +0000517 if (CS.isIntArg())
518 switch (LM) {
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000519 case AsLongDouble:
Ted Kremenek33567d22010-01-29 22:59:32 +0000520 return ArgTypeResult::Invalid();
521 case None: return Ctx.IntTy;
522 case AsChar: return Ctx.SignedCharTy;
523 case AsShort: return Ctx.ShortTy;
524 case AsLong: return Ctx.LongTy;
525 case AsLongLong: return Ctx.LongLongTy;
526 case AsIntMax:
527 // FIXME: Return unknown for now.
528 return ArgTypeResult();
529 case AsSizeT: return Ctx.getSizeType();
530 case AsPtrDiff: return Ctx.getPointerDiffType();
531 }
532
533 if (CS.isUIntArg())
534 switch (LM) {
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000535 case AsLongDouble:
Ted Kremenek33567d22010-01-29 22:59:32 +0000536 return ArgTypeResult::Invalid();
537 case None: return Ctx.UnsignedIntTy;
538 case AsChar: return Ctx.UnsignedCharTy;
539 case AsShort: return Ctx.UnsignedShortTy;
540 case AsLong: return Ctx.UnsignedLongTy;
541 case AsLongLong: return Ctx.UnsignedLongLongTy;
542 case AsIntMax:
543 // FIXME: Return unknown for now.
544 return ArgTypeResult();
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000545 case AsSizeT:
Ted Kremenek33567d22010-01-29 22:59:32 +0000546 // FIXME: How to get the corresponding unsigned
547 // version of size_t?
548 return ArgTypeResult();
549 case AsPtrDiff:
550 // FIXME: How to get the corresponding unsigned
551 // version of ptrdiff_t?
552 return ArgTypeResult();
553 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000554
Ted Kremenekf911eba2010-02-01 23:23:50 +0000555 if (CS.isDoubleArg()) {
556 if (LM == AsLongDouble)
557 return Ctx.LongDoubleTy;
Ted Kremenekc9a89fe2010-01-30 01:02:18 +0000558 return Ctx.DoubleTy;
Ted Kremenekf911eba2010-02-01 23:23:50 +0000559 }
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000560
Ted Kremenek87260c72010-02-24 00:05:54 +0000561 switch (CS.getKind()) {
562 case ConversionSpecifier::CStrArg:
563 return ArgTypeResult(LM == AsWideChar ? ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy);
564 case ConversionSpecifier::UnicodeStrArg:
565 // FIXME: This appears to be Mac OS X specific.
566 return ArgTypeResult::WCStrTy;
567 case ConversionSpecifier::CArg:
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000568 return Ctx.WCharTy;
Ted Kremenek87260c72010-02-24 00:05:54 +0000569 default:
570 break;
571 }
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000572
Ted Kremenek33567d22010-01-29 22:59:32 +0000573 // FIXME: Handle other cases.
Ted Kremenek40888ad2010-01-29 23:00:35 +0000574 return ArgTypeResult();
Ted Kremenek33567d22010-01-29 22:59:32 +0000575}
576