blob: 3aee57cb81966876f121b472e89ce37d45a952de [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 Kremenek4b220fa2010-01-29 02:13:53 +000018using clang::analyze_printf::FormatSpecifier;
19using clang::analyze_printf::OptionalAmount;
Ted Kremenek33567d22010-01-29 22:59:32 +000020using clang::analyze_printf::ArgTypeResult;
Ted Kremenek74d56a12010-02-04 20:46:58 +000021using clang::analyze_printf::FormatStringHandler;
Ted Kremenek808015a2010-01-29 03:16:21 +000022using namespace clang;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000023
24namespace {
25class FormatSpecifierResult {
26 FormatSpecifier FS;
27 const char *Start;
Ted Kremenek26ac2e02010-01-29 02:40:24 +000028 bool Stop;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000029public:
Ted Kremenek26ac2e02010-01-29 02:40:24 +000030 FormatSpecifierResult(bool stop = false)
31 : Start(0), Stop(stop) {}
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000032 FormatSpecifierResult(const char *start,
Ted Kremenekd2dcece2010-01-28 02:02:59 +000033 const FormatSpecifier &fs)
Ted Kremenek26ac2e02010-01-29 02:40:24 +000034 : FS(fs), Start(start), Stop(false) {}
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000035
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000036
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000037 const char *getStart() const { return Start; }
Ted Kremenek26ac2e02010-01-29 02:40:24 +000038 bool shouldStop() const { return Stop; }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000039 bool hasValue() const { return Start != 0; }
40 const FormatSpecifier &getValue() const {
41 assert(hasValue());
42 return FS;
43 }
Ted Kremenekd2dcece2010-01-28 02:02:59 +000044 const FormatSpecifier &getValue() { return FS; }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000045};
46} // end anonymous namespace
47
48template <typename T>
49class UpdateOnReturn {
50 T &ValueToUpdate;
51 const T &ValueToCopy;
52public:
53 UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
54 : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000055
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000056 ~UpdateOnReturn() {
57 ValueToUpdate = ValueToCopy;
58 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000059};
60
61//===----------------------------------------------------------------------===//
62// Methods for parsing format strings.
63//===----------------------------------------------------------------------===//
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000064
65static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
66 const char *I = Beg;
67 UpdateOnReturn <const char*> UpdateBeg(Beg, I);
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000068
Ted Kremenek8f0a1c72010-01-27 23:43:25 +000069 bool foundDigits = false;
70 unsigned accumulator = 0;
71
72 for ( ; I != E; ++I) {
73 char c = *I;
74 if (c >= '0' && c <= '9') {
75 foundDigits = true;
76 accumulator += (accumulator * 10) + (c - '0');
77 continue;
78 }
79
80 if (foundDigits)
Ted Kremenek0d277352010-01-29 01:06:55 +000081 return OptionalAmount(accumulator, Beg);
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000082
Ted Kremenek0d277352010-01-29 01:06:55 +000083 if (c == '*') {
84 ++I;
85 return OptionalAmount(OptionalAmount::Arg, Beg);
86 }
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 Kremenek808015a2010-01-29 03:16:21 +000094static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
Ted Kremenek74d56a12010-02-04 20:46:58 +000095 const char *&Beg,
96 const char *E) {
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000097
Ted Kremenek4b220fa2010-01-29 02:13:53 +000098 using namespace clang::analyze_printf;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +000099
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000100 const char *I = Beg;
Ted Kremenekc7ae51a2010-01-28 00:02:05 +0000101 const char *Start = 0;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000102 UpdateOnReturn <const char*> UpdateBeg(Beg, I);
103
104 // Look for a '%' character that indicates the start of a format specifier.
Ted Kremeneke729acb2010-01-28 23:56:52 +0000105 for ( ; I != E ; ++I) {
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000106 char c = *I;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000107 if (c == '\0') {
108 // Detect spurious null characters, which are likely errors.
109 H.HandleNullChar(I);
110 return true;
111 }
112 if (c == '%') {
Ted Kremeneke729acb2010-01-28 23:56:52 +0000113 Start = I++; // Record the start of the format specifier.
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000114 break;
115 }
116 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000117
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000118 // No format specifier found?
119 if (!Start)
120 return false;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000121
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000122 if (I == E) {
123 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000124 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000125 return true;
126 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000127
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000128 FormatSpecifier FS;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000129
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000130 // Look for flags (if any).
131 bool hasMore = true;
132 for ( ; I != E; ++I) {
133 switch (*I) {
134 default: hasMore = false; break;
135 case '-': FS.setIsLeftJustified(); break;
136 case '+': FS.setHasPlusPrefix(); break;
137 case ' ': FS.setHasSpacePrefix(); break;
138 case '#': FS.setHasAlternativeForm(); break;
139 case '0': FS.setHasLeadingZeros(); break;
140 }
141 if (!hasMore)
142 break;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000143 }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000144
145 if (I == E) {
146 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000147 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000148 return true;
149 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000150
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000151 // Look for the field width (if any).
152 FS.setFieldWidth(ParseAmount(I, E));
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000153
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000154 if (I == E) {
155 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000156 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000157 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000158 }
159
160 // Look for the precision (if any).
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000161 if (*I == '.') {
Ted Kremenek808015a2010-01-29 03:16:21 +0000162 ++I;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000163 if (I == E) {
Ted Kremenek808015a2010-01-29 03:16:21 +0000164 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000165 return true;
166 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000167
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000168 FS.setPrecision(ParseAmount(I, E));
169
170 if (I == E) {
171 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000172 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000173 return true;
174 }
175 }
176
177 // Look for the length modifier.
178 LengthModifier lm = None;
179 switch (*I) {
180 default:
181 break;
182 case 'h':
183 ++I;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000184 lm = (I != E && *I == 'h') ? ++I, AsChar : AsShort;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000185 break;
186 case 'l':
187 ++I;
188 lm = (I != E && *I == 'l') ? ++I, AsLongLong : AsLong;
189 break;
190 case 'j': lm = AsIntMax; ++I; break;
191 case 'z': lm = AsSizeT; ++I; break;
192 case 't': lm = AsPtrDiff; ++I; break;
193 case 'L': lm = AsLongDouble; ++I; break;
Daniel Dunbar01aefc62010-01-30 15:49:20 +0000194 case 'q': lm = AsLongLong; ++I; break;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000195 }
196 FS.setLengthModifier(lm);
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000197
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000198 if (I == E) {
199 // No more characters left?
Ted Kremenek808015a2010-01-29 03:16:21 +0000200 H.HandleIncompleteFormatSpecifier(Start, E - Start);
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000201 return true;
202 }
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000203
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000204 if (*I == '\0') {
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000205 // Detect spurious null characters, which are likely errors.
206 H.HandleNullChar(I);
207 return true;
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000208 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000209
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000210 // Finally, look for the conversion specifier.
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000211 const char *conversionPosition = I++;
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000212 ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000213 switch (*conversionPosition) {
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000214 default:
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000215 break;
Ted Kremenekc7cbb9b2010-01-28 00:55:28 +0000216 // C99: 7.19.6.1 (section 8).
Ted Kremenek87260c72010-02-24 00:05:54 +0000217 case '%': k = ConversionSpecifier::PercentArg; break;
218 case 'A': k = ConversionSpecifier::AArg; break;
219 case 'E': k = ConversionSpecifier::EArg; break;
220 case 'F': k = ConversionSpecifier::FArg; break;
221 case 'G': k = ConversionSpecifier::GArg; break;
222 case 'X': k = ConversionSpecifier::XArg; break;
223 case 'a': k = ConversionSpecifier::aArg; break;
224 case 'c': k = ConversionSpecifier::IntAsCharArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000225 case 'd': k = ConversionSpecifier::dArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000226 case 'e': k = ConversionSpecifier::eArg; break;
227 case 'f': k = ConversionSpecifier::fArg; break;
228 case 'g': k = ConversionSpecifier::gArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000229 case 'i': k = ConversionSpecifier::iArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000230 case 'n': k = ConversionSpecifier::OutIntPtrArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000231 case 'o': k = ConversionSpecifier::oArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000232 case 'p': k = ConversionSpecifier::VoidPtrArg; break;
233 case 's': k = ConversionSpecifier::CStrArg; break;
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000234 case 'u': k = ConversionSpecifier::uArg; break;
235 case 'x': k = ConversionSpecifier::xArg; break;
Ted Kremenek87260c72010-02-24 00:05:54 +0000236 // Mac OS X (unicode) specific
237 case 'C': k = ConversionSpecifier::CArg; break;
238 case 'S': k = ConversionSpecifier::UnicodeStrArg; break;
Ted Kremenekc7cbb9b2010-01-28 00:55:28 +0000239 // Objective-C.
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000240 case '@': k = ConversionSpecifier::ObjCObjArg; break;
Ted Kremenekdf17f9d2010-02-09 00:04:09 +0000241 // Glibc specific.
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000242 case 'm': k = ConversionSpecifier::PrintErrno; break;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000243 }
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000244 FS.setConversionSpecifier(ConversionSpecifier(conversionPosition, k));
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000245
246 if (k == ConversionSpecifier::InvalidSpecifier) {
247 H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg);
248 return false; // Keep processing format specifiers.
249 }
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000250 return FormatSpecifierResult(Start, FS);
251}
252
Ted Kremenek74d56a12010-02-04 20:46:58 +0000253bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H,
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000254 const char *I, const char *E) {
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000255 // Keep looking for a format specifier until we have exhausted the string.
256 while (I != E) {
257 const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E);
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000258 // Did a fail-stop error of any kind occur when parsing the specifier?
259 // If so, don't do any more processing.
260 if (FSR.shouldStop())
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000261 return true;;
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000262 // Did we exhaust the string or encounter an error that
263 // we can recover from?
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000264 if (!FSR.hasValue())
Ted Kremenek26ac2e02010-01-29 02:40:24 +0000265 continue;
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000266 // We have a format specifier. Pass it to the callback.
Ted Kremeneka8d8fec2010-01-28 02:46:17 +0000267 if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(),
268 I - FSR.getStart()))
Ted Kremenek4dcb18f2010-01-29 20:29:53 +0000269 return true;
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000270 }
271 assert(I == E && "Format string not exhausted");
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000272 return false;
273}
Ted Kremenek8f0a1c72010-01-27 23:43:25 +0000274
275FormatStringHandler::~FormatStringHandler() {}
Ted Kremenek33567d22010-01-29 22:59:32 +0000276
277//===----------------------------------------------------------------------===//
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000278// Methods on ArgTypeResult.
279//===----------------------------------------------------------------------===//
280
281bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
282 assert(isValid());
283
284 if (K == UnknownTy)
285 return true;
286
287 if (K == SpecificTy) {
288 argTy = C.getCanonicalType(argTy).getUnqualifiedType();
289
290 if (T == argTy)
291 return true;
292
293 if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
294 switch (BT->getKind()) {
295 default:
296 break;
297 case BuiltinType::Char_S:
298 case BuiltinType::SChar:
299 return T == C.UnsignedCharTy;
300 case BuiltinType::Char_U:
301 case BuiltinType::UChar:
302 return T == C.SignedCharTy;
303 case BuiltinType::Short:
304 return T == C.UnsignedShortTy;
305 case BuiltinType::UShort:
306 return T == C.ShortTy;
307 case BuiltinType::Int:
308 return T == C.UnsignedIntTy;
309 case BuiltinType::UInt:
310 return T == C.IntTy;
311 case BuiltinType::Long:
312 return T == C.UnsignedLongTy;
313 case BuiltinType::ULong:
314 return T == C.LongTy;
315 case BuiltinType::LongLong:
316 return T == C.UnsignedLongLongTy;
317 case BuiltinType::ULongLong:
318 return T == C.LongLongTy;
319 }
320
321 return false;
322 }
323
324 if (K == CStrTy) {
325 const PointerType *PT = argTy->getAs<PointerType>();
326 if (!PT)
327 return false;
328
329 QualType pointeeTy = PT->getPointeeType();
330
331 if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
332 switch (BT->getKind()) {
333 case BuiltinType::Void:
334 case BuiltinType::Char_U:
335 case BuiltinType::UChar:
336 case BuiltinType::Char_S:
337 case BuiltinType::SChar:
338 return true;
339 default:
340 break;
341 }
342
343 return false;
344 }
345
346 if (K == WCStrTy) {
347 const PointerType *PT = argTy->getAs<PointerType>();
348 if (!PT)
349 return false;
350
Ted Kremenek87260c72010-02-24 00:05:54 +0000351 QualType pointeeTy =
352 C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
353
354 return pointeeTy == C.getWCharType();
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000355 }
356
357 return false;
358}
359
360QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
361 assert(isValid());
362 if (K == SpecificTy)
363 return T;
364 if (K == CStrTy)
365 return C.getPointerType(C.CharTy);
366 if (K == WCStrTy)
Ted Kremenek87260c72010-02-24 00:05:54 +0000367 return C.getPointerType(C.getWCharType());
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000368 if (K == ObjCPointerTy)
369 return C.ObjCBuiltinIdTy;
370
371 return QualType();
372}
373
374//===----------------------------------------------------------------------===//
375// Methods on OptionalAmount.
376//===----------------------------------------------------------------------===//
377
378ArgTypeResult OptionalAmount::getArgType(ASTContext &Ctx) const {
379 return Ctx.IntTy;
380}
381
382//===----------------------------------------------------------------------===//
Ted Kremenek33567d22010-01-29 22:59:32 +0000383// Methods on FormatSpecifier.
384//===----------------------------------------------------------------------===//
385
386ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const {
387 if (!CS.consumesDataArgument())
388 return ArgTypeResult::Invalid();
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000389
Ted Kremenek33567d22010-01-29 22:59:32 +0000390 if (CS.isIntArg())
391 switch (LM) {
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000392 case AsLongDouble:
Ted Kremenek33567d22010-01-29 22:59:32 +0000393 return ArgTypeResult::Invalid();
394 case None: return Ctx.IntTy;
395 case AsChar: return Ctx.SignedCharTy;
396 case AsShort: return Ctx.ShortTy;
397 case AsLong: return Ctx.LongTy;
398 case AsLongLong: return Ctx.LongLongTy;
399 case AsIntMax:
400 // FIXME: Return unknown for now.
401 return ArgTypeResult();
402 case AsSizeT: return Ctx.getSizeType();
403 case AsPtrDiff: return Ctx.getPointerDiffType();
404 }
405
406 if (CS.isUIntArg())
407 switch (LM) {
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000408 case AsLongDouble:
Ted Kremenek33567d22010-01-29 22:59:32 +0000409 return ArgTypeResult::Invalid();
410 case None: return Ctx.UnsignedIntTy;
411 case AsChar: return Ctx.UnsignedCharTy;
412 case AsShort: return Ctx.UnsignedShortTy;
413 case AsLong: return Ctx.UnsignedLongTy;
414 case AsLongLong: return Ctx.UnsignedLongLongTy;
415 case AsIntMax:
416 // FIXME: Return unknown for now.
417 return ArgTypeResult();
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000418 case AsSizeT:
Ted Kremenek33567d22010-01-29 22:59:32 +0000419 // FIXME: How to get the corresponding unsigned
420 // version of size_t?
421 return ArgTypeResult();
422 case AsPtrDiff:
423 // FIXME: How to get the corresponding unsigned
424 // version of ptrdiff_t?
425 return ArgTypeResult();
426 }
Ted Kremenek4e4b30e2010-02-16 01:46:59 +0000427
Ted Kremenekf911eba2010-02-01 23:23:50 +0000428 if (CS.isDoubleArg()) {
429 if (LM == AsLongDouble)
430 return Ctx.LongDoubleTy;
Ted Kremenekc9a89fe2010-01-30 01:02:18 +0000431 return Ctx.DoubleTy;
Ted Kremenekf911eba2010-02-01 23:23:50 +0000432 }
Ted Kremenek87260c72010-02-24 00:05:54 +0000433
434 switch (CS.getKind()) {
435 case ConversionSpecifier::CStrArg:
436 return ArgTypeResult(LM == AsWideChar ? ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy);
437 case ConversionSpecifier::UnicodeStrArg:
438 // FIXME: This appears to be Mac OS X specific.
439 return ArgTypeResult::WCStrTy;
440 case ConversionSpecifier::CArg:
441 return Ctx.WCharTy;
442 default:
443 break;
444 }
445
Ted Kremenek33567d22010-01-29 22:59:32 +0000446 // FIXME: Handle other cases.
Ted Kremenek40888ad2010-01-29 23:00:35 +0000447 return ArgTypeResult();
Ted Kremenek33567d22010-01-29 22:59:32 +0000448}
449