xref: /llvm-project/clang/unittests/Format/ObjCPropertyAttributeOrderFixerTest.cpp (revision 1c58208d899285318c89e069268145c85ec33368)
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:
annotate(StringRef Code,const FormatStyle & Style=getLLVMStyle ())31   TokenList annotate(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 
TEST_F(ObjCPropertyAttributeOrderFixerTest,ParsesStyleOption)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 
TEST_F(ObjCPropertyAttributeOrderFixerTest,SortsSpecifiedAttributes)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 
TEST_F(ObjCPropertyAttributeOrderFixerTest,SortsAttributesWithValues)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 
TEST_F(ObjCPropertyAttributeOrderFixerTest,SortsUnspecifiedAttributesToBack)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 
TEST_F(ObjCPropertyAttributeOrderFixerTest,HandlesDuplicatedAttributes)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 
TEST_F(ObjCPropertyAttributeOrderFixerTest,SortsInPPDirective)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 
TEST_F(ObjCPropertyAttributeOrderFixerTest,HandlesAllAttributes)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 
TEST_F(ObjCPropertyAttributeOrderFixerTest,HandlesCommentsAroundAttributes)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