From: Nico Weber Date: Tue, 31 Jan 2012 01:43:25 +0000 (+0000) Subject: Let %S, %ls, %C match 16bit types in NSStrings. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=339b9072e26a2a0fe796dc69c4d28d964d0ec86d;p=clang 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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149325 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h index bf9406695d..f67c04cf42 100644 --- a/include/clang/Analysis/Analyses/FormatString.h +++ b/include/clang/Analysis/Analyses/FormatString.h @@ -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; diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index e5566f1411..6da37fc44a 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -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; diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 7a852aefad..092bf5b597 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -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 diff --git a/test/SemaObjC/format-strings-objc.m b/test/SemaObjC/format-strings-objc.m index 5ab4d8bf3b..24330006df 100644 --- a/test/SemaObjC/format-strings-objc.m +++ b/test/SemaObjC/format-strings-objc.m @@ -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'}} +}