Home | History | Annotate | Download | only in SemaObjC
      1 // RUN: %clang_cc1 -triple x86_64-apple-darwin -Wformat-nonliteral -fsyntax-only -fblocks -verify -Wno-objc-root-class %s
      2 
      3 //===----------------------------------------------------------------------===//
      4 // The following code is reduced using delta-debugging from
      5 // Foundation.h (Mac OS X).
      6 //
      7 // It includes the basic definitions for the test cases below.
      8 // Not including Foundation.h directly makes this test case both svelt and
      9 // portable to non-Mac platforms.
     10 //===----------------------------------------------------------------------===//
     11 
     12 #include <stdarg.h>
     13 
     14 typedef signed char BOOL;
     15 typedef unsigned int NSUInteger;
     16 @class NSString, Protocol;
     17 extern void NSLog(NSString *format, ...);
     18 extern void NSLogv(NSString *format, va_list args);
     19 typedef struct _NSZone NSZone;
     20 @class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
     21 @protocol NSObject  - (BOOL)isEqual:(id)object; @end
     22 @protocol NSCopying  - (id)copyWithZone:(NSZone *)zone; @end
     23 @protocol NSMutableCopying  - (id)mutableCopyWithZone:(NSZone *)zone; @end
     24 @protocol NSCoding  - (void)encodeWithCoder:(NSCoder *)aCoder; @end
     25 @interface NSObject <NSObject> {} @end
     26 typedef float CGFloat;
     27 @interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>    - (NSUInteger)length; @end
     28 @interface NSSimpleCString : NSString {} @end
     29 @interface NSConstantString : NSSimpleCString @end
     30 extern void *_NSConstantStringClassReference;
     31 
     32 typedef const struct __CFString * CFStringRef;
     33 extern void CFStringCreateWithFormat(CFStringRef format, ...) __attribute__((format(CFString, 1, 2)));
     34 
     35 int printf(const char * restrict, ...) ;
     36 
     37 //===----------------------------------------------------------------------===//
     38 // Test cases.
     39 //===----------------------------------------------------------------------===//
     40 
     41 void check_nslog(unsigned k) {
     42   NSLog(@"%d%%", k); // no-warning
     43   NSLog(@"%s%lb%d", "unix", 10,20); // expected-warning {{invalid conversion specifier 'b'}}
     44 }
     45 
     46 // Check type validation
     47 extern void NSLog2(int format, ...) __attribute__((format(__NSString__, 1, 2))); // expected-error {{format argument not an NSString}}
     48 extern void CFStringCreateWithFormat2(int *format, ...) __attribute__((format(CFString, 1, 2))); // expected-error {{format argument not a CFString}}
     49 
     50 // <rdar://problem/7068334> - Catch use of long long with int arguments.
     51 void rdar_7068334() {
     52   long long test = 500;  
     53   printf("%i ",test); // expected-warning{{format specifies type 'int' but the argument has type 'long long'}}
     54   NSLog(@"%i ",test); // expected-warning{{format specifies type 'int' but the argument has type 'long long'}}
     55 }
     56 
     57 // <rdar://problem/7697748>
     58 void rdar_7697748() {
     59   NSLog(@"%@!"); // expected-warning{{more '%' conversions than data arguments}}
     60 }
     61 
     62 @protocol Foo;
     63 
     64 void test_p_conversion_with_objc_pointer(id x, id<Foo> y) {
     65   printf("%p", x); // no-warning
     66   printf("%p", y); // no-warning
     67 }
     68 
     69 // <rdar://problem/10696348>, PR 10274 - CFString and NSString formats are ignored
     70 extern void MyNSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
     71 extern void MyCFStringCreateWithFormat(CFStringRef format, ...) __attribute__((format(__CFString__, 1, 2)));
     72 
     73 void check_mylog() {
     74   MyNSLog(@"%@"); // expected-warning {{more '%' conversions than data arguments}}
     75   // FIXME: find a way to test CFString too, but I don't know how to create constant CFString.
     76 }
     77 
     78 // PR 10275 - format function attribute isn't checked in Objective-C methods
     79 @interface Foo
     80 + (id)fooWithFormat:(NSString *)fmt, ... __attribute__((format(__NSString__, 1, 2)));
     81 + (id)fooWithCStringFormat:(const char *)format, ... __attribute__((format(__printf__, 1, 2)));
     82 @end
     83 
     84 void check_method() {
     85   [Foo fooWithFormat:@"%@"]; // expected-warning {{more '%' conversions than data arguments}}
     86   [Foo fooWithCStringFormat:"%@"]; // expected-warning {{invalid conversion specifier '@'}}
     87 }
     88 
     89 // Warn about using BOOL with %@
     90 void rdar10743758(id x) {
     91   NSLog(@"%@ %@", x, (BOOL) 1); // expected-warning {{format specifies type 'id' but the argument has type 'BOOL' (aka 'signed char')}}
     92 }
     93 
     94 NSString *test_literal_propagation(void) {
     95   const char * const s1 = "constant string %s"; // expected-note {{format string is defined here}}
     96   printf(s1); // expected-warning {{more '%' conversions than data arguments}}
     97   const char * const s5 = "constant string %s"; // expected-note {{format string is defined here}}
     98   const char * const s2 = s5;
     99   printf(s2); // expected-warning {{more '%' conversions than data arguments}}
    100 
    101   const char * const s3 = (const char *)0;
    102   printf(s3); // no-warning (NULL is a valid format string)
    103 
    104   NSString * const ns1 = @"constant string %s"; // expected-note {{format string is defined here}}
    105   NSLog(ns1); // expected-warning {{more '%' conversions than data arguments}}
    106   NSString * const ns5 = @"constant string %s"; // expected-note {{format string is defined here}}
    107   NSString * const ns2 = ns5;
    108   NSLog(ns2); // expected-warning {{more '%' conversions than data arguments}}
    109   NSString * ns3 = ns1;
    110   NSLog(ns3); // expected-warning {{format string is not a string literal}}}
    111 }
    112 
    113 // Do not emit warnings when using NSLocalizedString
    114 extern NSString *GetLocalizedString(NSString *str);
    115 #define NSLocalizedString(key) GetLocalizedString(key)
    116 
    117 void check_NSLocalizedString() {
    118   [Foo fooWithFormat:NSLocalizedString(@"format"), @"arg"]; // no-warning
    119 }
    120 
    121 typedef __WCHAR_TYPE__ wchar_t;
    122 
    123 // Test that %S, %C, %ls check for 16 bit types in ObjC strings, as described at
    124 // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html#//apple_ref/doc/uid/TP40004265
    125 
    126 void test_percent_S() {
    127   const unsigned short data[] = { 'a', 'b', 0 };
    128   const unsigned short* ptr = data;
    129   NSLog(@"%S", ptr);  // no-warning
    130 
    131   const wchar_t* wchar_ptr = L"ab";
    132   NSLog(@"%S", wchar_ptr);  // expected-warning{{format specifies type 'const unsigned short *' but the argument has type 'const wchar_t *'}}
    133 }
    134 
    135 void test_percent_ls() {
    136   const unsigned short data[] = { 'a', 'b', 0 };
    137   const unsigned short* ptr = data;
    138   NSLog(@"%ls", ptr);  // no-warning
    139 
    140   const wchar_t* wchar_ptr = L"ab";
    141   NSLog(@"%ls", wchar_ptr);  // expected-warning{{format specifies type 'const unsigned short *' but the argument has type 'const wchar_t *'}}
    142 }
    143 
    144 void test_percent_C() {
    145   const unsigned short data = 'a';
    146   NSLog(@"%C", data);  // no-warning
    147 
    148   const wchar_t wchar_data = L'a';
    149   NSLog(@"%C", wchar_data);  // expected-warning{{format specifies type 'unsigned short' but the argument has type 'wchar_t'}}
    150 }
    151 
    152 // Test that %@ works with toll-free bridging (<rdar://problem/10814120>).
    153 void test_toll_free_bridging(CFStringRef x) {
    154   NSLog(@"%@", x); // no-warning
    155 }
    156 
    157 @interface Bar
    158 + (void)log:(NSString *)fmt, ...;
    159 + (void)log2:(NSString *)fmt, ... __attribute__((format(NSString, 1, 2)));
    160 @end
    161 
    162 @implementation Bar
    163 
    164 + (void)log:(NSString *)fmt, ... {
    165   va_list ap;
    166   va_start(ap,fmt);
    167   NSLogv(fmt, ap); // expected-warning{{format string is not a string literal}}
    168   va_end(ap);
    169 }
    170 
    171 + (void)log2:(NSString *)fmt, ... {
    172   va_list ap;
    173   va_start(ap,fmt);
    174   NSLogv(fmt, ap); // no-warning
    175   va_end(ap);
    176 }
    177 
    178 @end
    179 
    180 
    181 // Test that it is okay to use %p with the address of a block.
    182 void rdar11049844_aux();
    183 int rdar11049844() {
    184   typedef void (^MyBlock)(void);
    185   MyBlock x = ^void() { rdar11049844_aux(); };
    186   printf("%p", x);  // no-warning
    187 }
    188 
    189