Let %S, %ls, %C match 16bit types in NSStrings.

As discussed at http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20120130/052200.html

llvm-svn: 149325
This commit is contained in:
Nico Weber 2012-01-31 01:43:25 +00:00
parent 6b68c98f7d
commit 496cdc2cb7
4 changed files with 45 additions and 5 deletions

View File

@ -455,7 +455,7 @@ public:
/// 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;

View File

@ -241,7 +241,8 @@ bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
// Methods on PrintfSpecifier.
//===----------------------------------------------------------------------===//
ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx,
bool IsObjCLiteral) const {
const PrintfConversionSpecifier &CS = getConversionSpecifier();
if (!CS.consumesDataArgument())
@ -309,13 +310,19 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
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;

View File

@ -2162,7 +2162,8 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
// 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

View File

@ -115,3 +115,35 @@ extern NSString *GetLocalizedString(NSString *str);
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'}}
}