1 | //===- unittest/Format/ObjCPropertyAttributeOrderFixerTest.cpp - unit tests |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "../lib/Format/ObjCPropertyAttributeOrderFixer.h" |
10 | #include "FormatTestBase.h" |
11 | #include "TestLexer.h" |
12 | |
13 | #define DEBUG_TYPE "format-objc-property-attribute-order-fixer-test" |
14 | |
15 | namespace clang { |
16 | namespace format { |
17 | namespace test { |
18 | namespace { |
19 | |
20 | #define CHECK_PARSE(TEXT, FIELD, VALUE) \ |
21 | EXPECT_NE(VALUE, Style.FIELD) << "Initial value already the same!"; \ |
22 | EXPECT_EQ(0, parseConfiguration(TEXT, &Style).value()); \ |
23 | EXPECT_EQ(VALUE, Style.FIELD) << "Unexpected value after parsing!" |
24 | |
25 | #define FAIL_PARSE(TEXT, FIELD, VALUE) \ |
26 | EXPECT_NE(0, parseConfiguration(TEXT, &Style).value()); \ |
27 | EXPECT_EQ(VALUE, Style.FIELD) << "Unexpected value after parsing!" |
28 | |
29 | class ObjCPropertyAttributeOrderFixerTest : public FormatTestBase { |
30 | protected: |
31 | TokenList annotate(llvm::StringRef Code, |
32 | const FormatStyle &Style = getLLVMStyle()) { |
33 | return TestLexer(Allocator, Buffers, Style).annotate(Code); |
34 | } |
35 | |
36 | llvm::SpecificBumpPtrAllocator<FormatToken> Allocator; |
37 | std::vector<std::unique_ptr<llvm::MemoryBuffer>> Buffers; |
38 | }; |
39 | |
40 | TEST_F(ObjCPropertyAttributeOrderFixerTest, ParsesStyleOption) { |
41 | FormatStyle Style = {}; |
42 | Style.Language = FormatStyle::LK_ObjC; |
43 | |
44 | CHECK_PARSE("ObjCPropertyAttributeOrder: [class]" , ObjCPropertyAttributeOrder, |
45 | std::vector<std::string>({"class" })); |
46 | |
47 | CHECK_PARSE("ObjCPropertyAttributeOrder: [" |
48 | "class, direct, atomic, nonatomic, " |
49 | "assign, retain, strong, copy, weak, unsafe_unretained, " |
50 | "readonly, readwrite, getter, setter, " |
51 | "nullable, nonnull, null_resettable, null_unspecified" |
52 | "]" , |
53 | ObjCPropertyAttributeOrder, |
54 | std::vector<std::string>({ |
55 | "class" , |
56 | "direct" , |
57 | "atomic" , |
58 | "nonatomic" , |
59 | "assign" , |
60 | "retain" , |
61 | "strong" , |
62 | "copy" , |
63 | "weak" , |
64 | "unsafe_unretained" , |
65 | "readonly" , |
66 | "readwrite" , |
67 | "getter" , |
68 | "setter" , |
69 | "nullable" , |
70 | "nonnull" , |
71 | "null_resettable" , |
72 | "null_unspecified" , |
73 | })); |
74 | } |
75 | |
76 | TEST_F(ObjCPropertyAttributeOrderFixerTest, SortsSpecifiedAttributes) { |
77 | FormatStyle Style = getLLVMStyle(); |
78 | Style.Language = FormatStyle::LK_ObjC; |
79 | Style.ObjCPropertyAttributeOrder = {"a" , "b" , "c" }; |
80 | |
81 | // Zero: nothing to do, but is legal. |
82 | verifyFormat("@property() int p;" , Style); |
83 | |
84 | // One: shouldn't move. |
85 | verifyFormat("@property(a) int p;" , Style); |
86 | verifyFormat("@property(b) int p;" , Style); |
87 | verifyFormat("@property(c) int p;" , Style); |
88 | |
89 | // Two in correct order already: no change. |
90 | verifyFormat("@property(a, b) int p;" , Style); |
91 | verifyFormat("@property(a, c) int p;" , Style); |
92 | verifyFormat("@property(b, c) int p;" , Style); |
93 | |
94 | // Three in correct order already: no change. |
95 | verifyFormat("@property(a, b, c) int p;" , Style); |
96 | |
97 | // Two wrong order. |
98 | verifyFormat("@property(a, b) int p;" , "@property(b, a) int p;" , Style); |
99 | verifyFormat("@property(a, c) int p;" , "@property(c, a) int p;" , Style); |
100 | verifyFormat("@property(b, c) int p;" , "@property(c, b) int p;" , Style); |
101 | |
102 | // Three wrong order. |
103 | verifyFormat("@property(a, b, c) int p;" , "@property(b, a, c) int p;" , Style); |
104 | verifyFormat("@property(a, b, c) int p;" , "@property(c, b, a) int p;" , Style); |
105 | |
106 | // Check that properties preceded by @optional/@required work. |
107 | verifyFormat("@optional\n" |
108 | "@property(a, b) int p;" , |
109 | "@optional @property(b, a) int p;" , Style); |
110 | verifyFormat("@required\n" |
111 | "@property(a, b) int p;" , |
112 | "@required @property(b, a) int p;" , Style); |
113 | |
114 | // Check two `@property`s on one-line are reflowed (by other passes) |
115 | // and both have their attributes reordered. |
116 | verifyFormat("@property(a, b) int p;\n" |
117 | "@property(a, b) int q;" , |
118 | "@property(b, a) int p; @property(b, a) int q;" , Style); |
119 | } |
120 | |
121 | TEST_F(ObjCPropertyAttributeOrderFixerTest, SortsAttributesWithValues) { |
122 | FormatStyle Style = getLLVMStyle(); |
123 | Style.Language = FormatStyle::LK_ObjC; |
124 | Style.ObjCPropertyAttributeOrder = {"a" , "getter" , "c" }; |
125 | |
126 | // No change |
127 | verifyFormat("@property(getter=G, c) int p;" , Style); |
128 | verifyFormat("@property(a, getter=G) int p;" , Style); |
129 | verifyFormat("@property(a, getter=G, c) int p;" , Style); |
130 | |
131 | // Reorder |
132 | verifyFormat("@property(getter=G, c) int p;" , "@property(c, getter=G) int p;" , |
133 | Style); |
134 | verifyFormat("@property(a, getter=G) int p;" , "@property(getter=G, a) int p;" , |
135 | Style); |
136 | verifyFormat("@property(a, getter=G, c) int p;" , |
137 | "@property(getter=G, c, a) int p;" , Style); |
138 | |
139 | // Multiple set properties, including ones not recognized |
140 | verifyFormat("@property(a=A, c=C, x=X, y=Y) int p;" , |
141 | "@property(c=C, x=X, y=Y, a=A) int p;" , Style); |
142 | } |
143 | |
144 | TEST_F(ObjCPropertyAttributeOrderFixerTest, SortsUnspecifiedAttributesToBack) { |
145 | FormatStyle Style = getLLVMStyle(); |
146 | Style.Language = FormatStyle::LK_ObjC; |
147 | Style.ObjCPropertyAttributeOrder = {"a" , "b" , "c" }; |
148 | |
149 | verifyFormat("@property(x) int p;" , Style); |
150 | |
151 | // No change in order. |
152 | verifyFormat("@property(a, x, y) int p;" , Style); |
153 | verifyFormat("@property(b, x, y) int p;" , Style); |
154 | verifyFormat("@property(a, b, c, x, y) int p;" , Style); |
155 | |
156 | // Reorder one unrecognized one. |
157 | verifyFormat("@property(a, x) int p;" , "@property(x, a) int p;" , Style); |
158 | |
159 | // Prove the unrecognized ones have a stable sort order |
160 | verifyFormat("@property(a, b, x, y) int p;" , "@property(x, b, y, a) int p;" , |
161 | Style); |
162 | verifyFormat("@property(a, b, y, x) int p;" , "@property(y, b, x, a) int p;" , |
163 | Style); |
164 | } |
165 | |
166 | TEST_F(ObjCPropertyAttributeOrderFixerTest, HandlesDuplicatedAttributes) { |
167 | // Duplicated attributes aren't rejected by the compiler even if it's silly |
168 | // to do so. Preserve them and sort them best-effort. |
169 | FormatStyle Style = getLLVMStyle(); |
170 | Style.Language = FormatStyle::LK_ObjC; |
171 | Style.ObjCPropertyAttributeOrder = {"a" , "b" , "c" }; |
172 | |
173 | // Just a dup and nothing else. |
174 | verifyFormat("@property(a) int p;" , "@property(a, a) int p;" , Style); |
175 | |
176 | // A dup and something else. |
177 | verifyFormat("@property(a, b) int p;" , "@property(a, b, a) int p;" , Style); |
178 | |
179 | // Duplicates using `=`. |
180 | verifyFormat("@property(a=A, b=X) int p;" , |
181 | "@property(a=A, b=X, a=A, b=Y) int p;" , Style); |
182 | verifyFormat("@property(a=A, b=Y) int p;" , |
183 | "@property(a=A, b=Y, a=A, b=X) int p;" , Style); |
184 | verifyFormat("@property(a, b=B) int p;" , "@property(a, b=B, a=A, b) int p;" , |
185 | Style); |
186 | } |
187 | |
188 | TEST_F(ObjCPropertyAttributeOrderFixerTest, SortsInPPDirective) { |
189 | FormatStyle Style = getLLVMStyle(); |
190 | Style.Language = FormatStyle::LK_ObjC; |
191 | Style.ObjCPropertyAttributeOrder = {"a" , "b" , "c" }; |
192 | |
193 | // Spot-check a few simple cases that require sorting in a macro definition. |
194 | verifyFormat("#define MACRO @property() int p;" , Style); |
195 | verifyFormat("#define MACRO @property(a) int p;" , Style); |
196 | verifyFormat("#define MACRO @property(a, b) int p;" , |
197 | "#define MACRO @property(b, a) int p;" , Style); |
198 | verifyFormat("#define MACRO @property(a, b, c) int p;" , |
199 | "#define MACRO @property(c, b, a) int p;" , Style); |
200 | } |
201 | |
202 | TEST_F(ObjCPropertyAttributeOrderFixerTest, HandlesAllAttributes) { |
203 | // `class` is the only attribute that is a keyword, so make sure it works too. |
204 | FormatStyle Style = getLLVMStyle(); |
205 | Style.Language = FormatStyle::LK_ObjC; |
206 | Style.ObjCPropertyAttributeOrder = {"FIRST" , |
207 | "class" , |
208 | "direct" , |
209 | "atomic" , |
210 | "nonatomic" , |
211 | "assign" , |
212 | "retain" , |
213 | "strong" , |
214 | "copy" , |
215 | "weak" , |
216 | "unsafe_unretained" , |
217 | "readonly" , |
218 | "readwrite" , |
219 | "getter" , |
220 | "setter" , |
221 | "nullable" , |
222 | "nonnull" , |
223 | "null_resettable" , |
224 | "null_unspecified" , |
225 | "LAST" }; |
226 | |
227 | // No change: specify all attributes in the correct order. |
228 | verifyFormat("@property(class, LAST) int p;" , Style); |
229 | verifyFormat("@property(direct, LAST) int p;" , Style); |
230 | verifyFormat("@property(atomic, LAST) int p;" , Style); |
231 | verifyFormat("@property(nonatomic, LAST) int p;" , Style); |
232 | verifyFormat("@property(assign, LAST) int p;" , Style); |
233 | verifyFormat("@property(retain, LAST) int p;" , Style); |
234 | verifyFormat("@property(strong, LAST) int p;" , Style); |
235 | verifyFormat("@property(copy, LAST) int p;" , Style); |
236 | verifyFormat("@property(weak, LAST) int p;" , Style); |
237 | verifyFormat("@property(unsafe_unretained, LAST) int p;" , Style); |
238 | verifyFormat("@property(readonly, LAST) int p;" , Style); |
239 | verifyFormat("@property(readwrite, LAST) int p;" , Style); |
240 | verifyFormat("@property(getter, LAST) int p;" , Style); |
241 | verifyFormat("@property(setter, LAST) int p;" , Style); |
242 | verifyFormat("@property(nullable, LAST) int p;" , Style); |
243 | verifyFormat("@property(nonnull, LAST) int p;" , Style); |
244 | verifyFormat("@property(null_resettable, LAST) int p;" , Style); |
245 | verifyFormat("@property(null_unspecified, LAST) int p;" , Style); |
246 | |
247 | verifyFormat("@property(FIRST, class) int p;" , Style); |
248 | verifyFormat("@property(FIRST, direct) int p;" , Style); |
249 | verifyFormat("@property(FIRST, atomic) int p;" , Style); |
250 | verifyFormat("@property(FIRST, nonatomic) int p;" , Style); |
251 | verifyFormat("@property(FIRST, assign) int p;" , Style); |
252 | verifyFormat("@property(FIRST, retain) int p;" , Style); |
253 | verifyFormat("@property(FIRST, strong) int p;" , Style); |
254 | verifyFormat("@property(FIRST, copy) int p;" , Style); |
255 | verifyFormat("@property(FIRST, weak) int p;" , Style); |
256 | verifyFormat("@property(FIRST, unsafe_unretained) int p;" , Style); |
257 | verifyFormat("@property(FIRST, readonly) int p;" , Style); |
258 | verifyFormat("@property(FIRST, readwrite) int p;" , Style); |
259 | verifyFormat("@property(FIRST, getter) int p;" , Style); |
260 | verifyFormat("@property(FIRST, setter) int p;" , Style); |
261 | verifyFormat("@property(FIRST, nullable) int p;" , Style); |
262 | verifyFormat("@property(FIRST, nonnull) int p;" , Style); |
263 | verifyFormat("@property(FIRST, null_resettable) int p;" , Style); |
264 | verifyFormat("@property(FIRST, null_unspecified) int p;" , Style); |
265 | |
266 | verifyFormat("@property(FIRST, class, LAST) int p;" , Style); |
267 | verifyFormat("@property(FIRST, direct, LAST) int p;" , Style); |
268 | verifyFormat("@property(FIRST, atomic, LAST) int p;" , Style); |
269 | verifyFormat("@property(FIRST, nonatomic, LAST) int p;" , Style); |
270 | verifyFormat("@property(FIRST, assign, LAST) int p;" , Style); |
271 | verifyFormat("@property(FIRST, retain, LAST) int p;" , Style); |
272 | verifyFormat("@property(FIRST, strong, LAST) int p;" , Style); |
273 | verifyFormat("@property(FIRST, copy, LAST) int p;" , Style); |
274 | verifyFormat("@property(FIRST, weak, LAST) int p;" , Style); |
275 | verifyFormat("@property(FIRST, unsafe_unretained, LAST) int p;" , Style); |
276 | verifyFormat("@property(FIRST, readonly, LAST) int p;" , Style); |
277 | verifyFormat("@property(FIRST, readwrite, LAST) int p;" , Style); |
278 | verifyFormat("@property(FIRST, getter, LAST) int p;" , Style); |
279 | verifyFormat("@property(FIRST, setter, LAST) int p;" , Style); |
280 | verifyFormat("@property(FIRST, nullable, LAST) int p;" , Style); |
281 | verifyFormat("@property(FIRST, nonnull, LAST) int p;" , Style); |
282 | verifyFormat("@property(FIRST, null_resettable, LAST) int p;" , Style); |
283 | verifyFormat("@property(FIRST, null_unspecified, LAST) int p;" , Style); |
284 | |
285 | // Reorder: put `FIRST` and/or `LAST` in the wrong spot. |
286 | verifyFormat("@property(class, LAST) int p;" , "@property(LAST, class) int p;" , |
287 | Style); |
288 | verifyFormat("@property(direct, LAST) int p;" , |
289 | "@property(LAST, direct) int p;" , Style); |
290 | verifyFormat("@property(atomic, LAST) int p;" , |
291 | "@property(LAST, atomic) int p;" , Style); |
292 | verifyFormat("@property(nonatomic, LAST) int p;" , |
293 | "@property(LAST, nonatomic) int p;" , Style); |
294 | verifyFormat("@property(assign, LAST) int p;" , |
295 | "@property(LAST, assign) int p;" , Style); |
296 | verifyFormat("@property(retain, LAST) int p;" , |
297 | "@property(LAST, retain) int p;" , Style); |
298 | verifyFormat("@property(strong, LAST) int p;" , |
299 | "@property(LAST, strong) int p;" , Style); |
300 | verifyFormat("@property(copy, LAST) int p;" , "@property(LAST, copy) int p;" , |
301 | Style); |
302 | verifyFormat("@property(weak, LAST) int p;" , "@property(LAST, weak) int p;" , |
303 | Style); |
304 | verifyFormat("@property(unsafe_unretained, LAST) int p;" , |
305 | "@property(LAST, unsafe_unretained) int p;" , Style); |
306 | verifyFormat("@property(readonly, LAST) int p;" , |
307 | "@property(LAST, readonly) int p;" , Style); |
308 | verifyFormat("@property(readwrite, LAST) int p;" , |
309 | "@property(LAST, readwrite) int p;" , Style); |
310 | verifyFormat("@property(getter, LAST) int p;" , |
311 | "@property(LAST, getter) int p;" , Style); |
312 | verifyFormat("@property(setter, LAST) int p;" , |
313 | "@property(LAST, setter) int p;" , Style); |
314 | verifyFormat("@property(nullable, LAST) int p;" , |
315 | "@property(LAST, nullable) int p;" , Style); |
316 | verifyFormat("@property(nonnull, LAST) int p;" , |
317 | "@property(LAST, nonnull) int p;" , Style); |
318 | verifyFormat("@property(null_resettable, LAST) int p;" , |
319 | "@property(LAST, null_resettable) int p;" , Style); |
320 | verifyFormat("@property(null_unspecified, LAST) int p;" , |
321 | "@property(LAST, null_unspecified) int p;" , Style); |
322 | |
323 | verifyFormat("@property(FIRST, class) int p;" , |
324 | "@property(class, FIRST) int p;" , Style); |
325 | verifyFormat("@property(FIRST, direct) int p;" , |
326 | "@property(direct, FIRST) int p;" , Style); |
327 | verifyFormat("@property(FIRST, atomic) int p;" , |
328 | "@property(atomic, FIRST) int p;" , Style); |
329 | verifyFormat("@property(FIRST, nonatomic) int p;" , |
330 | "@property(nonatomic, FIRST) int p;" , Style); |
331 | verifyFormat("@property(FIRST, assign) int p;" , |
332 | "@property(assign, FIRST) int p;" , Style); |
333 | verifyFormat("@property(FIRST, retain) int p;" , |
334 | "@property(retain, FIRST) int p;" , Style); |
335 | verifyFormat("@property(FIRST, strong) int p;" , |
336 | "@property(strong, FIRST) int p;" , Style); |
337 | verifyFormat("@property(FIRST, copy) int p;" , "@property(copy, FIRST) int p;" , |
338 | Style); |
339 | verifyFormat("@property(FIRST, weak) int p;" , "@property(weak, FIRST) int p;" , |
340 | Style); |
341 | verifyFormat("@property(FIRST, unsafe_unretained) int p;" , |
342 | "@property(unsafe_unretained, FIRST) int p;" , Style); |
343 | verifyFormat("@property(FIRST, readonly) int p;" , |
344 | "@property(readonly, FIRST) int p;" , Style); |
345 | verifyFormat("@property(FIRST, readwrite) int p;" , |
346 | "@property(readwrite, FIRST) int p;" , Style); |
347 | verifyFormat("@property(FIRST, getter) int p;" , |
348 | "@property(getter, FIRST) int p;" , Style); |
349 | verifyFormat("@property(FIRST, setter) int p;" , |
350 | "@property(setter, FIRST) int p;" , Style); |
351 | verifyFormat("@property(FIRST, nullable) int p;" , |
352 | "@property(nullable, FIRST) int p;" , Style); |
353 | verifyFormat("@property(FIRST, nonnull) int p;" , |
354 | "@property(nonnull, FIRST) int p;" , Style); |
355 | verifyFormat("@property(FIRST, null_resettable) int p;" , |
356 | "@property(null_resettable, FIRST) int p;" , Style); |
357 | verifyFormat("@property(FIRST, null_unspecified) int p;" , |
358 | "@property(null_unspecified, FIRST) int p;" , Style); |
359 | |
360 | verifyFormat("@property(FIRST, class, LAST) int p;" , |
361 | "@property(LAST, class, FIRST) int p;" , Style); |
362 | verifyFormat("@property(FIRST, direct, LAST) int p;" , |
363 | "@property(LAST, direct, FIRST) int p;" , Style); |
364 | verifyFormat("@property(FIRST, atomic, LAST) int p;" , |
365 | "@property(LAST, atomic, FIRST) int p;" , Style); |
366 | verifyFormat("@property(FIRST, nonatomic, LAST) int p;" , |
367 | "@property(LAST, nonatomic, FIRST) int p;" , Style); |
368 | verifyFormat("@property(FIRST, assign, LAST) int p;" , |
369 | "@property(LAST, assign, FIRST) int p;" , Style); |
370 | verifyFormat("@property(FIRST, retain, LAST) int p;" , |
371 | "@property(LAST, retain, FIRST) int p;" , Style); |
372 | verifyFormat("@property(FIRST, strong, LAST) int p;" , |
373 | "@property(LAST, strong, FIRST) int p;" , Style); |
374 | verifyFormat("@property(FIRST, copy, LAST) int p;" , |
375 | "@property(LAST, copy, FIRST) int p;" , Style); |
376 | verifyFormat("@property(FIRST, weak, LAST) int p;" , |
377 | "@property(LAST, weak, FIRST) int p;" , Style); |
378 | verifyFormat("@property(FIRST, unsafe_unretained, LAST) int p;" , |
379 | "@property(LAST, unsafe_unretained, FIRST) int p;" , Style); |
380 | verifyFormat("@property(FIRST, readonly, LAST) int p;" , |
381 | "@property(LAST, readonly, FIRST) int p;" , Style); |
382 | verifyFormat("@property(FIRST, readwrite, LAST) int p;" , |
383 | "@property(LAST, readwrite, FIRST) int p;" , Style); |
384 | verifyFormat("@property(FIRST, getter, LAST) int p;" , |
385 | "@property(LAST, getter, FIRST) int p;" , Style); |
386 | verifyFormat("@property(FIRST, setter, LAST) int p;" , |
387 | "@property(LAST, setter, FIRST) int p;" , Style); |
388 | verifyFormat("@property(FIRST, nullable, LAST) int p;" , |
389 | "@property(LAST, nullable, FIRST) int p;" , Style); |
390 | verifyFormat("@property(FIRST, nonnull, LAST) int p;" , |
391 | "@property(LAST, nonnull, FIRST) int p;" , Style); |
392 | verifyFormat("@property(FIRST, null_resettable, LAST) int p;" , |
393 | "@property(LAST, null_resettable, FIRST) int p;" , Style); |
394 | verifyFormat("@property(FIRST, null_unspecified, LAST) int p;" , |
395 | "@property(LAST, null_unspecified, FIRST) int p;" , Style); |
396 | } |
397 | |
398 | TEST_F(ObjCPropertyAttributeOrderFixerTest, HandlesCommentsAroundAttributes) { |
399 | FormatStyle Style = getLLVMStyle(); |
400 | Style.Language = FormatStyle::LK_ObjC; |
401 | Style.ObjCPropertyAttributeOrder = {"a" , "b" }; |
402 | |
403 | // Zero attributes but comments. |
404 | verifyFormat("@property(/* 1 */) int p;" , Style); |
405 | verifyFormat("@property(/* 1 */ /* 2 */) int p;" , Style); |
406 | |
407 | // One attribute with comments before or after. |
408 | verifyFormat("@property(/* 1 */ a) int p;" , Style); |
409 | verifyFormat("@property(a /* 2 */) int p;" , Style); |
410 | verifyFormat("@property(/* 1 */ a /* 2 */) int p;" , Style); |
411 | |
412 | // No reordering if comments are encountered anywhere. |
413 | // (Each case represents a reordering that would have happened |
414 | // without the comment.) |
415 | verifyFormat("@property(/* before */ b, a) int p;" , Style); |
416 | verifyFormat("@property(b, /* between */ a) int p;" , Style); |
417 | verifyFormat("@property(b, a /* after */) int p;" , Style); |
418 | } |
419 | |
420 | } // namespace |
421 | } // namespace test |
422 | } // namespace format |
423 | } // namespace clang |
424 | |