/// will return null if the format specifier does not have
/// a matching data argument or the matching argument matches
/// more than one type.
- ArgTypeResult getArgType(ASTContext &Ctx) const;
+ ArgTypeResult getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
const OptionalFlag &hasThousandsGrouping() const {
return HasThousandsGrouping;
// Methods on PrintfSpecifier.
//===----------------------------------------------------------------------===//
-ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
+ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx,
+ bool IsObjCLiteral) const {
const PrintfConversionSpecifier &CS = getConversionSpecifier();
if (!CS.consumesDataArgument())
switch (CS.getKind()) {
case ConversionSpecifier::sArg:
- if (LM.getKind() == LengthModifier::AsWideChar)
+ if (LM.getKind() == LengthModifier::AsWideChar) {
+ if (IsObjCLiteral)
+ return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst());
return ArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t *");
+ }
return ArgTypeResult::CStrTy;
case ConversionSpecifier::SArg:
- // FIXME: This appears to be Mac OS X specific.
+ if (IsObjCLiteral)
+ return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst());
return ArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t *");
case ConversionSpecifier::CArg:
+ if (IsObjCLiteral)
+ return Ctx.UnsignedShortTy;
return ArgTypeResult(Ctx.WCharTy, "wchar_t");
case ConversionSpecifier::pArg:
return ArgTypeResult::CPointerTy;
// Now type check the data expression that matches the
// format specifier.
const Expr *Ex = getDataArg(argIndex);
- const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context);
+ const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context,
+ IsObjCLiteral);
if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) {
// Check if we didn't match because of an implicit cast from a 'char'
// or 'short' to an 'int'. This is done because printf is a varargs
void check_NSLocalizedString() {
[Foo fooWithFormat:NSLocalizedString(@"format"), @"arg"]; // no-warning
}
+
+typedef __WCHAR_TYPE__ wchar_t;
+
+
+// Test that %S, %C, %ls check for 16 bit types in ObjC strings, as described at
+// http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html#//apple_ref/doc/uid/TP40004265
+
+void test_percent_S() {
+ const unsigned short data[] = { 'a', 'b', 0 };
+ const unsigned short* ptr = data;
+ NSLog(@"%S", ptr); // no-warning
+
+ const wchar_t* wchar_ptr = L"ab";
+ NSLog(@"%S", wchar_ptr); // expected-warning{{format specifies type 'const unsigned short *' but the argument has type 'const wchar_t *'}}
+}
+
+void test_percent_ls() {
+ const unsigned short data[] = { 'a', 'b', 0 };
+ const unsigned short* ptr = data;
+ NSLog(@"%ls", ptr); // no-warning
+
+ const wchar_t* wchar_ptr = L"ab";
+ NSLog(@"%ls", wchar_ptr); // expected-warning{{format specifies type 'const unsigned short *' but the argument has type 'const wchar_t *'}}
+}
+
+void test_percent_C() {
+ const unsigned short data = 'a';
+ NSLog(@"%C", data); // no-warning
+
+ const wchar_t wchar_data = L'a';
+ NSLog(@"%C", wchar_data); // expected-warning{{format specifies type 'unsigned short' but the argument has type 'wchar_t'}}
+}