blob: c38aae34764c9af6f97cda28bace3909f03661d6 [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;
Ted Kremenekd49d8772010-03-01 19:22:33 +000072 bool hasDigits = false;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000073
74 for ( ; I != E; ++I) {
75 char c = *I;
76 if (c >= '0' && c <= '9') {
Ted Kremenekd49d8772010-03-01 19:22:33 +000077 hasDigits = true;
Ted Kremenekfdb703a2010-03-25 03:59:09 +000078 accumulator = (accumulator * 10) + (c - '0');
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000079 continue;
80 }
81
Ted Kremenekd49d8772010-03-01 19:22:33 +000082 if (hasDigits)
Ted Kremenek7f70dc82010-02-26 19:18:41 +000083 return OptionalAmount(OptionalAmount::Constant, accumulator, Beg);
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000084
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000085 break;
86 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000087
88 return OptionalAmount();
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000089}
90
Ted Kremenekefaff192010-02-27 01:41:03 +000091static OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
92 unsigned &argIndex) {
93 if (*Beg == '*') {
94 ++Beg;
95 return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg);
96 }
97
98 return ParseAmount(Beg, E);
99}
100
101static OptionalAmount ParsePositionAmount(FormatStringHandler &H,
102 const char *Start,
103 const char *&Beg, const char *E,
104 PositionContext p) {
105 if (*Beg == '*') {
106 const char *I = Beg + 1;
107 const OptionalAmount &Amt = ParseAmount(I, E);
108
109 if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
110 H.HandleInvalidPosition(Beg, I - Beg, p);
111 return OptionalAmount(false);
112 }
113
114 if (I== E) {
115 // No more characters left?
116 H.HandleIncompleteFormatSpecifier(Start, E - Start);
117 return OptionalAmount(false);
118 }
119
Ted Kremenekd49d8772010-03-01 19:22:33 +0000120 assert(Amt.getHowSpecified() == OptionalAmount::Constant);
121
Ted Kremenekefaff192010-02-27 01:41:03 +0000122 if (*I == '$') {
Ted Kremenekd49d8772010-03-01 19:22:33 +0000123 // Special case: '*0$', since this is an easy mistake.
124 if (Amt.getConstantAmount() == 0) {
125 H.HandleZeroPosition(Beg, I - Beg + 1);
126 return OptionalAmount(false);
127 }
128
Ted Kremenekefaff192010-02-27 01:41:03 +0000129 const char *Tmp = Beg;
130 Beg = ++I;
Ted Kremenekd49d8772010-03-01 19:22:33 +0000131
Ted Kremenekefaff192010-02-27 01:41:03 +0000132 return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,
133 Tmp);
134 }
135
136 H.HandleInvalidPosition(Beg, I - Beg, p);
137 return OptionalAmount(false);
138 }
139
140 return ParseAmount(Beg, E);
141}
142
143static bool ParsePrecision(FormatStringHandler &H, FormatSpecifier &FS,
144 const char *Start, const char *&Beg, const char *E,
145 unsigned *argIndex) {
146 if (argIndex) {
147 FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
148 }
149 else {
150 const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
151 analyze_printf::PrecisionPos);
152 if (Amt.isInvalid())
153 return true;
154 FS.setPrecision(Amt);
155 }
156 return false;
157}
158
159static bool ParseFieldWidth(FormatStringHandler &H, FormatSpecifier &FS,
160 const char *Start, const char *&Beg, const char *E,
161 unsigned *argIndex) {
162 // FIXME: Support negative field widths.
163 if (argIndex) {
164 FS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
165 }
166 else {
167 const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
168 analyze_printf::FieldWidthPos);
169 if (Amt.isInvalid())
170 return true;
171 FS.setFieldWidth(Amt);
172 }
173 return false;
174}
175
176
177static bool ParseArgPosition(FormatStringHandler &H,
178 FormatSpecifier &FS, const char *Start,
179 const char *&Beg, const char *E) {
180
181 using namespace clang::analyze_printf;
182 const char *I = Beg;
183
184 const OptionalAmount &Amt = ParseAmount(I, E);
185
186 if (I == E) {
187 // No more characters left?
188 H.HandleIncompleteFormatSpecifier(Start, E - Start);
189 return true;
190 }
191
192 if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
Ted Kremenekd49d8772010-03-01 19:22:33 +0000193 // Special case: '%0$', since this is an easy mistake.
194 if (Amt.getConstantAmount() == 0) {
195 H.HandleZeroPosition(Start, I - Start);
196 return true;
197 }
198
Ted Kremenekefaff192010-02-27 01:41:03 +0000199 FS.setArgIndex(Amt.getConstantAmount() - 1);
200 FS.setUsesPositionalArg();
201 // Update the caller's pointer if we decided to consume
202 // these characters.
203 Beg = I;
204 return false;
205 }
206
Ted Kremenekefaff192010-02-27 01:41:03 +0000207 return false;
208}
209
Ted Kremenek808015a2010-01-29 03:16:21 +0000210static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
Ted Kremenek74d56a12010-02-04 20:46:58 +0000211 const char *&Beg,
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000212 const char *E,
213 unsigned &argIndex) {
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000214
Ted Kremenek4b220fa2010-01-29 02:13:53 +0000215 using namespace clang::analyze_printf;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000216
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000217 const char *I = Beg;
Ted Kremenekc7ae51a2010-01-28 00:02:05 +0000218 const char *Start = 0;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000219 UpdateOnReturn <const char*> UpdateBeg(Beg, I);
220
221 // Look for a '%' character that indicates the start of a format specifier.
Ted Kremeneke729acb2010-01-28 23:56:52 +0000222 for ( ; I != E ; ++I) {
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000223 char c = *I;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000224 if (c == '\0') {
225 // Detect spurious null characters, which are likely errors.
226 H.HandleNullChar(I);
227 return true;
228 }
229 if (c == '%') {
Ted Kremeneke729acb2010-01-28 23:56:52 +0000230 Start = I++; // Record the start of the format specifier.
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000231 break;
232 }
233 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000234
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000235 // No format specifier found?
236 if (!Start)
237 return false;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000238
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000239 if (I == E) {
240 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000241 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000242 return true;
243 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000244
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000245 FormatSpecifier FS;
Ted Kremenekefaff192010-02-27 01:41:03 +0000246 if (ParseArgPosition(H, FS, Start, I, E))
247 return true;
248
249 if (I == E) {
250 // No more characters left?
251 H.HandleIncompleteFormatSpecifier(Start, E - Start);
252 return true;
253 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000254
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000255 // Look for flags (if any).
256 bool hasMore = true;
257 for ( ; I != E; ++I) {
258 switch (*I) {
259 default: hasMore = false; break;
260 case '-': FS.setIsLeftJustified(); break;
261 case '+': FS.setHasPlusPrefix(); break;
262 case ' ': FS.setHasSpacePrefix(); break;
263 case '#': FS.setHasAlternativeForm(); break;
264 case '0': FS.setHasLeadingZeros(); break;
265 }
266 if (!hasMore)
267 break;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000268 }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000269
270 if (I == E) {
271 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000272 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000273 return true;
274 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000275
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000276 // Look for the field width (if any).
Ted Kremenekefaff192010-02-27 01:41:03 +0000277 if (ParseFieldWidth(H, FS, Start, I, E,
278 FS.usesPositionalArg() ? 0 : &argIndex))
279 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000280
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000281 if (I == E) {
282 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000283 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000284 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000285 }
286
287 // Look for the precision (if any).
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000288 if (*I == '.') {
Ted Kremenek808015a2010-01-29 03:16:21 +0000289 ++I;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000290 if (I == E) {
Ted Kremenek808015a2010-01-29 03:16:21 +0000291 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000292 return true;
293 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000294
Ted Kremenekefaff192010-02-27 01:41:03 +0000295 if (ParsePrecision(H, FS, Start, I, E,
296 FS.usesPositionalArg() ? 0 : &argIndex))
297 return true;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000298
299 if (I == E) {
300 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000301 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000302 return true;
303 }
304 }
305
306 // Look for the length modifier.
307 LengthModifier lm = None;
308 switch (*I) {
309 default:
310 break;
311 case 'h':
312 ++I;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000313 lm = (I != E && *I == 'h') ? ++I, AsChar : AsShort;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000314 break;
315 case 'l':
316 ++I;
317 lm = (I != E && *I == 'l') ? ++I, AsLongLong : AsLong;
318 break;
319 case 'j': lm = AsIntMax; ++I; break;
320 case 'z': lm = AsSizeT; ++I; break;
321 case 't': lm = AsPtrDiff; ++I; break;
322 case 'L': lm = AsLongDouble; ++I; break;
Daniel Dunbar01aefc62010-01-30 15:49:20 +0000323 case 'q': lm = AsLongLong; ++I; break;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000324 }
325 FS.setLengthModifier(lm);
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000326
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000327 if (I == E) {
328 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000329 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000330 return true;
331 }
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000332
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000333 if (*I == '\0') {
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000334 // Detect spurious null characters, which are likely errors.
335 H.HandleNullChar(I);
336 return true;
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000337 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000338
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000339 // Finally, look for the conversion specifier.
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000340 const char *conversionPosition = I++;
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000341 ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000342 switch (*conversionPosition) {
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000343 default:
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000344 break;
Ted Kremenekc7cbb9b2010-01-28 00:55:28 +0000345 // C99: 7.19.6.1 (section 8).
Ted Kremenek87260c72010-02-24 00:05:54 +0000346 case '%': k = ConversionSpecifier::PercentArg; break;
347 case 'A': k = ConversionSpecifier::AArg; break;
348 case 'E': k = ConversionSpecifier::EArg; break;
349 case 'F': k = ConversionSpecifier::FArg; break;
350 case 'G': k = ConversionSpecifier::GArg; break;
351 case 'X': k = ConversionSpecifier::XArg; break;
352 case 'a': k = ConversionSpecifier::aArg; break;
353 case 'c': k = ConversionSpecifier::IntAsCharArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000354 case 'd': k = ConversionSpecifier::dArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000355 case 'e': k = ConversionSpecifier::eArg; break;
356 case 'f': k = ConversionSpecifier::fArg; break;
357 case 'g': k = ConversionSpecifier::gArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000358 case 'i': k = ConversionSpecifier::iArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000359 case 'n': k = ConversionSpecifier::OutIntPtrArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000360 case 'o': k = ConversionSpecifier::oArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000361 case 'p': k = ConversionSpecifier::VoidPtrArg; break;
362 case 's': k = ConversionSpecifier::CStrArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000363 case 'u': k = ConversionSpecifier::uArg; break;
364 case 'x': k = ConversionSpecifier::xArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000365 // Mac OS X (unicode) specific
366 case 'C': k = ConversionSpecifier::CArg; break;
367 case 'S': k = ConversionSpecifier::UnicodeStrArg; break;
Ted Kremenekc7cbb9b2010-01-28 00:55:28 +0000368 // Objective-C.
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000369 case '@': k = ConversionSpecifier::ObjCObjArg; break;
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000370 // Glibc specific.
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000371 case 'm': k = ConversionSpecifier::PrintErrno; break;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000372 }
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000373 ConversionSpecifier CS(conversionPosition, k);
374 FS.setConversionSpecifier(CS);
Ted Kremenekefaff192010-02-27 01:41:03 +0000375 if (CS.consumesDataArgument() && !FS.usesPositionalArg())
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000376 FS.setArgIndex(argIndex++);
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000377
378 if (k == ConversionSpecifier::InvalidSpecifier) {
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000379 // Assume the conversion takes one argument.
380 return !H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg);
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000381 }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000382 return FormatSpecifierResult(Start, FS);
383}
384
Ted Kremenek74d56a12010-02-04 20:46:58 +0000385bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H,
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000386 const char *I, const char *E) {
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000387
388 unsigned argIndex = 0;
389
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000390 // Keep looking for a format specifier until we have exhausted the string.
391 while (I != E) {
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000392 const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E, argIndex);
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000393 // Did a fail-stop error of any kind occur when parsing the specifier?
394 // If so, don't do any more processing.
395 if (FSR.shouldStop())
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000396 return true;;
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000397 // Did we exhaust the string or encounter an error that
398 // we can recover from?
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000399 if (!FSR.hasValue())
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000400 continue;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000401 // We have a format specifier. Pass it to the callback.
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000402 if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(),
403 I - FSR.getStart()))
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000404 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000405 }
406 assert(I == E && "Format string not exhausted");
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000407 return false;
408}
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000409
410FormatStringHandler::~FormatStringHandler() {}
Ted Kremenek33567d22010-01-29 22:59:32 +0000411
412//===----------------------------------------------------------------------===//
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000413// Methods on ArgTypeResult.
414//===----------------------------------------------------------------------===//
415
416bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
417 assert(isValid());
418
419 if (K == UnknownTy)
420 return true;
421
422 if (K == SpecificTy) {
423 argTy = C.getCanonicalType(argTy).getUnqualifiedType();
424
425 if (T == argTy)
426 return true;
427
428 if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
429 switch (BT->getKind()) {
430 default:
431 break;
432 case BuiltinType::Char_S:
433 case BuiltinType::SChar:
434 return T == C.UnsignedCharTy;
435 case BuiltinType::Char_U:
436 case BuiltinType::UChar:
437 return T == C.SignedCharTy;
438 case BuiltinType::Short:
439 return T == C.UnsignedShortTy;
440 case BuiltinType::UShort:
441 return T == C.ShortTy;
442 case BuiltinType::Int:
443 return T == C.UnsignedIntTy;
444 case BuiltinType::UInt:
445 return T == C.IntTy;
446 case BuiltinType::Long:
447 return T == C.UnsignedLongTy;
448 case BuiltinType::ULong:
449 return T == C.LongTy;
450 case BuiltinType::LongLong:
451 return T == C.UnsignedLongLongTy;
452 case BuiltinType::ULongLong:
453 return T == C.LongLongTy;
454 }
455
456 return false;
457 }
458
459 if (K == CStrTy) {
460 const PointerType *PT = argTy->getAs<PointerType>();
461 if (!PT)
462 return false;
463
464 QualType pointeeTy = PT->getPointeeType();
465
466 if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
467 switch (BT->getKind()) {
468 case BuiltinType::Void:
469 case BuiltinType::Char_U:
470 case BuiltinType::UChar:
471 case BuiltinType::Char_S:
472 case BuiltinType::SChar:
473 return true;
474 default:
475 break;
476 }
477
478 return false;
479 }
480
481 if (K == WCStrTy) {
482 const PointerType *PT = argTy->getAs<PointerType>();
483 if (!PT)
484 return false;
485
Ted Kremenek87260c72010-02-24 00:05:54 +0000486 QualType pointeeTy =
487 C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
488
489 return pointeeTy == C.getWCharType();
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000490 }
491
492 return false;
493}
494
495QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
496 assert(isValid());
497 if (K == SpecificTy)
498 return T;
499 if (K == CStrTy)
500 return C.getPointerType(C.CharTy);
501 if (K == WCStrTy)
Ted Kremenek87260c72010-02-24 00:05:54 +0000502 return C.getPointerType(C.getWCharType());
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000503 if (K == ObjCPointerTy)
504 return C.ObjCBuiltinIdTy;
505
506 return QualType();
507}
508
509//===----------------------------------------------------------------------===//
510// Methods on OptionalAmount.
511//===----------------------------------------------------------------------===//
512
513ArgTypeResult OptionalAmount::getArgType(ASTContext &Ctx) const {
514 return Ctx.IntTy;
515}
516
517//===----------------------------------------------------------------------===//
Ted Kremenek33567d22010-01-29 22:59:32 +0000518// Methods on FormatSpecifier.
519//===----------------------------------------------------------------------===//
520
521ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const {
522 if (!CS.consumesDataArgument())
523 return ArgTypeResult::Invalid();
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000524
Ted Kremenek33567d22010-01-29 22:59:32 +0000525 if (CS.isIntArg())
526 switch (LM) {
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000527 case AsLongDouble:
Ted Kremenek33567d22010-01-29 22:59:32 +0000528 return ArgTypeResult::Invalid();
529 case None: return Ctx.IntTy;
530 case AsChar: return Ctx.SignedCharTy;
531 case AsShort: return Ctx.ShortTy;
532 case AsLong: return Ctx.LongTy;
533 case AsLongLong: return Ctx.LongLongTy;
534 case AsIntMax:
535 // FIXME: Return unknown for now.
536 return ArgTypeResult();
537 case AsSizeT: return Ctx.getSizeType();
538 case AsPtrDiff: return Ctx.getPointerDiffType();
539 }
540
541 if (CS.isUIntArg())
542 switch (LM) {
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000543 case AsLongDouble:
Ted Kremenek33567d22010-01-29 22:59:32 +0000544 return ArgTypeResult::Invalid();
545 case None: return Ctx.UnsignedIntTy;
546 case AsChar: return Ctx.UnsignedCharTy;
547 case AsShort: return Ctx.UnsignedShortTy;
548 case AsLong: return Ctx.UnsignedLongTy;
549 case AsLongLong: return Ctx.UnsignedLongLongTy;
550 case AsIntMax:
551 // FIXME: Return unknown for now.
552 return ArgTypeResult();
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000553 case AsSizeT:
Ted Kremenek33567d22010-01-29 22:59:32 +0000554 // FIXME: How to get the corresponding unsigned
555 // version of size_t?
556 return ArgTypeResult();
557 case AsPtrDiff:
558 // FIXME: How to get the corresponding unsigned
559 // version of ptrdiff_t?
560 return ArgTypeResult();
561 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000562
Ted Kremenekf911eba2010-02-01 23:23:50 +0000563 if (CS.isDoubleArg()) {
564 if (LM == AsLongDouble)
565 return Ctx.LongDoubleTy;
Ted Kremenekc9a89fe2010-01-30 01:02:18 +0000566 return Ctx.DoubleTy;
Ted Kremenekf911eba2010-02-01 23:23:50 +0000567 }
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000568
Ted Kremenek87260c72010-02-24 00:05:54 +0000569 switch (CS.getKind()) {
570 case ConversionSpecifier::CStrArg:
571 return ArgTypeResult(LM == AsWideChar ? ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy);
572 case ConversionSpecifier::UnicodeStrArg:
573 // FIXME: This appears to be Mac OS X specific.
574 return ArgTypeResult::WCStrTy;
575 case ConversionSpecifier::CArg:
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000576 return Ctx.WCharTy;
Ted Kremenek87260c72010-02-24 00:05:54 +0000577 default:
578 break;
579 }
Ted Kremenek7f70dc82010-02-26 19:18:41 +0000580
Ted Kremenek33567d22010-01-29 22:59:32 +0000581 // FIXME: Handle other cases.
Ted Kremenek40888ad2010-01-29 23:00:35 +0000582 return ArgTypeResult();
Ted Kremenek33567d22010-01-29 22:59:32 +0000583}
584