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