]> granicus.if.org Git - clang/commitdiff
Let %S, %ls, %C match 16bit types in NSStrings.
authorNico Weber <nicolasweber@gmx.de>
Tue, 31 Jan 2012 01:43:25 +0000 (01:43 +0000)
committerNico Weber <nicolasweber@gmx.de>
Tue, 31 Jan 2012 01:43:25 +0000 (01:43 +0000)
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

include/clang/Analysis/Analyses/FormatString.h
lib/Analysis/PrintfFormatString.cpp
lib/Sema/SemaChecking.cpp
test/SemaObjC/format-strings-objc.m

index bf9406695d7bb32443335fe8e8db704c39532cdb..f67c04cf4202ffec055b1a0f008a6e17a491ab2e 100644 (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;
index e5566f1411fcbbf72dea13945997e17528c8ea9f..6da37fc44aba27588f98695bfb396610ddfe1be8 100644 (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;
index 7a852aefad1360332ff59aff3f5253dae2dc4fbc..092bf5b5970ae47029ef189ab75b84e47315aac2 100644 (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
index 5ab4d8bf3ba41c193ec726f34eba143173693822..24330006df92051568f341507253575062aa1868 100644 (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'}}
+}