[cfe-commits] r157716 - in /cfe/trunk: lib/Analysis/PrintfFormatString.cpp test/FixIt/format-no-fixit.m test/FixIt/format.m

Jordan Rose jordan_rose at apple.com
Wed May 30 14:53:13 PDT 2012


Author: jrose
Date: Wed May 30 16:53:13 2012
New Revision: 157716

URL: http://llvm.org/viewvc/llvm-project?rev=157716&view=rev
Log:
Suggest '%@' for Objective-C objects in ObjC format strings.

Added:
    cfe/trunk/test/FixIt/format-no-fixit.m
    cfe/trunk/test/FixIt/format.m
Modified:
    cfe/trunk/lib/Analysis/PrintfFormatString.cpp

Modified: cfe/trunk/lib/Analysis/PrintfFormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PrintfFormatString.cpp?rev=157716&r1=157715&r2=157716&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/PrintfFormatString.cpp (original)
+++ cfe/trunk/lib/Analysis/PrintfFormatString.cpp Wed May 30 16:53:13 2012
@@ -342,7 +342,29 @@
 
 bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
                               ASTContext &Ctx, bool IsObjCLiteral) {
-  // Handle strings first (char *, wchar_t *)
+  // Handle Objective-C objects first. Note that while the '%@' specifier will
+  // not warn for structure pointer or void pointer arguments (because that's
+  // how CoreFoundation objects are implemented), we only show a fixit for '%@'
+  // if we know it's an object (block, id, class, or __attribute__((NSObject))).
+  if (QT->isObjCRetainableType()) {
+    if (!IsObjCLiteral)
+      return false;
+
+    CS.setKind(ConversionSpecifier::ObjCObjArg);
+
+    // Disable irrelevant flags
+    HasThousandsGrouping = false;
+    HasPlusPrefix = false;
+    HasSpacePrefix = false;
+    HasAlternativeForm = false;
+    HasLeadingZeroes = false;
+    Precision.setHowSpecified(OptionalAmount::NotSpecified);
+    LM.setKind(LengthModifier::None);
+
+    return true;
+  }
+
+  // Handle strings next (char *, wchar_t *)
   if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
     CS.setKind(ConversionSpecifier::sArg);
 

Added: cfe/trunk/test/FixIt/format-no-fixit.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/format-no-fixit.m?rev=157716&view=auto
==============================================================================
--- cfe/trunk/test/FixIt/format-no-fixit.m (added)
+++ cfe/trunk/test/FixIt/format-no-fixit.m Wed May 30 16:53:13 2012
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fdiagnostics-parseable-fixits -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK-NOT: fix-it:
+
+ at class NSString;
+extern void NSLog(NSString *format, ...);
+int printf(const char * restrict, ...) ;
+
+
+void test_object_correction (id x) {  
+  printf("%d", x); // expected-warning{{format specifies type 'int' but the argument has type 'id'}}
+  printf("%s", x); // expected-warning{{format specifies type 'char *' but the argument has type 'id'}}
+  printf("%lf", x); // expected-warning{{format specifies type 'double' but the argument has type 'id'}}
+}
+
+
+// Old-style Core Foundation types do not have __attribute__((NSObject)).
+// This is okay, but we won't suggest a fixit; arbitrary structure pointers may
+// not be objects.
+typedef const struct __CFString * CFStringRef;
+
+void test_cf_object_correction (CFStringRef x) {
+  NSLog(@"%@", x); // no-warning
+
+  NSLog(@"%d", x); // expected-warning{{format specifies type 'int' but the argument has type 'CFStringRef'}}
+  NSLog(@"%s", x); // expected-warning{{format specifies type 'char *' but the argument has type 'CFStringRef'}}
+  NSLog(@"%lf", x); // expected-warning{{format specifies type 'double' but the argument has type 'CFStringRef'}}
+}
+

Added: cfe/trunk/test/FixIt/format.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/format.m?rev=157716&view=auto
==============================================================================
--- cfe/trunk/test/FixIt/format.m (added)
+++ cfe/trunk/test/FixIt/format.m Wed May 30 16:53:13 2012
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s
+// RUN: %clang_cc1 -fdiagnostics-parseable-fixits -fblocks %s 2>&1 | FileCheck %s
+
+ at class NSString;
+extern void NSLog(NSString *, ...);
+int printf(const char * restrict, ...) ;
+
+void test_integer_correction (int x) {
+  printf("%d", x); // no-warning
+  printf("%s", x); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
+  printf("%lf", x); // expected-warning{{format specifies type 'double' but the argument has type 'int'}}
+  // CHECK: fix-it:"{{.*}}":{10:11-10:13}:"%d"
+  // CHECK: fix-it:"{{.*}}":{11:11-11:14}:"%d"
+
+  NSLog(@"%d", x); // no-warning
+  NSLog(@"%s", x); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
+  NSLog(@"%lf", x); // expected-warning{{format specifies type 'double' but the argument has type 'int'}}
+  NSLog(@"%@", x); // expected-warning{{format specifies type 'id' but the argument has type 'int'}}
+  // CHECK: fix-it:"{{.*}}":{16:11-16:13}:"%d"
+  // CHECK: fix-it:"{{.*}}":{17:11-17:14}:"%d"
+  // CHECK: fix-it:"{{.*}}":{18:11-18:13}:"%d"
+}
+
+void test_string_correction (char *x) {
+  printf("%d", x); // expected-warning{{format specifies type 'int' but the argument has type 'char *'}}
+  printf("%s", x); // no-warning
+  printf("%lf", x); // expected-warning{{format specifies type 'double' but the argument has type 'char *'}}
+  // CHECK: fix-it:"{{.*}}":{25:11-25:13}:"%s"
+  // CHECK: fix-it:"{{.*}}":{27:11-27:14}:"%s"
+
+  NSLog(@"%d", x); // expected-warning{{format specifies type 'int' but the argument has type 'char *'}}
+  NSLog(@"%s", x); // no-warning
+  NSLog(@"%lf", x); // expected-warning{{format specifies type 'double' but the argument has type 'char *'}}
+  NSLog(@"%@", x); // expected-warning{{format specifies type 'id' but the argument has type 'char *'}}
+  // CHECK: fix-it:"{{.*}}":{31:11-31:13}:"%s"
+  // CHECK: fix-it:"{{.*}}":{33:11-33:14}:"%s"
+  // CHECK: fix-it:"{{.*}}":{34:11-34:13}:"%s"
+}
+
+void test_object_correction (id x) {  
+  NSLog(@"%d", x); // expected-warning{{format specifies type 'int' but the argument has type 'id'}}
+  NSLog(@"%s", x); // expected-warning{{format specifies type 'char *' but the argument has type 'id'}}
+  NSLog(@"%lf", x); // expected-warning{{format specifies type 'double' but the argument has type 'id'}}
+  NSLog(@"%@", x); // no-warning
+  // CHECK: fix-it:"{{.*}}":{41:11-41:13}:"%@"
+  // CHECK: fix-it:"{{.*}}":{42:11-42:13}:"%@"
+  // CHECK: fix-it:"{{.*}}":{43:11-43:14}:"%@"
+}
+
+typedef const struct __CFString * __attribute__((NSObject)) CFStringRef;
+void test_cf_object_correction (CFStringRef x) {
+  NSLog(@"%d", x); // expected-warning{{format specifies type 'int' but the argument has type 'CFStringRef'}}
+  NSLog(@"%s", x); // expected-warning{{format specifies type 'char *' but the argument has type 'CFStringRef'}}
+  NSLog(@"%lf", x); // expected-warning{{format specifies type 'double' but the argument has type 'CFStringRef'}}
+  NSLog(@"%@", x); // no-warning
+  // CHECK: fix-it:"{{.*}}":{52:11-52:13}:"%@"
+  // CHECK: fix-it:"{{.*}}":{53:11-53:13}:"%@"
+  // CHECK: fix-it:"{{.*}}":{54:11-54:14}:"%@"
+}
+
+typedef void (^block_t)(void);
+void test_block_correction (block_t x) {
+  NSLog(@"%d", x); // expected-warning{{format specifies type 'int' but the argument has type 'block_t'}}
+  NSLog(@"%s", x); // expected-warning{{format specifies type 'char *' but the argument has type 'block_t'}}
+  NSLog(@"%lf", x); // expected-warning{{format specifies type 'double' but the argument has type 'block_t'}}
+  NSLog(@"%@", x); // no-warning
+  // CHECK: fix-it:"{{.*}}":{63:11-63:13}:"%@"
+  // CHECK: fix-it:"{{.*}}":{64:11-64:13}:"%@"
+  // CHECK: fix-it:"{{.*}}":{65:11-65:14}:"%@"
+}





More information about the cfe-commits mailing list