Home | History | Annotate | Download | only in FixIt
      1 // RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -fblocks -Wformat-non-iso -verify %s
      2 // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -fblocks -Wformat-non-iso -verify %s
      3 
      4 // RUN: %clang_cc1 -triple i386-apple-darwin9 -fdiagnostics-parseable-fixits -fblocks -Wformat-non-iso %s 2>&1 | FileCheck -check-prefix=CHECK -check-prefix=CHECK-32 %s
      5 // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fdiagnostics-parseable-fixits -fblocks -Wformat-non-iso %s 2>&1 | FileCheck -check-prefix=CHECK -check-prefix=CHECK-64 %s
      6 
      7 int printf(const char * restrict, ...);
      8 
      9 #if __LP64__
     10 typedef long NSInteger;
     11 typedef unsigned long NSUInteger;
     12 typedef int SInt32;
     13 typedef unsigned int UInt32;
     14 
     15 #else
     16 
     17 typedef int NSInteger;
     18 typedef unsigned int NSUInteger;
     19 typedef long SInt32;
     20 typedef unsigned long UInt32;
     21 #endif
     22 
     23 typedef SInt32 OSStatus;
     24 
     25 typedef enum NSIntegerEnum : NSInteger {
     26   EnumValueA,
     27   EnumValueB
     28 } NSIntegerEnum;
     29 
     30 NSInteger getNSInteger();
     31 NSUInteger getNSUInteger();
     32 SInt32 getSInt32();
     33 UInt32 getUInt32();
     34 NSIntegerEnum getNSIntegerEnum();
     35 
     36 void testCorrectionInAllCases() {
     37   printf("%s", getNSInteger()); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
     38   printf("%s", getNSUInteger()); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
     39   printf("%s", getSInt32()); // expected-warning{{values of type 'SInt32' should not be used as format arguments; add an explicit cast to 'int' instead}}
     40   printf("%s", getUInt32()); // expected-warning{{values of type 'UInt32' should not be used as format arguments; add an explicit cast to 'unsigned int' instead}}
     41 
     42   // CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:11-[[@LINE-5]]:13}:"%ld"
     43   // CHECK: fix-it:"{{.*}}":{[[@LINE-6]]:16-[[@LINE-6]]:16}:"(long)"
     44 
     45   // CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:11-[[@LINE-7]]:13}:"%lu"
     46   // CHECK: fix-it:"{{.*}}":{[[@LINE-8]]:16-[[@LINE-8]]:16}:"(unsigned long)"
     47 
     48   // CHECK: fix-it:"{{.*}}":{[[@LINE-9]]:11-[[@LINE-9]]:13}:"%d"
     49   // CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:16-[[@LINE-10]]:16}:"(int)"
     50 
     51   // CHECK: fix-it:"{{.*}}":{[[@LINE-11]]:11-[[@LINE-11]]:13}:"%u"
     52   // CHECK: fix-it:"{{.*}}":{[[@LINE-12]]:16-[[@LINE-12]]:16}:"(unsigned int)"
     53 
     54   printf("%s", getNSIntegerEnum()); // expected-warning{{enum values with underlying type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
     55 
     56   // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:13}:"%ld"
     57   // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:16-[[@LINE-3]]:16}:"(long)"
     58 }
     59 
     60 @interface Foo {
     61 @public
     62   NSInteger _value;
     63 }
     64 - (NSInteger)getInteger;
     65 
     66 @property NSInteger value;
     67 @end
     68 
     69 struct Bar {
     70   NSInteger value;
     71 };
     72 
     73 
     74 void testParens(Foo *obj, struct Bar *record) {
     75   NSInteger arr[4] = {0};
     76   NSInteger i = 0;
     77 
     78   // These cases match the relevant cases in CheckPrintfHandler::checkFormatExpr.
     79   printf("%s", arr[0]);  // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
     80   printf("%s", getNSInteger());  // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
     81   printf("%s", i);  // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
     82   printf("%s", obj->_value);  // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
     83   printf("%s", [obj getInteger]);  // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
     84   printf("%s", obj.value);  // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
     85   printf("%s", record->value);  // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
     86   printf("%s", (i ? i : i));  // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
     87   printf("%s", *arr);  // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
     88 
     89   // CHECK-NOT: fix-it:{{.*}}:")"
     90 
     91   printf("%s", i ? i : i); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
     92 
     93   // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:13}:"%ld"
     94   // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:16-[[@LINE-3]]:16}:"(long)("
     95   // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:25-[[@LINE-4]]:25}:")"
     96 }
     97 
     98 
     99 #if __LP64__
    100 
    101 void testWarn() {
    102   printf("%d", getNSInteger()); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
    103   printf("%u", getNSUInteger()); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
    104   printf("%ld", getSInt32()); // expected-warning{{values of type 'SInt32' should not be used as format arguments; add an explicit cast to 'int' instead}}
    105   printf("%lu", getUInt32()); // expected-warning{{values of type 'UInt32' should not be used as format arguments; add an explicit cast to 'unsigned int' instead}}
    106 
    107   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-5]]:11-[[@LINE-5]]:13}:"%ld"
    108   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-6]]:16-[[@LINE-6]]:16}:"(long)"
    109 
    110   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-7]]:11-[[@LINE-7]]:13}:"%lu"
    111   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-8]]:16-[[@LINE-8]]:16}:"(unsigned long)"
    112 
    113   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-9]]:11-[[@LINE-9]]:14}:"%d"
    114   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-10]]:17-[[@LINE-10]]:17}:"(int)"
    115 
    116   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-11]]:11-[[@LINE-11]]:14}:"%u"
    117   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-12]]:17-[[@LINE-12]]:17}:"(unsigned int)"
    118 
    119   printf("%d", getNSIntegerEnum()); // expected-warning{{enum values with underlying type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
    120 
    121   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:13}:"%ld"
    122   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-3]]:16-[[@LINE-3]]:16}:"(long)"
    123 }
    124 
    125 void testPreserveHex() {
    126   printf("%x", getNSInteger()); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
    127   printf("%x", getNSUInteger()); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
    128 
    129   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:13}:"%lx"
    130   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-4]]:16-[[@LINE-4]]:16}:"(long)"
    131 
    132   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-5]]:11-[[@LINE-5]]:13}:"%lx"
    133   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-6]]:16-[[@LINE-6]]:16}:"(unsigned long)"
    134 }
    135 
    136 void testSignedness(NSInteger i, NSUInteger u) {
    137   printf("%d", u); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
    138   printf("%i", u); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
    139   printf("%u", i); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
    140 
    141   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:13}:"%lu"
    142   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:13}:"%lu"
    143   // CHECK-64: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:13}:"%ld"
    144 }
    145 
    146 void testNoWarn() {
    147   printf("%ld", getNSInteger()); // no-warning
    148   printf("%lu", getNSUInteger()); // no-warning
    149   printf("%d", getSInt32()); // no-warning
    150   printf("%u", getUInt32()); // no-warning
    151   printf("%ld", getNSIntegerEnum()); // no-warning
    152 }
    153 
    154 #else
    155 
    156 void testWarn() {
    157   printf("%ld", getNSInteger()); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
    158   printf("%lu", getNSUInteger()); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
    159   printf("%d", getSInt32()); // expected-warning{{values of type 'SInt32' should not be used as format arguments; add an explicit cast to 'int' instead}}
    160   printf("%u", getUInt32()); // expected-warning{{values of type 'UInt32' should not be used as format arguments; add an explicit cast to 'unsigned int' instead}}
    161 
    162   // CHECK-32: fix-it:"{{.*}}":{[[@LINE-5]]:17-[[@LINE-5]]:17}:"(long)"
    163   // CHECK-32: fix-it:"{{.*}}":{[[@LINE-5]]:17-[[@LINE-5]]:17}:"(unsigned long)"
    164   // CHECK-32: fix-it:"{{.*}}":{[[@LINE-5]]:16-[[@LINE-5]]:16}:"(int)"
    165   // CHECK-32: fix-it:"{{.*}}":{[[@LINE-5]]:16-[[@LINE-5]]:16}:"(unsigned int)"
    166 
    167   printf("%ld", getNSIntegerEnum()); // expected-warning{{enum values with underlying type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
    168 
    169   // CHECK-32: fix-it:"{{.*}}":{[[@LINE-2]]:17-[[@LINE-2]]:17}:"(long)"
    170 }
    171 
    172 void testPreserveHex() {
    173   printf("%lx", getNSInteger()); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
    174   printf("%lx", getNSUInteger()); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
    175 
    176   // CHECK-32: fix-it:"{{.*}}":{[[@LINE-3]]:17-[[@LINE-3]]:17}:"(long)"
    177   // CHECK-32: fix-it:"{{.*}}":{[[@LINE-3]]:17-[[@LINE-3]]:17}:"(unsigned long)"
    178 }
    179 
    180 void testNoWarn() {
    181   printf("%d", getNSInteger()); // no-warning
    182   printf("%u", getNSUInteger()); // no-warning
    183   printf("%ld", getSInt32()); // no-warning
    184   printf("%lu", getUInt32()); // no-warning
    185   printf("%d", getNSIntegerEnum()); // no-warning
    186 }
    187 
    188 void testSignedness(NSInteger i, NSUInteger u) {
    189   // It is valid to use a specifier with the opposite signedness as long as
    190   // the type is correct.
    191   printf("%d", u); // no-warning
    192   printf("%i", u); // no-warning
    193   printf("%u", i); // no-warning
    194 }
    195 
    196 #endif
    197 
    198 
    199 void testCasts() {
    200   printf("%s", (NSInteger)0); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
    201   printf("%s", (NSUInteger)0); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
    202   printf("%s", (SInt32)0); // expected-warning{{values of type 'SInt32' should not be used as format arguments; add an explicit cast to 'int' instead}}
    203   printf("%s", (UInt32)0); // expected-warning{{values of type 'UInt32' should not be used as format arguments; add an explicit cast to 'unsigned int' instead}}
    204 
    205   // CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:11-[[@LINE-5]]:13}:"%ld"
    206   // CHECK: fix-it:"{{.*}}":{[[@LINE-6]]:16-[[@LINE-6]]:27}:"(long)"
    207 
    208   // CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:11-[[@LINE-7]]:13}:"%lu"
    209   // CHECK: fix-it:"{{.*}}":{[[@LINE-8]]:16-[[@LINE-8]]:28}:"(unsigned long)"
    210 
    211   // CHECK: fix-it:"{{.*}}":{[[@LINE-9]]:11-[[@LINE-9]]:13}:"%d"
    212   // CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:16-[[@LINE-10]]:24}:"(int)"
    213 
    214   // CHECK: fix-it:"{{.*}}":{[[@LINE-11]]:11-[[@LINE-11]]:13}:"%u"
    215   // CHECK: fix-it:"{{.*}}":{[[@LINE-12]]:16-[[@LINE-12]]:24}:"(unsigned int)"
    216 
    217   printf("%s", (NSIntegerEnum)0); // expected-warning{{enum values with underlying type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
    218 
    219   // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:13}:"%ld"
    220   // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:16-[[@LINE-3]]:31}:"(long)"
    221 }
    222 
    223 void testCapitals() {
    224   printf("%D", 1); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}}
    225   printf("%U", 1); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'u'?}}
    226   printf("%O", 1); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'o'?}}
    227   
    228   // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:12-[[@LINE-4]]:13}:"d"
    229   // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:12-[[@LINE-4]]:13}:"u"
    230   // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:12-[[@LINE-4]]:13}:"o"
    231 
    232   
    233   printf("%lD", 1); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}} expected-warning{{format specifies type 'long' but the argument has type 'int'}}
    234 
    235   // FIXME: offering two somewhat-conflicting fixits is less than ideal.
    236   // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:14}:"d"
    237   // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:14}:"%D"
    238 }
    239 
    240 void testLayeredTypedefs(OSStatus i) {
    241   printf("%s", i); // expected-warning {{values of type 'OSStatus' should not be used as format arguments}}
    242   // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%d"
    243 }
    244 
    245