1 | //===- unittest/Format/FormatTestObjC.cpp - Formatting 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 "FormatTestBase.h" |
10 | |
11 | #define DEBUG_TYPE "format-test-objc" |
12 | |
13 | namespace clang { |
14 | namespace format { |
15 | namespace test { |
16 | namespace { |
17 | |
18 | class FormatTestObjC : public FormatTestBase { |
19 | protected: |
20 | FormatTestObjC() { |
21 | Style = getLLVMStyle(); |
22 | Style.Language = FormatStyle::LK_ObjC; |
23 | } |
24 | |
25 | FormatStyle getDefaultStyle() const override { return Style; } |
26 | |
27 | FormatStyle Style; |
28 | }; |
29 | |
30 | #define verifyIncompleteFormat(...) \ |
31 | _verifyIncompleteFormat(__FILE__, __LINE__, __VA_ARGS__) |
32 | #define verifyFormat(...) _verifyFormat(__FILE__, __LINE__, __VA_ARGS__) |
33 | |
34 | TEST(FormatTestObjCStyle, DetectsObjCInStdin) { |
35 | auto Style = getStyle(StyleName: "LLVM" , FileName: "<stdin>" , FallbackStyle: "none" , |
36 | Code: "@interface\n" |
37 | "- (id)init;" ); |
38 | ASSERT_TRUE((bool)Style); |
39 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
40 | } |
41 | |
42 | TEST(FormatTestObjCStyle, DetectsObjCInHeaders) { |
43 | auto Style = getStyle(StyleName: "LLVM" , FileName: "a.h" , FallbackStyle: "none" , |
44 | Code: "@interface\n" |
45 | "- (id)init;" ); |
46 | ASSERT_TRUE((bool)Style); |
47 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
48 | |
49 | Style = getStyle(StyleName: "LLVM" , FileName: "a.h" , FallbackStyle: "none" , |
50 | Code: "@interface\n" |
51 | "+ (id)init;" ); |
52 | ASSERT_TRUE((bool)Style); |
53 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
54 | |
55 | Style = getStyle(StyleName: "LLVM" , FileName: "a.h" , FallbackStyle: "none" , |
56 | Code: "@interface\n" |
57 | "@end\n" |
58 | "//comment" ); |
59 | ASSERT_TRUE((bool)Style); |
60 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
61 | |
62 | Style = getStyle(StyleName: "LLVM" , FileName: "a.h" , FallbackStyle: "none" , |
63 | Code: "@interface\n" |
64 | "@end //comment" ); |
65 | ASSERT_TRUE((bool)Style); |
66 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
67 | |
68 | // No recognizable ObjC. |
69 | Style = getStyle(StyleName: "LLVM" , FileName: "a.h" , FallbackStyle: "none" , Code: "void f() {}" ); |
70 | ASSERT_TRUE((bool)Style); |
71 | EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language); |
72 | |
73 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , Code: "@interface Foo\n@end" ); |
74 | ASSERT_TRUE((bool)Style); |
75 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
76 | |
77 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , |
78 | Code: "const int interface = 1;\nconst int end = 2;" ); |
79 | ASSERT_TRUE((bool)Style); |
80 | EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language); |
81 | |
82 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , Code: "@protocol Foo\n@end" ); |
83 | ASSERT_TRUE((bool)Style); |
84 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
85 | |
86 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , |
87 | Code: "const int protocol = 1;\nconst int end = 2;" ); |
88 | ASSERT_TRUE((bool)Style); |
89 | EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language); |
90 | |
91 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , Code: "typedef NS_ENUM(int, Foo) {};" ); |
92 | ASSERT_TRUE((bool)Style); |
93 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
94 | |
95 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , Code: "typedef NS_CLOSED_ENUM(int, Foo) {};" ); |
96 | ASSERT_TRUE((bool)Style); |
97 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
98 | |
99 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , Code: "typedef NS_ERROR_ENUM(int, Foo) {};" ); |
100 | ASSERT_TRUE((bool)Style); |
101 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
102 | |
103 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , Code: R"objc( |
104 | NS_ASSUME_NONNULL_BEGIN |
105 | extern int i; |
106 | NS_ASSUME_NONNULL_END |
107 | )objc" ); |
108 | ASSERT_TRUE((bool)Style); |
109 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
110 | |
111 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , Code: R"objc( |
112 | FOUNDATION_EXTERN void DoStuff(void); |
113 | )objc" ); |
114 | ASSERT_TRUE((bool)Style); |
115 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
116 | |
117 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , Code: R"objc( |
118 | FOUNDATION_EXPORT void DoStuff(void); |
119 | )objc" ); |
120 | ASSERT_TRUE((bool)Style); |
121 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
122 | |
123 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , Code: "enum Foo {};" ); |
124 | ASSERT_TRUE((bool)Style); |
125 | EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language); |
126 | |
127 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , Code: "inline void Foo() { Log(@\"Foo\"); }" ); |
128 | ASSERT_TRUE((bool)Style); |
129 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
130 | |
131 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , Code: "inline void Foo() { Log(\"Foo\"); }" ); |
132 | ASSERT_TRUE((bool)Style); |
133 | EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language); |
134 | |
135 | Style = |
136 | getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , Code: "inline void Foo() { id = @[1, 2, 3]; }" ); |
137 | ASSERT_TRUE((bool)Style); |
138 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
139 | |
140 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , |
141 | Code: "inline void Foo() { id foo = @{1: 2, 3: 4, 5: 6}; }" ); |
142 | ASSERT_TRUE((bool)Style); |
143 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
144 | |
145 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , |
146 | Code: "inline void Foo() { int foo[] = {1, 2, 3}; }" ); |
147 | ASSERT_TRUE((bool)Style); |
148 | EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language); |
149 | |
150 | // ObjC characteristic types. |
151 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , Code: "extern NSString *kFoo;" ); |
152 | ASSERT_TRUE((bool)Style); |
153 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
154 | |
155 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , Code: "extern NSInteger Foo();" ); |
156 | ASSERT_TRUE((bool)Style); |
157 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
158 | |
159 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , Code: "NSObject *Foo();" ); |
160 | ASSERT_TRUE((bool)Style); |
161 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
162 | |
163 | Style = getStyle(StyleName: "{}" , FileName: "a.h" , FallbackStyle: "none" , Code: "NSSet *Foo();" ); |
164 | ASSERT_TRUE((bool)Style); |
165 | EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); |
166 | } |
167 | |
168 | TEST(FormatTestObjCStyle, AvoidDetectingDesignatedInitializersAsObjCInHeaders) { |
169 | auto Style = getStyle(StyleName: "LLVM" , FileName: "a.h" , FallbackStyle: "none" , |
170 | Code: "static const char *names[] = {[0] = \"foo\",\n" |
171 | "[kBar] = \"bar\"};" ); |
172 | ASSERT_TRUE((bool)Style); |
173 | EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language); |
174 | |
175 | Style = getStyle(StyleName: "LLVM" , FileName: "a.h" , FallbackStyle: "none" , |
176 | Code: "static const char *names[] = {[0] EQ \"foo\",\n" |
177 | "[kBar] EQ \"bar\"};" ); |
178 | ASSERT_TRUE((bool)Style); |
179 | EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language); |
180 | } |
181 | |
182 | TEST_F(FormatTestObjC, FormatObjCTryCatch) { |
183 | verifyFormat("@try {\n" |
184 | " f();\n" |
185 | "} @catch (NSException e) {\n" |
186 | " @throw;\n" |
187 | "} @finally {\n" |
188 | " exit(42);\n" |
189 | "}" ); |
190 | verifyFormat("DEBUG({\n" |
191 | " @try {\n" |
192 | " } @finally {\n" |
193 | " }\n" |
194 | "});" ); |
195 | } |
196 | |
197 | TEST_F(FormatTestObjC, FormatObjCAutoreleasepool) { |
198 | verifyFormat("@autoreleasepool {\n" |
199 | " f();\n" |
200 | "}\n" |
201 | "@autoreleasepool {\n" |
202 | " f();\n" |
203 | "}" ); |
204 | Style.BreakBeforeBraces = FormatStyle::BS_Custom; |
205 | Style.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always; |
206 | verifyFormat("@autoreleasepool\n" |
207 | "{\n" |
208 | " f();\n" |
209 | "}\n" |
210 | "@autoreleasepool\n" |
211 | "{\n" |
212 | " f();\n" |
213 | "}" ); |
214 | } |
215 | |
216 | TEST_F(FormatTestObjC, FormatObjCGenerics) { |
217 | Style.ColumnLimit = 40; |
218 | verifyFormat("int aaaaaaaaaaaaaaaa(\n" |
219 | " NSArray<aaaaaaaaaaaaaaaaaa *>\n" |
220 | " aaaaaaaaaaaaaaaaa);" ); |
221 | verifyFormat("int aaaaaaaaaaaaaaaa(\n" |
222 | " NSArray<aaaaaaaaaaaaaaaaaaa<\n" |
223 | " aaaaaaaaaaaaaaaa *> *>\n" |
224 | " aaaaaaaaaaaaaaaaa);" ); |
225 | } |
226 | |
227 | TEST_F(FormatTestObjC, FormatObjCSynchronized) { |
228 | verifyFormat("@synchronized(self) {\n" |
229 | " f();\n" |
230 | "}\n" |
231 | "@synchronized(self) {\n" |
232 | " f();\n" |
233 | "}" ); |
234 | Style.BreakBeforeBraces = FormatStyle::BS_Custom; |
235 | Style.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always; |
236 | verifyFormat("@synchronized(self)\n" |
237 | "{\n" |
238 | " f();\n" |
239 | "}\n" |
240 | "@synchronized(self)\n" |
241 | "{\n" |
242 | " f();\n" |
243 | "}" ); |
244 | } |
245 | |
246 | TEST_F(FormatTestObjC, FormatObjCInterface) { |
247 | verifyFormat("@interface Foo : NSObject <NSSomeDelegate> {\n" |
248 | "@public\n" |
249 | " int field1;\n" |
250 | "@protected\n" |
251 | " int field2;\n" |
252 | "@private\n" |
253 | " int field3;\n" |
254 | "@package\n" |
255 | " int field4;\n" |
256 | "}\n" |
257 | "+ (id)init;\n" |
258 | "@end" ); |
259 | |
260 | verifyFormat("@interface /* wait for it */ Foo\n" |
261 | "+ (id)init;\n" |
262 | "// Look, a comment!\n" |
263 | "- (int)answerWith:(int)i;\n" |
264 | "@end" ); |
265 | |
266 | verifyFormat("@interface Foo\n" |
267 | "@end\n" |
268 | "@interface Bar\n" |
269 | "@end" ); |
270 | |
271 | verifyFormat("@interface Foo : Bar\n" |
272 | "@property(assign, readwrite) NSInteger bar;\n" |
273 | "+ (id)init;\n" |
274 | "@end" ); |
275 | |
276 | verifyFormat("FOUNDATION_EXPORT NS_AVAILABLE_IOS(10.0) @interface Foo : Bar\n" |
277 | "@property(assign, readwrite) NSInteger bar;\n" |
278 | "+ (id)init;\n" |
279 | "@end" ); |
280 | |
281 | verifyFormat("@interface Foo : /**/ Bar /**/ <Baz, /**/ Quux>\n" |
282 | "+ (id)init;\n" |
283 | "@end" ); |
284 | |
285 | verifyFormat("@interface Foo (HackStuff)\n" |
286 | "+ (id)init;\n" |
287 | "@end" ); |
288 | |
289 | verifyFormat("@interface Foo ()\n" |
290 | "+ (id)init;\n" |
291 | "@end" ); |
292 | |
293 | verifyFormat("@interface Foo (HackStuff) <MyProtocol>\n" |
294 | "+ (id)init;\n" |
295 | "@end" ); |
296 | |
297 | verifyFormat("@interface Foo {\n" |
298 | " int _i;\n" |
299 | "}\n" |
300 | "+ (id)init;\n" |
301 | "@end" ); |
302 | |
303 | verifyFormat("@interface Foo : Bar {\n" |
304 | " int _i;\n" |
305 | "}\n" |
306 | "+ (id)init;\n" |
307 | "@end" ); |
308 | |
309 | verifyFormat("@interface Foo : Bar <Baz, Quux> {\n" |
310 | " int _i;\n" |
311 | "}\n" |
312 | "+ (id)init;\n" |
313 | "@end" ); |
314 | |
315 | verifyFormat("@interface Foo<Baz : Blech> : Bar <Baz, Quux> {\n" |
316 | " int _i;\n" |
317 | "}\n" |
318 | "+ (id)init;\n" |
319 | "@end" ); |
320 | |
321 | verifyFormat("@interface Foo<Bar : Baz <Blech>> : Xyzzy <Corge> {\n" |
322 | " int _i;\n" |
323 | "}\n" |
324 | "+ (id)init;\n" |
325 | "@end" ); |
326 | |
327 | verifyFormat("@interface Foo<Bar : Baz <Blech>> : Xyzzy <Corge> <Quux> {\n" |
328 | " int _i;\n" |
329 | "}\n" |
330 | "+ (id)init;\n" |
331 | "@end" ); |
332 | |
333 | verifyFormat("@interface Foo : Bar <Baz> <Blech>\n" |
334 | "@end" ); |
335 | |
336 | verifyFormat("@interface Foo : Bar <Baz> <Blech, Xyzzy, Corge>\n" |
337 | "@end" ); |
338 | |
339 | verifyFormat("@interface Foo (HackStuff) {\n" |
340 | " int _i;\n" |
341 | "}\n" |
342 | "+ (id)init;\n" |
343 | "@end" ); |
344 | |
345 | verifyFormat("@interface Foo () {\n" |
346 | " int _i;\n" |
347 | "}\n" |
348 | "+ (id)init;\n" |
349 | "@end" ); |
350 | |
351 | verifyFormat("@interface Foo (HackStuff) <MyProtocol> {\n" |
352 | " int _i;\n" |
353 | "}\n" |
354 | "+ (id)init;\n" |
355 | "@end" ); |
356 | verifyFormat("@interface Foo\n" |
357 | "- (void)foo {\n" |
358 | "}\n" |
359 | "@end\n" |
360 | "@implementation Bar\n" |
361 | "- (void)bar {\n" |
362 | "}\n" |
363 | "@end" ); |
364 | Style.ColumnLimit = 40; |
365 | verifyFormat("@interface ccccccccccccc () <\n" |
366 | " ccccccccccccc, ccccccccccccc,\n" |
367 | " ccccccccccccc, ccccccccccccc> {\n" |
368 | "}" ); |
369 | verifyFormat("@interface ccccccccccccc (ccccccccccc) <\n" |
370 | " ccccccccccccc> {\n" |
371 | "}" ); |
372 | Style.ObjCBinPackProtocolList = FormatStyle::BPS_Never; |
373 | verifyFormat("@interface ddddddddddddd () <\n" |
374 | " ddddddddddddd,\n" |
375 | " ddddddddddddd,\n" |
376 | " ddddddddddddd,\n" |
377 | " ddddddddddddd> {\n" |
378 | "}" ); |
379 | |
380 | Style.BinPackParameters = false; |
381 | Style.ObjCBinPackProtocolList = FormatStyle::BPS_Auto; |
382 | verifyFormat("@interface eeeeeeeeeeeee () <\n" |
383 | " eeeeeeeeeeeee,\n" |
384 | " eeeeeeeeeeeee,\n" |
385 | " eeeeeeeeeeeee,\n" |
386 | " eeeeeeeeeeeee> {\n" |
387 | "}" ); |
388 | Style.ObjCBinPackProtocolList = FormatStyle::BPS_Always; |
389 | verifyFormat("@interface fffffffffffff () <\n" |
390 | " fffffffffffff, fffffffffffff,\n" |
391 | " fffffffffffff, fffffffffffff> {\n" |
392 | "}" ); |
393 | |
394 | Style = getGoogleStyle(Language: FormatStyle::LK_ObjC); |
395 | verifyFormat("@interface Foo : NSObject <NSSomeDelegate> {\n" |
396 | " @public\n" |
397 | " int field1;\n" |
398 | " @protected\n" |
399 | " int field2;\n" |
400 | " @private\n" |
401 | " int field3;\n" |
402 | " @package\n" |
403 | " int field4;\n" |
404 | "}\n" |
405 | "+ (id)init;\n" |
406 | "@end" ); |
407 | verifyFormat("@interface Foo : Bar <Baz, Quux>\n" |
408 | "+ (id)init;\n" |
409 | "@end" ); |
410 | verifyFormat("@interface Foo (HackStuff) <MyProtocol>\n" |
411 | "+ (id)init;\n" |
412 | "@end" ); |
413 | Style.ColumnLimit = 40; |
414 | // BinPackParameters should be true by default. |
415 | verifyFormat("void eeeeeeee(int eeeee, int eeeee,\n" |
416 | " int eeeee, int eeeee);" ); |
417 | // ObjCBinPackProtocolList should be BPS_Never by default. |
418 | verifyFormat("@interface fffffffffffff () <\n" |
419 | " fffffffffffff,\n" |
420 | " fffffffffffff,\n" |
421 | " fffffffffffff,\n" |
422 | " fffffffffffff> {\n" |
423 | "}" ); |
424 | verifyFormat("@interface ggggggggggggg\n" |
425 | " : ggggggggggggg <ggggggggggggg>\n" |
426 | " <ggggggggggggg>\n" |
427 | "@end" ); |
428 | } |
429 | |
430 | TEST_F(FormatTestObjC, FormatObjCImplementation) { |
431 | verifyFormat("@implementation Foo : NSObject {\n" |
432 | "@public\n" |
433 | " int field1;\n" |
434 | "@protected\n" |
435 | " int field2;\n" |
436 | "@private\n" |
437 | " int field3;\n" |
438 | "@package\n" |
439 | " int field4;\n" |
440 | "}\n" |
441 | "+ (id)init {\n}\n" |
442 | "@end" ); |
443 | |
444 | verifyFormat("@implementation Foo\n" |
445 | "+ (id)init {\n" |
446 | " if (true)\n" |
447 | " return nil;\n" |
448 | "}\n" |
449 | "// Look, a comment!\n" |
450 | "- (int)answerWith:(int)i {\n" |
451 | " return i;\n" |
452 | "}\n" |
453 | "+ (int)answerWith:(int)i {\n" |
454 | " return i;\n" |
455 | "}\n" |
456 | "@end" ); |
457 | |
458 | verifyFormat("@implementation Foo\n" |
459 | "@end\n" |
460 | "@implementation Bar\n" |
461 | "@end" ); |
462 | |
463 | EXPECT_EQ("@implementation Foo : Bar\n" |
464 | "+ (id)init {\n}\n" |
465 | "- (void)foo {\n}\n" |
466 | "@end" , |
467 | format("@implementation Foo : Bar\n" |
468 | "+(id)init{}\n" |
469 | "-(void)foo{}\n" |
470 | "@end" )); |
471 | |
472 | verifyFormat("@implementation Foo {\n" |
473 | " int _i;\n" |
474 | "}\n" |
475 | "+ (id)init {\n}\n" |
476 | "@end" ); |
477 | |
478 | verifyFormat("@implementation Foo : Bar {\n" |
479 | " int _i;\n" |
480 | "}\n" |
481 | "+ (id)init {\n}\n" |
482 | "@end" ); |
483 | |
484 | verifyFormat("@implementation Foo (HackStuff)\n" |
485 | "+ (id)init {\n}\n" |
486 | "@end" ); |
487 | verifyFormat("@implementation ObjcClass\n" |
488 | "- (void)method;\n" |
489 | "{}\n" |
490 | "@end" ); |
491 | |
492 | Style = getGoogleStyle(Language: FormatStyle::LK_ObjC); |
493 | verifyFormat("@implementation Foo : NSObject {\n" |
494 | " @public\n" |
495 | " int field1;\n" |
496 | " @protected\n" |
497 | " int field2;\n" |
498 | " @private\n" |
499 | " int field3;\n" |
500 | " @package\n" |
501 | " int field4;\n" |
502 | "}\n" |
503 | "+ (id)init {\n}\n" |
504 | "@end" ); |
505 | } |
506 | |
507 | TEST_F(FormatTestObjC, FormatObjCProtocol) { |
508 | verifyFormat("@protocol Foo\n" |
509 | "@property(weak) id delegate;\n" |
510 | "- (NSUInteger)numberOfThings;\n" |
511 | "@end" ); |
512 | |
513 | verifyFormat("@protocol MyProtocol <NSObject>\n" |
514 | "- (NSUInteger)numberOfThings;\n" |
515 | "@end" ); |
516 | |
517 | verifyFormat("@protocol Foo;\n" |
518 | "@protocol Bar;" ); |
519 | |
520 | verifyFormat("@protocol Foo\n" |
521 | "@end\n" |
522 | "@protocol Bar\n" |
523 | "@end" ); |
524 | |
525 | verifyFormat("FOUNDATION_EXPORT NS_AVAILABLE_IOS(10.0) @protocol Foo\n" |
526 | "@property(assign, readwrite) NSInteger bar;\n" |
527 | "@end" ); |
528 | |
529 | verifyFormat("@protocol myProtocol\n" |
530 | "- (void)mandatoryWithInt:(int)i;\n" |
531 | "@optional\n" |
532 | "- (void)optional;\n" |
533 | "@required\n" |
534 | "- (void)required;\n" |
535 | "@optional\n" |
536 | "@property(assign) int madProp;\n" |
537 | "@end" ); |
538 | |
539 | verifyFormat("@property(nonatomic, assign, readonly)\n" |
540 | " int *looooooooooooooooooooooooooooongNumber;\n" |
541 | "@property(nonatomic, assign, readonly)\n" |
542 | " NSString *looooooooooooooooooooooooooooongName;" ); |
543 | |
544 | verifyFormat("@implementation PR18406\n" |
545 | "}\n" |
546 | "@end" ); |
547 | |
548 | Style = getGoogleStyle(Language: FormatStyle::LK_ObjC); |
549 | verifyFormat("@protocol MyProtocol <NSObject>\n" |
550 | "- (NSUInteger)numberOfThings;\n" |
551 | "@end" ); |
552 | } |
553 | |
554 | TEST_F(FormatTestObjC, FormatObjCMethodDeclarations) { |
555 | verifyFormat("- (void)doSomethingWith:(GTMFoo *)theFoo\n" |
556 | " rect:(NSRect)theRect\n" |
557 | " interval:(float)theInterval {\n" |
558 | "}" ); |
559 | verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n" |
560 | " longKeyword:(NSRect)theRect\n" |
561 | " longerKeyword:(float)theInterval\n" |
562 | " error:(NSError **)theError {\n" |
563 | "}" ); |
564 | verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n" |
565 | " longKeyword:(NSRect)theRect\n" |
566 | " evenLongerKeyword:(float)theInterval\n" |
567 | " error:(NSError **)theError {\n" |
568 | "}" ); |
569 | verifyFormat("+ (instancetype)new;" ); |
570 | Style.ColumnLimit = 60; |
571 | verifyFormat("- (instancetype)initXxxxxx:(id<x>)x\n" |
572 | " y:(id<yyyyyyyyyyyyyyyyyyyy>)y\n" |
573 | " NS_DESIGNATED_INITIALIZER;" ); |
574 | verifyFormat("- (void)drawRectOn:(id)surface\n" |
575 | " ofSize:(size_t)height\n" |
576 | " :(size_t)width;" ); |
577 | Style.ColumnLimit = 40; |
578 | // Make sure selectors with 0, 1, or more arguments are indented when wrapped. |
579 | verifyFormat("- (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n" |
580 | " aaaaaaaaaaaaaaaaaaaaaaaaaaaa;" ); |
581 | verifyFormat("- (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n" |
582 | " aaaaaaaaaaaaaaaaaaaaaaaaaaaa:(int)a;" ); |
583 | verifyFormat("- (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n" |
584 | " aaaaaaaaaaaaaaaaaaaaaaaaaaaa:(int)a\n" |
585 | " aaaaaaaaaaaaaaaaaaaaaaaaaaaa:(int)a;" ); |
586 | verifyFormat("- (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n" |
587 | " aaaaaaaaaaaaaaaaaaaaaaaaaaa:(int)a\n" |
588 | " aaaaaaaaaaaaaaaaaaaaaaaaaaaa:(int)a;" ); |
589 | verifyFormat("- (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n" |
590 | " aaaaaaaaaaaaaaaaaaaaaaaaaaaa:(int)a\n" |
591 | " aaaaaaaaaaaaaaaaaaaaaaaaaaa:(int)a;" ); |
592 | |
593 | // Continuation indent width should win over aligning colons if the function |
594 | // name is long. |
595 | Style = getGoogleStyle(Language: FormatStyle::LK_ObjC); |
596 | Style.ColumnLimit = 40; |
597 | verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n" |
598 | " dontAlignNamef:(NSRect)theRect {\n" |
599 | "}" ); |
600 | |
601 | // Make sure we don't break aligning for short parameter names. |
602 | verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n" |
603 | " aShortf:(NSRect)theRect {\n" |
604 | "}" ); |
605 | |
606 | // Format pairs correctly. |
607 | Style.ColumnLimit = 80; |
608 | verifyFormat("- (void)drawRectOn:(id)surface\n" |
609 | " ofSize:(aaaaaaaa)height\n" |
610 | " :(size_t)width\n" |
611 | " atOrigin:(size_t)x\n" |
612 | " :(size_t)y\n" |
613 | " aaaaa:(a)yyy\n" |
614 | " bbb:(d)cccc;" ); |
615 | verifyFormat("- (void)drawRectOn:(id)surface ofSize:(aaa)height:(bbb)width;" ); |
616 | |
617 | // BraceWrapping AfterFunction is respected for ObjC methods |
618 | Style = getGoogleStyle(Language: FormatStyle::LK_ObjC); |
619 | Style.BreakBeforeBraces = FormatStyle::BS_Custom; |
620 | Style.BraceWrapping.AfterFunction = true; |
621 | verifyFormat("@implementation Foo\n" |
622 | "- (void)foo:(id)bar\n" |
623 | "{\n" |
624 | "}\n" |
625 | "@end" ); |
626 | } |
627 | |
628 | TEST_F(FormatTestObjC, FormatObjCMethodExpr) { |
629 | verifyFormat("[foo bar:baz];" ); |
630 | verifyFormat("[foo bar]->baz;" ); |
631 | verifyFormat("return [foo bar:baz];" ); |
632 | verifyFormat("return (a)[foo bar:baz];" ); |
633 | verifyFormat("f([foo bar:baz]);" ); |
634 | verifyFormat("f(2, [foo bar:baz]);" ); |
635 | verifyFormat("f(2, a ? b : c);" ); |
636 | verifyFormat("[[self initWithInt:4] bar:[baz quux:arrrr]];" ); |
637 | |
638 | // Unary operators. |
639 | verifyFormat("int a = +[foo bar:baz];" ); |
640 | verifyFormat("int a = -[foo bar:baz];" ); |
641 | verifyFormat("int a = ![foo bar:baz];" ); |
642 | verifyFormat("int a = ~[foo bar:baz];" ); |
643 | verifyFormat("int a = ++[foo bar:baz];" ); |
644 | verifyFormat("int a = --[foo bar:baz];" ); |
645 | verifyFormat("int a = sizeof [foo bar:baz];" ); |
646 | verifyFormat("int a = alignof [foo bar:baz];" ); |
647 | verifyFormat("int a = &[foo bar:baz];" ); |
648 | verifyFormat("int a = *[foo bar:baz];" ); |
649 | // FIXME: Make casts work, without breaking f()[4]. |
650 | // verifyFormat("int a = (int)[foo bar:baz];"); |
651 | // verifyFormat("return (int)[foo bar:baz];"); |
652 | // verifyFormat("(void)[foo bar:baz];"); |
653 | verifyFormat("return (MyType *)[self.tableView cellForRowAtIndexPath:cell];" ); |
654 | |
655 | // Binary operators. |
656 | verifyFormat("[foo bar:baz], [foo bar:baz];" ); |
657 | verifyFormat("[foo bar:baz] = [foo bar:baz];" ); |
658 | verifyFormat("[foo bar:baz] *= [foo bar:baz];" ); |
659 | verifyFormat("[foo bar:baz] /= [foo bar:baz];" ); |
660 | verifyFormat("[foo bar:baz] %= [foo bar:baz];" ); |
661 | verifyFormat("[foo bar:baz] += [foo bar:baz];" ); |
662 | verifyFormat("[foo bar:baz] -= [foo bar:baz];" ); |
663 | verifyFormat("[foo bar:baz] <<= [foo bar:baz];" ); |
664 | verifyFormat("[foo bar:baz] >>= [foo bar:baz];" ); |
665 | verifyFormat("[foo bar:baz] &= [foo bar:baz];" ); |
666 | verifyFormat("[foo bar:baz] ^= [foo bar:baz];" ); |
667 | verifyFormat("[foo bar:baz] |= [foo bar:baz];" ); |
668 | verifyFormat("[foo bar:baz] ? [foo bar:baz] : [foo bar:baz];" ); |
669 | verifyFormat("[foo bar:baz] || [foo bar:baz];" ); |
670 | verifyFormat("[foo bar:baz] && [foo bar:baz];" ); |
671 | verifyFormat("[foo bar:baz] | [foo bar:baz];" ); |
672 | verifyFormat("[foo bar:baz] ^ [foo bar:baz];" ); |
673 | verifyFormat("[foo bar:baz] & [foo bar:baz];" ); |
674 | verifyFormat("[foo bar:baz] == [foo bar:baz];" ); |
675 | verifyFormat("[foo bar:baz] != [foo bar:baz];" ); |
676 | verifyFormat("[foo bar:baz] >= [foo bar:baz];" ); |
677 | verifyFormat("[foo bar:baz] <= [foo bar:baz];" ); |
678 | verifyFormat("[foo bar:baz] > [foo bar:baz];" ); |
679 | verifyFormat("[foo bar:baz] < [foo bar:baz];" ); |
680 | verifyFormat("[foo bar:baz] >> [foo bar:baz];" ); |
681 | verifyFormat("[foo bar:baz] << [foo bar:baz];" ); |
682 | verifyFormat("[foo bar:baz] - [foo bar:baz];" ); |
683 | verifyFormat("[foo bar:baz] + [foo bar:baz];" ); |
684 | verifyFormat("[foo bar:baz] * [foo bar:baz];" ); |
685 | verifyFormat("[foo bar:baz] / [foo bar:baz];" ); |
686 | verifyFormat("[foo bar:baz] % [foo bar:baz];" ); |
687 | // Whew! |
688 | |
689 | verifyFormat("return in[42];" ); |
690 | verifyFormat("for (auto v : in[1]) {\n}" ); |
691 | verifyFormat("for (int i = 0; i < in[a]; ++i) {\n}" ); |
692 | verifyFormat("for (int i = 0; in[a] < i; ++i) {\n}" ); |
693 | verifyFormat("for (int i = 0; i < n; ++i, ++in[a]) {\n}" ); |
694 | verifyFormat("for (int i = 0; i < n; ++i, in[a]++) {\n}" ); |
695 | verifyFormat("for (int i = 0; i < f(in[a]); ++i, in[a]++) {\n}" ); |
696 | verifyFormat("for (id foo in [self getStuffFor:bla]) {\n" |
697 | "}" ); |
698 | verifyFormat("[self aaaaa:MACRO(a, b:, c:)];" ); |
699 | verifyFormat("[self aaaaa:MACRO(a, b:c:, d:e:)];" ); |
700 | verifyFormat("[self aaaaa:MACRO(a, b:c:d:, e:f:g:)];" ); |
701 | verifyFormat("int XYMyFoo(int a, int b) NS_SWIFT_NAME(foo(self:scale:));" ); |
702 | verifyFormat("[self aaaaa:(1 + 2) bbbbb:3];" ); |
703 | verifyFormat("[self aaaaa:(Type)a bbbbb:3];" ); |
704 | |
705 | verifyFormat("[self stuffWithInt:(4 + 2) float:4.5];" ); |
706 | verifyFormat("[self stuffWithInt:a ? b : c float:4.5];" ); |
707 | verifyFormat("[self stuffWithInt:a ? [self foo:bar] : c];" ); |
708 | verifyFormat("[self stuffWithInt:a ? (e ? f : g) : c];" ); |
709 | verifyFormat("[cond ? obj1 : obj2 methodWithParam:param]" ); |
710 | verifyFormat("[button setAction:@selector(zoomOut:)];" ); |
711 | verifyFormat("[color getRed:&r green:&g blue:&b alpha:&a];" ); |
712 | |
713 | verifyFormat("arr[[self indexForFoo:a]];" ); |
714 | verifyFormat("throw [self errorFor:a];" ); |
715 | verifyFormat("@throw [self errorFor:a];" ); |
716 | |
717 | verifyFormat("[(id)foo bar:(id)baz quux:(id)snorf];" ); |
718 | verifyFormat("[(id)foo bar:(id) ? baz : quux];" ); |
719 | verifyFormat("4 > 4 ? (id)a : (id)baz;" ); |
720 | |
721 | unsigned PreviousColumnLimit = Style.ColumnLimit; |
722 | Style.ColumnLimit = 50; |
723 | // Instead of: |
724 | // bool a = |
725 | // ([object a:42] == 0 || [object a:42 |
726 | // b:42] == 0); |
727 | verifyFormat("bool a = ([object a:42] == 0 ||\n" |
728 | " [object a:42 b:42] == 0);" ); |
729 | Style.ColumnLimit = PreviousColumnLimit; |
730 | verifyFormat("bool a = ([aaaaaaaa aaaaa] == aaaaaaaaaaaaaaaaa ||\n" |
731 | " [aaaaaaaa aaaaa] == aaaaaaaaaaaaaaaaaaaa);" ); |
732 | |
733 | // This tests that the formatter doesn't break after "backing" but before ":", |
734 | // which would be at 80 columns. |
735 | verifyFormat( |
736 | "void f() {\n" |
737 | " if ((self = [super initWithContentRect:contentRect\n" |
738 | " styleMask:styleMask ?: otherMask\n" |
739 | " backing:NSBackingStoreBuffered\n" |
740 | " defer:YES]))" ); |
741 | |
742 | verifyFormat( |
743 | "[foo checkThatBreakingAfterColonWorksOk:\n" |
744 | " [bar ifItDoes:reduceOverallLineLengthLikeInThisCase]];" ); |
745 | |
746 | verifyFormat("[myObj short:arg1 // Force line break\n" |
747 | " longKeyword:arg2 != nil ? arg2 : @\"longKeyword\"\n" |
748 | " evenLongerKeyword:arg3 ?: @\"evenLongerKeyword\"\n" |
749 | " error:arg4];" ); |
750 | verifyFormat( |
751 | "void f() {\n" |
752 | " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n" |
753 | " initWithContentRect:NSMakeRect(origin_global.x, origin_global.y,\n" |
754 | " pos.width(), pos.height())\n" |
755 | " styleMask:NSBorderlessWindowMask\n" |
756 | " backing:NSBackingStoreBuffered\n" |
757 | " defer:NO]);\n" |
758 | "}" ); |
759 | verifyFormat("[contentsContainer replaceSubview:[subviews objectAtIndex:0]\n" |
760 | " with:contentsNativeView];" ); |
761 | |
762 | verifyFormat( |
763 | "[pboard addTypes:[NSArray arrayWithObject:kBookmarkButtonDragType]\n" |
764 | " owner:nillllll];" ); |
765 | |
766 | verifyFormat( |
767 | "[pboard setData:[NSData dataWithBytes:&button length:sizeof(button)]\n" |
768 | " forType:kBookmarkButtonDragType];" ); |
769 | |
770 | verifyFormat("[defaultCenter addObserver:self\n" |
771 | " selector:@selector(willEnterFullscreen)\n" |
772 | " name:kWillEnterFullscreenNotification\n" |
773 | " object:nil];" ); |
774 | verifyFormat("[image_rep drawInRect:drawRect\n" |
775 | " fromRect:NSZeroRect\n" |
776 | " operation:NSCompositeCopy\n" |
777 | " fraction:1.0\n" |
778 | " respectFlipped:NO\n" |
779 | " hints:nil];" ); |
780 | verifyFormat("[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" |
781 | " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];" ); |
782 | verifyFormat("[aaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaa)\n" |
783 | " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];" ); |
784 | verifyFormat("[aaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaa[aaaaaaaaaaaaaaaaaaaaa]\n" |
785 | " aaaaaaaaaaaaaaaaaaaaaa];" ); |
786 | |
787 | verifyFormat( |
788 | "scoped_nsobject<NSTextField> message(\n" |
789 | " // The frame will be fixed up when |-setMessageText:| is called.\n" |
790 | " [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]);" ); |
791 | verifyFormat("[self aaaaaa:bbbbbbbbbbbbb\n" |
792 | " aaaaaaaaaa:bbbbbbbbbbbbbbbbb\n" |
793 | " aaaaa:bbbbbbbbbbb + bbbbbbbbbbbb\n" |
794 | " aaaa:bbb];" ); |
795 | verifyFormat("[self param:function( //\n" |
796 | " parameter)]" ); |
797 | verifyFormat( |
798 | "[self aaaaaaaaaa:aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa |\n" |
799 | " aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa |\n" |
800 | " aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa];" ); |
801 | |
802 | // Variadic parameters. |
803 | verifyFormat( |
804 | "NSArray *myStrings = [NSArray stringarray:@\"a\", @\"b\", nil];" ); |
805 | verifyFormat( |
806 | "[self aaaaaaaaaaaaa:aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa,\n" |
807 | " aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa,\n" |
808 | " aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa];" ); |
809 | |
810 | verifyFormat("[self // break\n" |
811 | " a:a\n" |
812 | " aaa:aaa];" ); |
813 | |
814 | // Formats pair-parameters. |
815 | verifyFormat("[I drawRectOn:surface ofSize:aa:bbb atOrigin:cc:dd];" ); |
816 | verifyFormat("[I drawRectOn:surface //\n" |
817 | " ofSize:aa:bbb\n" |
818 | " atOrigin:cc:dd];" ); |
819 | |
820 | // Inline block as a first argument. |
821 | verifyFormat("[object justBlock:^{\n" |
822 | " a = 42;\n" |
823 | "}];" ); |
824 | verifyFormat("[object\n" |
825 | " justBlock:^{\n" |
826 | " a = 42;\n" |
827 | " }\n" |
828 | " notBlock:42\n" |
829 | " a:42];" ); |
830 | verifyFormat("[object\n" |
831 | " firstBlock:^{\n" |
832 | " a = 42;\n" |
833 | " }\n" |
834 | " blockWithLongerName:^{\n" |
835 | " a = 42;\n" |
836 | " }];" ); |
837 | verifyFormat("[object\n" |
838 | " blockWithLongerName:^{\n" |
839 | " a = 42;\n" |
840 | " }\n" |
841 | " secondBlock:^{\n" |
842 | " a = 42;\n" |
843 | " }];" ); |
844 | verifyFormat("[object\n" |
845 | " firstBlock:^{\n" |
846 | " a = 42;\n" |
847 | " }\n" |
848 | " notBlock:42\n" |
849 | " secondBlock:^{\n" |
850 | " a = 42;\n" |
851 | " }];" ); |
852 | |
853 | // Space between cast rparen and selector name component. |
854 | verifyFormat("[((Foo *)foo) bar];" ); |
855 | verifyFormat("[((Foo *)foo) bar:1 blech:2];" ); |
856 | |
857 | Style.ColumnLimit = 20; |
858 | verifyFormat("aaaaa = [a aa:aa\n" |
859 | " aa:aa];" ); |
860 | verifyFormat("aaaaaa = [aa aa:aa\n" |
861 | " aa:aa];" ); |
862 | |
863 | // Message receiver taking multiple lines. |
864 | // Non-corner case. |
865 | verifyFormat("[[object block:^{\n" |
866 | " return 42;\n" |
867 | "}] a:42 b:42];" ); |
868 | // Arguments just fit into one line. |
869 | verifyFormat("[[object block:^{\n" |
870 | " return 42;\n" |
871 | "}] aaaaaaa:42 b:42];" ); |
872 | // Arguments just over a column limit. |
873 | verifyFormat("[[object block:^{\n" |
874 | " return 42;\n" |
875 | "}] aaaaaaa:42\n" |
876 | " bb:42];" ); |
877 | // Arguments just fit into one line. |
878 | Style.ColumnLimit = 23; |
879 | verifyFormat("[[obj a:42\n" |
880 | " b:42\n" |
881 | " c:42\n" |
882 | " d:42] e:42 f:42];" ); |
883 | |
884 | // Arguments do not fit into one line with a receiver. |
885 | Style.ColumnLimit = 20; |
886 | verifyFormat("[[obj a:42] a:42\n" |
887 | " b:42];" ); |
888 | verifyFormat("[[obj a:42] a:42\n" |
889 | " b:42\n" |
890 | " c:42];" ); |
891 | verifyFormat("[[obj aaaaaa:42\n" |
892 | " b:42]\n" |
893 | " cc:42\n" |
894 | " d:42];" ); |
895 | |
896 | // Avoid breaking receiver expression. |
897 | Style.ColumnLimit = 30; |
898 | verifyFormat("fooooooo =\n" |
899 | " [[obj fooo] aaa:42\n" |
900 | " aaa:42];" ); |
901 | verifyFormat("[[[obj foo] bar] aa:42\n" |
902 | " bb:42\n" |
903 | " cc:42];" ); |
904 | |
905 | // Avoid breaking between unary operators and ObjC method expressions. |
906 | Style.ColumnLimit = 45; |
907 | verifyFormat("if (a012345678901234567890123 &&\n" |
908 | " ![foo bar]) {\n" |
909 | "}" ); |
910 | verifyFormat("if (a012345678901234567890123 &&\n" |
911 | " +[foo bar]) {\n" |
912 | "}" ); |
913 | verifyFormat("if (a012345678901234567890123 &&\n" |
914 | " -[foo bar]) {\n" |
915 | "}" ); |
916 | |
917 | Style.ColumnLimit = 70; |
918 | verifyFormat( |
919 | "void f() {\n" |
920 | " popup_wdow_.reset([[RenderWidgetPopupWindow alloc]\n" |
921 | " iniithContentRect:NSMakRet(origin_global.x, origin_global.y,\n" |
922 | " pos.width(), pos.height())\n" |
923 | " syeMask:NSBorderlessWindowMask\n" |
924 | " bking:NSBackingStoreBuffered\n" |
925 | " der:NO]);\n" |
926 | "}" ); |
927 | |
928 | Style.ColumnLimit = 60; |
929 | verifyFormat("[call aaaaaaaa.aaaaaa.aaaaaaaa.aaaaaaaa.aaaaaaaa.aaaaaaaa\n" |
930 | " .aaaaaaaa];" ); // FIXME: Indentation seems off. |
931 | // FIXME: This violates the column limit. |
932 | verifyFormat( |
933 | "[aaaaaaaaaaaaaaaaaaaaaaaaa\n" |
934 | " aaaaaaaaaaaaaaaaa:aaaaaaaa\n" |
935 | " aaa:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];" ); |
936 | |
937 | Style = getChromiumStyle(Language: FormatStyle::LK_ObjC); |
938 | Style.ColumnLimit = 80; |
939 | verifyFormat( |
940 | "void f() {\n" |
941 | " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n" |
942 | " initWithContentRect:NSMakeRect(origin_global.x, origin_global.y,\n" |
943 | " pos.width(), pos.height())\n" |
944 | " styleMask:NSBorderlessWindowMask\n" |
945 | " backing:NSBackingStoreBuffered\n" |
946 | " defer:NO]);\n" |
947 | "}" ); |
948 | |
949 | // Respect continuation indent and colon alignment (e.g. when object name is |
950 | // short, and first selector is the longest one) |
951 | Style = getLLVMStyle(); |
952 | Style.Language = FormatStyle::LK_ObjC; |
953 | Style.ContinuationIndentWidth = 8; |
954 | verifyFormat("[self performSelectorOnMainThread:@selector(loadAccessories)\n" |
955 | " withObject:nil\n" |
956 | " waitUntilDone:false];" ); |
957 | verifyFormat("[self performSelector:@selector(loadAccessories)\n" |
958 | " withObjectOnMainThread:nil\n" |
959 | " waitUntilDone:false];" ); |
960 | verifyFormat( |
961 | "[aaaaaaaaaaaaaaaaaaaaaaaaa\n" |
962 | " performSelectorOnMainThread:@selector(loadAccessories)\n" |
963 | " withObject:nil\n" |
964 | " waitUntilDone:false];" ); |
965 | verifyFormat( |
966 | "[self // force wrapping\n" |
967 | " performSelectorOnMainThread:@selector(loadAccessories)\n" |
968 | " withObject:nil\n" |
969 | " waitUntilDone:false];" ); |
970 | |
971 | // The appropriate indentation is used after a block statement. |
972 | Style.ContinuationIndentWidth = 4; |
973 | verifyFormat( |
974 | "void aaaaaaaaaaaaaaaaaaaaa(int c) {\n" |
975 | " if (c) {\n" |
976 | " f();\n" |
977 | " }\n" |
978 | " [dddddddddddddddddddddddddddddddddddddddddddddddddddddddd\n" |
979 | " eeeeeeeeeeeeeeeeeeeeeeeeeeeee:^(fffffffffffffff gggggggg) {\n" |
980 | " f(SSSSS, c);\n" |
981 | " }];\n" |
982 | "}" ); |
983 | } |
984 | |
985 | TEST_F(FormatTestObjC, ObjCAt) { |
986 | verifyFormat("@autoreleasepool" ); |
987 | verifyFormat("@catch" ); |
988 | verifyFormat("@class" ); |
989 | verifyFormat("@compatibility_alias" ); |
990 | verifyFormat("@defs" ); |
991 | verifyFormat("@dynamic" ); |
992 | verifyFormat("@encode" ); |
993 | verifyFormat("@end" ); |
994 | verifyFormat("@finally" ); |
995 | verifyFormat("@implementation" ); |
996 | verifyFormat("@import" ); |
997 | verifyFormat("@interface" ); |
998 | verifyFormat("@optional" ); |
999 | verifyFormat("@package" ); |
1000 | verifyFormat("@private" ); |
1001 | verifyFormat("@property" ); |
1002 | verifyFormat("@protected" ); |
1003 | verifyFormat("@protocol" ); |
1004 | verifyFormat("@public" ); |
1005 | verifyFormat("@required" ); |
1006 | verifyFormat("@selector" ); |
1007 | verifyFormat("@synchronized" ); |
1008 | verifyFormat("@synthesize" ); |
1009 | verifyFormat("@throw" ); |
1010 | verifyFormat("@try" ); |
1011 | |
1012 | EXPECT_EQ("@interface" , format("@ interface" )); |
1013 | |
1014 | // The precise formatting of this doesn't matter, nobody writes code like |
1015 | // this. |
1016 | verifyFormat("@ /*foo*/ interface" ); |
1017 | } |
1018 | |
1019 | TEST_F(FormatTestObjC, ObjCBlockTypesAndVariables) { |
1020 | verifyFormat("void DoStuffWithBlockType(int (^)(char));" ); |
1021 | verifyFormat("int (^foo)(char, float);" ); |
1022 | verifyFormat("int (^foo[10])(char, float);" ); |
1023 | verifyFormat("int (^foo[kNumEntries])(char, float);" ); |
1024 | verifyFormat("int (^foo[kNumEntries + 10])(char, float);" ); |
1025 | verifyFormat("int (^foo[(kNumEntries + 10)])(char, float);" ); |
1026 | |
1027 | verifyFormat("int *p = ^int *() { //\n" |
1028 | " return nullptr;\n" |
1029 | "}();" ); |
1030 | |
1031 | verifyFormat("int * (^p)(void) = ^int *(void) { //\n" |
1032 | " return nullptr;\n" |
1033 | "};" ); |
1034 | |
1035 | // WebKit forces function braces onto a newline, but blocks should not. |
1036 | verifyFormat("int* p = ^int*() { //\n" |
1037 | " return nullptr;\n" |
1038 | "}();" , |
1039 | getWebKitStyle()); |
1040 | } |
1041 | |
1042 | TEST_F(FormatTestObjC, ObjCSnippets) { |
1043 | verifyFormat("@autoreleasepool {\n" |
1044 | " foo();\n" |
1045 | "}" ); |
1046 | verifyFormat("@class Foo, Bar;" ); |
1047 | verifyFormat("@compatibility_alias AliasName ExistingClass;" ); |
1048 | verifyFormat("@dynamic textColor;" ); |
1049 | verifyFormat("char *buf1 = @encode(int *);" ); |
1050 | verifyFormat("char *buf1 = @encode(typeof(4 * 5));" ); |
1051 | verifyFormat("char *buf1 = @encode(int **);" ); |
1052 | verifyFormat("Protocol *proto = @protocol(p1);" ); |
1053 | verifyFormat("SEL s = @selector(foo:);" ); |
1054 | verifyFormat("@synchronized(self) {\n" |
1055 | " f();\n" |
1056 | "}" ); |
1057 | |
1058 | verifyFormat("@import foo.bar;\n" |
1059 | "@import baz;" ); |
1060 | |
1061 | verifyFormat("@synthesize dropArrowPosition = dropArrowPosition_;" ); |
1062 | |
1063 | verifyFormat("@property(assign, nonatomic) CGFloat hoverAlpha;" ); |
1064 | verifyFormat("@property(assign, getter=isEditable) BOOL editable;" ); |
1065 | |
1066 | verifyFormat("extern UIWindow *MainWindow(void) " |
1067 | "NS_SWIFT_NAME(getter:MyHelper.mainWindow());" ); |
1068 | |
1069 | verifyFormat("extern UIWindow *MainWindow(void) " |
1070 | "CF_SWIFT_NAME(getter:MyHelper.mainWindow());" ); |
1071 | |
1072 | Style.ColumnLimit = 50; |
1073 | verifyFormat("@interface Foo\n" |
1074 | "- (void)doStuffWithFoo:(id)name\n" |
1075 | " bar:(id)bar\n" |
1076 | " baz:(id)baz\n" |
1077 | " NS_SWIFT_NAME(doStuff(withFoo:bar:baz:));\n" |
1078 | "@end" ); |
1079 | |
1080 | Style = getMozillaStyle(); |
1081 | verifyFormat("@property (assign, getter=isEditable) BOOL editable;" ); |
1082 | verifyFormat("@property BOOL editable;" ); |
1083 | |
1084 | Style = getWebKitStyle(); |
1085 | verifyFormat("@property (assign, getter=isEditable) BOOL editable;" ); |
1086 | verifyFormat("@property BOOL editable;" ); |
1087 | |
1088 | Style = getGoogleStyle(Language: FormatStyle::LK_ObjC); |
1089 | verifyFormat("@synthesize dropArrowPosition = dropArrowPosition_;" ); |
1090 | verifyFormat("@property(assign, getter=isEditable) BOOL editable;" ); |
1091 | } |
1092 | |
1093 | TEST_F(FormatTestObjC, ObjCForIn) { |
1094 | verifyFormat("- (void)test {\n" |
1095 | " for (NSString *n in arrayOfStrings) {\n" |
1096 | " foo(n);\n" |
1097 | " }\n" |
1098 | "}" ); |
1099 | verifyFormat("- (void)test {\n" |
1100 | " for (NSString *n in (__bridge NSArray *)arrayOfStrings) {\n" |
1101 | " foo(n);\n" |
1102 | " }\n" |
1103 | "}" ); |
1104 | verifyFormat("for (Foo *x in bar) {\n}" ); |
1105 | verifyFormat("for (Foo *x in [bar baz]) {\n}" ); |
1106 | verifyFormat("for (Foo *x in [bar baz:blech]) {\n}" ); |
1107 | verifyFormat("for (Foo *x in [bar baz:blech, 1, 2, 3, 0]) {\n}" ); |
1108 | verifyFormat("for (Foo *x in [bar baz:^{\n" |
1109 | " [uh oh];\n" |
1110 | " }]) {\n}" ); |
1111 | } |
1112 | |
1113 | TEST_F(FormatTestObjC, ObjCCxxKeywords) { |
1114 | verifyFormat("+ (instancetype)new {\n" |
1115 | " return nil;\n" |
1116 | "}" ); |
1117 | verifyFormat("+ (instancetype)myNew {\n" |
1118 | " return [self new];\n" |
1119 | "}" ); |
1120 | verifyFormat("SEL NewSelector(void) { return @selector(new); }" ); |
1121 | verifyFormat("SEL MacroSelector(void) { return MACRO(new); }" ); |
1122 | verifyFormat("+ (instancetype)delete {\n" |
1123 | " return nil;\n" |
1124 | "}" ); |
1125 | verifyFormat("+ (instancetype)myDelete {\n" |
1126 | " return [self delete];\n" |
1127 | "}" ); |
1128 | verifyFormat("SEL DeleteSelector(void) { return @selector(delete); }" ); |
1129 | verifyFormat("SEL MacroSelector(void) { return MACRO(delete); }" ); |
1130 | verifyFormat("MACRO(new:)" ); |
1131 | verifyFormat("MACRO(delete:)" ); |
1132 | verifyFormat("foo = @{MACRO(new:) : MACRO(delete:)}" ); |
1133 | verifyFormat("@implementation Foo\n" |
1134 | "// Testing\n" |
1135 | "- (Class)class {\n" |
1136 | "}\n" |
1137 | "- (void)foo {\n" |
1138 | "}\n" |
1139 | "@end" ); |
1140 | verifyFormat("@implementation Foo\n" |
1141 | "- (Class)class {\n" |
1142 | "}\n" |
1143 | "- (void)foo {\n" |
1144 | "}\n" |
1145 | "@end" ); |
1146 | verifyFormat("@implementation Foo\n" |
1147 | "+ (Class)class {\n" |
1148 | "}\n" |
1149 | "- (void)foo {\n" |
1150 | "}\n" |
1151 | "@end" ); |
1152 | verifyFormat("@implementation Foo\n" |
1153 | "- (Class)class:(Class)klass {\n" |
1154 | "}\n" |
1155 | "- (void)foo {\n" |
1156 | "}\n" |
1157 | "@end" ); |
1158 | verifyFormat("@implementation Foo\n" |
1159 | "+ (Class)class:(Class)klass {\n" |
1160 | "}\n" |
1161 | "- (void)foo {\n" |
1162 | "}\n" |
1163 | "@end" ); |
1164 | |
1165 | verifyFormat("@interface Foo\n" |
1166 | "// Testing\n" |
1167 | "- (Class)class;\n" |
1168 | "- (void)foo;\n" |
1169 | "@end" ); |
1170 | verifyFormat("@interface Foo\n" |
1171 | "- (Class)class;\n" |
1172 | "- (void)foo;\n" |
1173 | "@end" ); |
1174 | verifyFormat("@interface Foo\n" |
1175 | "+ (Class)class;\n" |
1176 | "- (void)foo;\n" |
1177 | "@end" ); |
1178 | verifyFormat("@interface Foo\n" |
1179 | "- (Class)class:(Class)klass;\n" |
1180 | "- (void)foo;\n" |
1181 | "@end" ); |
1182 | verifyFormat("@interface Foo\n" |
1183 | "+ (Class)class:(Class)klass;\n" |
1184 | "- (void)foo;\n" |
1185 | "@end" ); |
1186 | } |
1187 | |
1188 | TEST_F(FormatTestObjC, ObjCLiterals) { |
1189 | verifyFormat("@\"String\"" ); |
1190 | verifyFormat("@1" ); |
1191 | verifyFormat("@+4.8" ); |
1192 | verifyFormat("@-4" ); |
1193 | verifyFormat("@1LL" ); |
1194 | verifyFormat("@.5" ); |
1195 | verifyFormat("@'c'" ); |
1196 | verifyFormat("@true" ); |
1197 | |
1198 | verifyFormat("NSNumber *smallestInt = @(-INT_MAX - 1);" ); |
1199 | verifyFormat("NSNumber *piOverTwo = @(M_PI / 2);" ); |
1200 | verifyFormat("NSNumber *favoriteColor = @(Green);" ); |
1201 | verifyFormat("NSString *path = @(getenv(\"PATH\"));" ); |
1202 | |
1203 | verifyFormat("[dictionary setObject:@(1) forKey:@\"number\"];" ); |
1204 | } |
1205 | |
1206 | TEST_F(FormatTestObjC, ObjCDictLiterals) { |
1207 | verifyFormat("@{" ); |
1208 | verifyFormat("@{}" ); |
1209 | verifyFormat("@{@\"one\" : @1}" ); |
1210 | verifyFormat("return @{@\"one\" : @1;" ); |
1211 | verifyFormat("@{@\"one\" : @1}" ); |
1212 | |
1213 | verifyFormat("@{@\"one\" : @{@2 : @1}}" ); |
1214 | verifyFormat("@{\n" |
1215 | " @\"one\" : @{@2 : @1},\n" |
1216 | "}" ); |
1217 | |
1218 | verifyFormat("@{1 > 2 ? @\"one\" : @\"two\" : 1 > 2 ? @1 : @2}" ); |
1219 | verifyIncompleteFormat("[self setDict:@{}" ); |
1220 | verifyIncompleteFormat("[self setDict:@{@1 : @2}" ); |
1221 | verifyFormat("NSLog(@\"%@\", @{@1 : @2, @2 : @3}[@1]);" ); |
1222 | verifyFormat( |
1223 | "NSDictionary *masses = @{@\"H\" : @1.0078, @\"He\" : @4.0026};" ); |
1224 | verifyFormat( |
1225 | "NSDictionary *settings = @{AVEncoderKey : @(AVAudioQualityMax)};" ); |
1226 | |
1227 | verifyFormat("NSDictionary *d = @{\n" |
1228 | " @\"nam\" : NSUserNam(),\n" |
1229 | " @\"dte\" : [NSDate date],\n" |
1230 | " @\"processInfo\" : [NSProcessInfo processInfo]\n" |
1231 | "};" ); |
1232 | verifyFormat( |
1233 | "@{\n" |
1234 | " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee : " |
1235 | "regularFont,\n" |
1236 | "};" ); |
1237 | verifyFormat( |
1238 | "@{\n" |
1239 | " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee :\n" |
1240 | " reeeeeeeeeeeeeeeeeeeeeeeegularFont,\n" |
1241 | "};" ); |
1242 | |
1243 | // We should try to be robust in case someone forgets the "@". |
1244 | verifyFormat("NSDictionary *d = {\n" |
1245 | " @\"nam\" : NSUserNam(),\n" |
1246 | " @\"dte\" : [NSDate date],\n" |
1247 | " @\"processInfo\" : [NSProcessInfo processInfo]\n" |
1248 | "};" ); |
1249 | verifyFormat("NSMutableDictionary *dictionary =\n" |
1250 | " [NSMutableDictionary dictionaryWithDictionary:@{\n" |
1251 | " aaaaaaaaaaaaaaaaaaaaa : aaaaaaaaaaaaa,\n" |
1252 | " bbbbbbbbbbbbbbbbbb : bbbbb,\n" |
1253 | " cccccccccccccccc : ccccccccccccccc\n" |
1254 | " }];" ); |
1255 | |
1256 | // Ensure that casts before the key are kept on the same line as the key. |
1257 | verifyFormat( |
1258 | "NSDictionary *d = @{\n" |
1259 | " (aaaaaaaa id)aaaaaaaaa : (aaaaaaaa id)aaaaaaaaaaaaaaaaaaaaaaaa,\n" |
1260 | " (aaaaaaaa id)aaaaaaaaaaaaaa : (aaaaaaaa id)aaaaaaaaaaaaaa,\n" |
1261 | "};" ); |
1262 | Style.ColumnLimit = 40; |
1263 | verifyFormat("int Foo() {\n" |
1264 | " a12345 = @{a12345 : a12345};\n" |
1265 | "}" ); |
1266 | verifyFormat("int Foo() {\n" |
1267 | " a12345 = @{a12345 : @(a12345)};\n" |
1268 | "}" ); |
1269 | verifyFormat("int Foo() {\n" |
1270 | " a12345 = @{(Foo *)a12345 : @(a12345)};\n" |
1271 | "}" ); |
1272 | verifyFormat("int Foo() {\n" |
1273 | " a12345 = @{@(a12345) : a12345};\n" |
1274 | "}" ); |
1275 | verifyFormat("int Foo() {\n" |
1276 | " a12345 = @{@(a12345) : @YES};\n" |
1277 | "}" ); |
1278 | Style.SpacesInContainerLiterals = false; |
1279 | verifyFormat("int Foo() {\n" |
1280 | " b12345 = @{b12345: b12345};\n" |
1281 | "}" ); |
1282 | verifyFormat("int Foo() {\n" |
1283 | " b12345 = @{(Foo *)b12345: @(b12345)};\n" |
1284 | "}" ); |
1285 | Style.SpacesInContainerLiterals = true; |
1286 | |
1287 | Style = getGoogleStyle(Language: FormatStyle::LK_ObjC); |
1288 | verifyFormat( |
1289 | "@{\n" |
1290 | " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee : " |
1291 | "regularFont,\n" |
1292 | "};" ); |
1293 | } |
1294 | |
1295 | TEST_F(FormatTestObjC, ObjCArrayLiterals) { |
1296 | verifyIncompleteFormat("@[" ); |
1297 | verifyFormat("@[]" ); |
1298 | verifyFormat( |
1299 | "NSArray *array = @[ @\" Hey \", NSApp, [NSNumber numberWithInt:42] ];" ); |
1300 | verifyFormat("return @[ @3, @[], @[ @4, @5 ] ];" ); |
1301 | verifyFormat("NSArray *array = @[ [foo description] ];" ); |
1302 | |
1303 | verifyFormat( |
1304 | "NSArray *some_variable = @[\n" |
1305 | " aaaa == bbbbbbbbbbb ? @\"aaaaaaaaaaaa\" : @\"aaaaaaaaaaaaaa\",\n" |
1306 | " @\"aaaaaaaaaaaaaaaaa\",\n" |
1307 | " @\"aaaaaaaaaaaaaaaaa\",\n" |
1308 | " @\"aaaaaaaaaaaaaaaaa\",\n" |
1309 | "];" ); |
1310 | verifyFormat( |
1311 | "NSArray *some_variable = @[\n" |
1312 | " aaaa == bbbbbbbbbbb ? @\"aaaaaaaaaaaa\" : @\"aaaaaaaaaaaaaa\",\n" |
1313 | " @\"aaaaaaaaaaaaaaaa\", @\"aaaaaaaaaaaaaaaa\", @\"aaaaaaaaaaaaaaaa\"\n" |
1314 | "];" ); |
1315 | verifyFormat("NSArray *some_variable = @[\n" |
1316 | " @\"aaaaaaaaaaaaaaaaa\",\n" |
1317 | " @\"aaaaaaaaaaaaaaaaa\",\n" |
1318 | " @\"aaaaaaaaaaaaaaaaa\",\n" |
1319 | " @\"aaaaaaaaaaaaaaaaa\",\n" |
1320 | "];" ); |
1321 | verifyFormat("NSArray *array = @[\n" |
1322 | " @\"a\",\n" |
1323 | " @\"a\",\n" // Trailing comma -> one per line. |
1324 | "];" ); |
1325 | |
1326 | // We should try to be robust in case someone forgets the "@". |
1327 | verifyFormat("NSArray *some_variable = [\n" |
1328 | " @\"aaaaaaaaaaaaaaaaa\",\n" |
1329 | " @\"aaaaaaaaaaaaaaaaa\",\n" |
1330 | " @\"aaaaaaaaaaaaaaaaa\",\n" |
1331 | " @\"aaaaaaaaaaaaaaaaa\",\n" |
1332 | "];" ); |
1333 | verifyFormat( |
1334 | "- (NSAttributedString *)attributedStringForSegment:(NSUInteger)segment\n" |
1335 | " index:(NSUInteger)index\n" |
1336 | " nonDigitAttributes:\n" |
1337 | " (NSDictionary *)noDigitAttributes;" ); |
1338 | verifyFormat("[someFunction someLooooooooooooongParameter:@[\n" |
1339 | " NSBundle.mainBundle.infoDictionary[@\"a\"]\n" |
1340 | "]];" ); |
1341 | Style.ColumnLimit = 40; |
1342 | verifyFormat("int Foo() {\n" |
1343 | " a12345 = @[ a12345, a12345 ];\n" |
1344 | "}" ); |
1345 | verifyFormat("int Foo() {\n" |
1346 | " a123 = @[ (Foo *)a12345, @(a12345) ];\n" |
1347 | "}" ); |
1348 | Style.SpacesInContainerLiterals = false; |
1349 | verifyFormat("int Foo() {\n" |
1350 | " b12345 = @[b12345, b12345];\n" |
1351 | "}" ); |
1352 | verifyFormat("int Foo() {\n" |
1353 | " b12345 = @[(Foo *)b12345, @(b12345)];\n" |
1354 | "}" ); |
1355 | Style.SpacesInContainerLiterals = true; |
1356 | Style.ColumnLimit = 20; |
1357 | // We can't break string literals inside NSArray literals |
1358 | // (that raises -Wobjc-string-concatenation). |
1359 | verifyFormat("NSArray *foo = @[\n" |
1360 | " @\"aaaaaaaaaaaaaaaaaaaaaaaaaa\"\n" |
1361 | "];" ); |
1362 | } |
1363 | |
1364 | TEST_F(FormatTestObjC, BreaksCallStatementWhereSemiJustOverTheLimit) { |
1365 | Style.ColumnLimit = 60; |
1366 | // If the statement starting with 'a = ...' is put on a single line, the ';' |
1367 | // is at line 61. |
1368 | verifyFormat("int f(int a) {\n" |
1369 | " a = [self aaaaaaaaaa:bbbbbbbbb\n" |
1370 | " ccccccccc:dddddddd\n" |
1371 | " ee:fddd];\n" |
1372 | "}" ); |
1373 | } |
1374 | |
1375 | TEST_F(FormatTestObjC, AlwaysBreakBeforeMultilineStrings) { |
1376 | Style = getGoogleStyle(Language: FormatStyle::LK_ObjC); |
1377 | Style.ColumnLimit = 40; |
1378 | verifyFormat("aaaa = @\"bbbb\"\n" |
1379 | " @\"cccc\";" ); |
1380 | verifyFormat("aaaa(@\"bbbb\"\n" |
1381 | " @\"cccc\");" ); |
1382 | verifyFormat("aaaa(qqq, @\"bbbb\"\n" |
1383 | " @\"cccc\");" ); |
1384 | verifyFormat("[aaaa qqqq:@\"bbbb\"\n" |
1385 | " @\"cccc\"];" ); |
1386 | verifyFormat("aaaa = [aaaa qqqq:@\"bbbb\"\n" |
1387 | " @\"cccc\"];" ); |
1388 | verifyFormat("[aaaa qqqq:@\"bbbb\"\n" |
1389 | " @\"cccc\"\n" |
1390 | " rr:42\n" |
1391 | " ssssss:@\"ee\"\n" |
1392 | " @\"fffff\"];" ); |
1393 | } |
1394 | |
1395 | TEST_F(FormatTestObjC, DisambiguatesCallsFromCppLambdas) { |
1396 | verifyFormat("x = ([a foo:bar] && b->c == 'd');" ); |
1397 | verifyFormat("x = ([a foo:bar] + b->c == 'd');" ); |
1398 | verifyFormat("x = ([a foo:bar] + !b->c == 'd');" ); |
1399 | verifyFormat("x = ([a foo:bar] + ~b->c == 'd');" ); |
1400 | verifyFormat("x = ([a foo:bar] - b->c == 'd');" ); |
1401 | verifyFormat("x = ([a foo:bar] / b->c == 'd');" ); |
1402 | verifyFormat("x = ([a foo:bar] % b->c == 'd');" ); |
1403 | verifyFormat("x = ([a foo:bar] | b->c == 'd');" ); |
1404 | verifyFormat("x = ([a foo:bar] || b->c == 'd');" ); |
1405 | verifyFormat("x = ([a foo:bar] && b->c == 'd');" ); |
1406 | verifyFormat("x = ([a foo:bar] == b->c == 'd');" ); |
1407 | verifyFormat("x = ([a foo:bar] != b->c == 'd');" ); |
1408 | verifyFormat("x = ([a foo:bar] <= b->c == 'd');" ); |
1409 | verifyFormat("x = ([a foo:bar] >= b->c == 'd');" ); |
1410 | verifyFormat("x = ([a foo:bar] << b->c == 'd');" ); |
1411 | verifyFormat("x = ([a foo:bar] ? b->c == 'd' : 'e');" ); |
1412 | // FIXME: The following are wrongly classified as C++ lambda expressions. |
1413 | // For example this code: |
1414 | // x = ([a foo:bar] & b->c == 'd'); |
1415 | // is formatted as: |
1416 | // x = ([a foo:bar] & b -> c == 'd'); |
1417 | // verifyFormat("x = ([a foo:bar] & b->c == 'd');"); |
1418 | // verifyFormat("x = ([a foo:bar] > b->c == 'd');"); |
1419 | // verifyFormat("x = ([a foo:bar] < b->c == 'd');"); |
1420 | // verifyFormat("x = ([a foo:bar] >> b->c == 'd');"); |
1421 | } |
1422 | |
1423 | TEST_F(FormatTestObjC, DisambiguatesCallsFromStructuredBindings) { |
1424 | verifyFormat("int f() {\n" |
1425 | " if (a && [f arg])\n" |
1426 | " return 0;\n" |
1427 | "}" ); |
1428 | verifyFormat("int f() {\n" |
1429 | " if (a & [f arg])\n" |
1430 | " return 0;\n" |
1431 | "}" ); |
1432 | verifyFormat("int f() {\n" |
1433 | " for (auto &[elem] : list)\n" |
1434 | " return 0;\n" |
1435 | "}" ); |
1436 | verifyFormat("int f() {\n" |
1437 | " for (auto &&[elem] : list)\n" |
1438 | " return 0;\n" |
1439 | "}" ); |
1440 | verifyFormat( |
1441 | "int f() {\n" |
1442 | " for (auto /**/ const /**/ volatile /**/ && /**/ [elem] : list)\n" |
1443 | " return 0;\n" |
1444 | "}" ); |
1445 | } |
1446 | |
1447 | TEST_F(FormatTestObjC, BreakLineBeforeNestedBlockParam) { |
1448 | Style = getGoogleStyle(Language: FormatStyle::LK_ObjC); |
1449 | Style.ObjCBreakBeforeNestedBlockParam = false; |
1450 | Style.ColumnLimit = 0; |
1451 | |
1452 | verifyFormat("[self.test1 t:self callback:^(typeof(self) self, NSNumber *u, " |
1453 | "NSNumber *v) {\n" |
1454 | " u = v;\n" |
1455 | "}]" ); |
1456 | |
1457 | verifyFormat("[self.test1 t:self w:self callback:^(typeof(self) self, " |
1458 | "NSNumber *u, NSNumber *v) {\n" |
1459 | " u = v;\n" |
1460 | "}]" ); |
1461 | |
1462 | verifyFormat("[self.test1 t:self w:self callback:^(typeof(self) self, " |
1463 | "NSNumber *u, NSNumber *v) {\n" |
1464 | " u = c;\n" |
1465 | "} w:self callback2:^(typeof(self) self, NSNumber *a, NSNumber " |
1466 | "*b, NSNumber *c) {\n" |
1467 | " b = c;\n" |
1468 | "}]" ); |
1469 | verifyFormat("[self.test1 t:self w:self callback:^(typeof(self) self, " |
1470 | "NSNumber *u, NSNumber *v) {\n" |
1471 | " u = v;\n" |
1472 | "} z:self]" ); |
1473 | |
1474 | Style.ColumnLimit = 80; |
1475 | verifyFormat( |
1476 | "[self.test_method a:self b:self\n" |
1477 | " callback:^(typeof(self) self, NSNumber *u, NSNumber *v) {\n" |
1478 | " u = v;\n" |
1479 | " }]" ); |
1480 | |
1481 | verifyFormat("[self block:^(void) {\n" |
1482 | " doStuff();\n" |
1483 | "} completionHandler:^(void) {\n" |
1484 | " doStuff();\n" |
1485 | " [self block:^(void) {\n" |
1486 | " doStuff();\n" |
1487 | " } completionHandler:^(void) {\n" |
1488 | " doStuff();\n" |
1489 | " }];\n" |
1490 | "}];" ); |
1491 | |
1492 | Style.ColumnLimit = 0; |
1493 | verifyFormat("[[SessionService sharedService] " |
1494 | "loadWindowWithCompletionBlock:^(SessionWindow *window) {\n" |
1495 | " if (window) {\n" |
1496 | " [self windowDidLoad:window];\n" |
1497 | " } else {\n" |
1498 | " [self errorLoadingWindow];\n" |
1499 | " }\n" |
1500 | "}];" ); |
1501 | verifyFormat("[controller test:^{\n" |
1502 | " doStuff();\n" |
1503 | "} withTimeout:5 completionHandler:^{\n" |
1504 | " doStuff();\n" |
1505 | "}];" ); |
1506 | verifyFormat( |
1507 | "[self setupTextFieldSignals:@[\n" |
1508 | " self.documentWidthField,\n" |
1509 | " self.documentHeightField,\n" |
1510 | "] solver:^(NSTextField *textField) {\n" |
1511 | " return [self.representedObject solveEquationForTextField:textField];\n" |
1512 | "}];" ); |
1513 | } |
1514 | |
1515 | TEST_F(FormatTestObjC, IfNotUnlikely) { |
1516 | Style = getGoogleStyle(Language: FormatStyle::LK_ObjC); |
1517 | |
1518 | verifyFormat("if (argc < 5) [obj func:arg];" ); |
1519 | verifyFormat("if (argc < 5) [[obj1 method1:arg1] method2:arg2];" ); |
1520 | verifyFormat("if (argc < 5) [[foo bar] baz:i[0]];" ); |
1521 | verifyFormat("if (argc < 5) [[foo bar] baz:i[0]][1];" ); |
1522 | |
1523 | verifyFormat("if (argc < 5)\n" |
1524 | " [obj func:arg];\n" |
1525 | "else\n" |
1526 | " [obj func:arg2];" ); |
1527 | |
1528 | verifyFormat("if (argc < 5) [[unlikely]]\n" |
1529 | " [obj func:arg];\n" |
1530 | "else [[likely]]\n" |
1531 | " [obj func:arg2];" ); |
1532 | } |
1533 | |
1534 | TEST_F(FormatTestObjC, AttributesOnObjCDecl) { |
1535 | Style.AttributeMacros.push_back(x: "ATTRIBUTE_MACRO" ); |
1536 | |
1537 | // Check '__attribute__' macro directly. |
1538 | verifyFormat("__attribute__((objc_subclassing_restricted))\n" |
1539 | "@interface Foo\n" |
1540 | "@end" ); |
1541 | verifyFormat("__attribute__((objc_subclassing_restricted))\n" |
1542 | "@protocol Foo\n" |
1543 | "@end" ); |
1544 | verifyFormat("__attribute__((objc_subclassing_restricted))\n" |
1545 | "@implementation Foo\n" |
1546 | "@end" ); |
1547 | |
1548 | // Check AttributeMacro gets treated the same, with or without parentheses. |
1549 | verifyFormat("ATTRIBUTE_MACRO\n" |
1550 | "@interface Foo\n" |
1551 | "@end" ); |
1552 | verifyFormat("ATTRIBUTE_MACRO(X)\n" |
1553 | "@interface Foo\n" |
1554 | "@end" ); |
1555 | |
1556 | // Indenter also needs to understand multiple attribute macros. |
1557 | // Try each of the three kinds paired with each of the other kind. |
1558 | |
1559 | // Column limit, but no reflow. |
1560 | verifyFormat("ATTRIBUTE_MACRO(X) ATTRIBUTE_MACRO\n" |
1561 | "@interface Foo\n" |
1562 | "@end" ); |
1563 | verifyFormat("ATTRIBUTE_MACRO ATTRIBUTE_MACRO(X)\n" |
1564 | "@interface Foo\n" |
1565 | "@end" ); |
1566 | verifyFormat("__attribute__((X)) ATTRIBUTE_MACRO\n" |
1567 | "@interface Foo\n" |
1568 | "@end" ); |
1569 | verifyFormat("ATTRIBUTE_MACRO __attribute__((X))\n" |
1570 | "@interface Foo\n" |
1571 | "@end" ); |
1572 | verifyFormat("__attribute__((X)) ATTRIBUTE_MACRO(X)\n" |
1573 | "@interface Foo\n" |
1574 | "@end" ); |
1575 | verifyFormat("ATTRIBUTE_MACRO(X) __attribute__((X))\n" |
1576 | "@interface Foo\n" |
1577 | "@end" ); |
1578 | |
1579 | // Column limit that requires reflow. |
1580 | Style.ColumnLimit = 30; |
1581 | verifyFormat("ATTRIBUTE_MACRO(X)\n" |
1582 | "ATTRIBUTE_MACRO\n" |
1583 | "@interface Foo\n" |
1584 | "@end" ); |
1585 | verifyFormat("ATTRIBUTE_MACRO\n" |
1586 | "ATTRIBUTE_MACRO(X)\n" |
1587 | "@interface Foo\n" |
1588 | "@end" ); |
1589 | verifyFormat("__attribute__((X))\n" |
1590 | "ATTRIBUTE_MACRO\n" |
1591 | "@interface Foo\n" |
1592 | "@end" ); |
1593 | verifyFormat("ATTRIBUTE_MACRO\n" |
1594 | "__attribute__((X))\n" |
1595 | "@interface Foo\n" |
1596 | "@end" ); |
1597 | verifyFormat("__attribute__((X))\n" |
1598 | "ATTRIBUTE_MACRO(X)\n" |
1599 | "@interface Foo\n" |
1600 | "@end" ); |
1601 | verifyFormat("ATTRIBUTE_MACRO(X)\n" |
1602 | "__attribute__((X))\n" |
1603 | "@interface Foo\n" |
1604 | "@end" ); |
1605 | |
1606 | // No column limit |
1607 | Style.ColumnLimit = 0; |
1608 | verifyFormat("ATTRIBUTE_MACRO(X) ATTRIBUTE_MACRO\n" |
1609 | "@interface Foo\n" |
1610 | "@end" ); |
1611 | verifyFormat("ATTRIBUTE_MACRO ATTRIBUTE_MACRO(X)\n" |
1612 | "@interface Foo\n" |
1613 | "@end" ); |
1614 | verifyFormat("__attribute__((X)) ATTRIBUTE_MACRO\n" |
1615 | "@interface Foo\n" |
1616 | "@end" ); |
1617 | verifyFormat("ATTRIBUTE_MACRO __attribute__((X))\n" |
1618 | "@interface Foo\n" |
1619 | "@end" ); |
1620 | verifyFormat("__attribute__((X)) ATTRIBUTE_MACRO(X)\n" |
1621 | "@interface Foo\n" |
1622 | "@end" ); |
1623 | verifyFormat("ATTRIBUTE_MACRO(X) __attribute__((X))\n" |
1624 | "@interface Foo\n" |
1625 | "@end" ); |
1626 | } |
1627 | |
1628 | TEST_F(FormatTestObjC, AttributesOnObjCMethodDecl) { |
1629 | Style.AttributeMacros.push_back(x: "ATTRIBUTE_MACRO" ); |
1630 | |
1631 | // Check '__attribute__' macro directly. |
1632 | verifyFormat("- (id)init __attribute__((objc_designated_initializer));" ); |
1633 | |
1634 | // Check AttributeMacro gets treated the same, with or without parentheses. |
1635 | verifyFormat("- (id)init ATTRIBUTE_MACRO;" ); |
1636 | verifyFormat("- (id)init ATTRIBUTE_MACRO(X);" ); |
1637 | |
1638 | // Indenter also needs to understand multiple attribute macros. |
1639 | |
1640 | // Column limit (default), but no reflow. |
1641 | verifyFormat("- (id)init ATTRIBUTE_MACRO(X) ATTRIBUTE_MACRO;" ); |
1642 | verifyFormat("- (id)init ATTRIBUTE_MACRO ATTRIBUTE_MACRO(X);" ); |
1643 | verifyFormat("- (id)init __attribute__((X)) ATTRIBUTE_MACRO;" ); |
1644 | verifyFormat("- (id)init ATTRIBUTE_MACRO __attribute__((X));" ); |
1645 | verifyFormat("- (id)init __attribute__((X)) ATTRIBUTE_MACRO(X);" ); |
1646 | verifyFormat("- (id)init ATTRIBUTE_MACRO(X) __attribute__((X));" ); |
1647 | |
1648 | // Column limit that requires reflow. |
1649 | Style.ColumnLimit = 30; |
1650 | |
1651 | // Reflow after method name. |
1652 | verifyFormat("- (id)initWithReallyLongName\n" |
1653 | " __attribute__((X))\n" |
1654 | " ATTRIBUTE_MACRO;" ); |
1655 | verifyFormat("- (id)initWithReallyLongName\n" |
1656 | " ATTRIBUTE_MACRO(X)\n" |
1657 | " ATTRIBUTE_MACRO;" ); |
1658 | verifyFormat("- (id)initWithReallyLongName\n" |
1659 | " ATTRIBUTE_MACRO\n" |
1660 | " ATTRIBUTE_MACRO;" ); |
1661 | // Reflow after first macro. |
1662 | // FIXME: these should indent but don't. |
1663 | #if 0 |
1664 | verifyFormat("- (id)init ATTRIBUTE_MACRO(X)\n" |
1665 | " ATTRIBUTE_MACRO;" ); |
1666 | verifyFormat("- (id)init ATTRIBUTE_MACRO\n" |
1667 | " ATTRIBUTE_MACRO(X);" ); |
1668 | verifyFormat("- (id)init __attribute__((X))\n" |
1669 | " ATTRIBUTE_MACRO;" ); |
1670 | verifyFormat("- (id)init ATTRIBUTE_MACRO\n" |
1671 | " __attribute__((X));" ); |
1672 | verifyFormat("- (id)init __attribute__((X))\n" |
1673 | " ATTRIBUTE_MACRO(X);" ); |
1674 | verifyFormat("- (id)init ATTRIBUTE_MACRO(X)\n" |
1675 | " __attribute__((X));" ); |
1676 | #endif |
1677 | |
1678 | // No column limit. |
1679 | Style.ColumnLimit = 0; |
1680 | verifyFormat("- (id)init ATTRIBUTE_MACRO(X) ATTRIBUTE_MACRO;" ); |
1681 | verifyFormat("- (id)init ATTRIBUTE_MACRO ATTRIBUTE_MACRO(X);" ); |
1682 | verifyFormat("- (id)init __attribute__((X)) ATTRIBUTE_MACRO;" ); |
1683 | verifyFormat("- (id)init ATTRIBUTE_MACRO __attribute__((X));" ); |
1684 | verifyFormat("- (id)init __attribute__((X)) ATTRIBUTE_MACRO(X);" ); |
1685 | verifyFormat("- (id)init ATTRIBUTE_MACRO(X) __attribute__((X));" ); |
1686 | } |
1687 | |
1688 | TEST_F(FormatTestObjC, AttributesOnObjCProperty) { |
1689 | Style.AttributeMacros.push_back(x: "ATTRIBUTE_MACRO" ); |
1690 | |
1691 | // Check '__attribute__' macro directly. |
1692 | verifyFormat("@property(weak) id delegate " |
1693 | "__attribute__((objc_designated_initializer));" ); |
1694 | |
1695 | // Check AttributeMacro gets treated the same, with or without parentheses. |
1696 | verifyFormat("@property(weak) id delegate ATTRIBUTE_MACRO;" ); |
1697 | verifyFormat("@property(weak) id delegate ATTRIBUTE_MACRO(X);" ); |
1698 | |
1699 | // Indenter also needs to understand multiple attribute macros. |
1700 | |
1701 | // Column limit (default), but no reflow. |
1702 | verifyFormat( |
1703 | "@property(weak) id delegate ATTRIBUTE_MACRO(X) ATTRIBUTE_MACRO;" ); |
1704 | verifyFormat( |
1705 | "@property(weak) id delegate ATTRIBUTE_MACRO ATTRIBUTE_MACRO(X);" ); |
1706 | verifyFormat( |
1707 | "@property(weak) id delegate __attribute__((X)) ATTRIBUTE_MACRO;" ); |
1708 | verifyFormat( |
1709 | "@property(weak) id delegate ATTRIBUTE_MACRO __attribute__((X));" ); |
1710 | verifyFormat( |
1711 | "@property(weak) id delegate __attribute__((X)) ATTRIBUTE_MACRO(X);" ); |
1712 | verifyFormat( |
1713 | "@property(weak) id delegate ATTRIBUTE_MACRO(X) __attribute__((X));" ); |
1714 | |
1715 | // Column limit that requires reflow. |
1716 | Style.ColumnLimit = 50; |
1717 | |
1718 | // Reflow after method name. |
1719 | verifyFormat("@property(weak) id delegateWithLongName\n" |
1720 | " __attribute__((X)) ATTRIBUTE_MACRO;" ); |
1721 | verifyFormat("@property(weak) id delegateWithLongName\n" |
1722 | " ATTRIBUTE_MACRO(X) ATTRIBUTE_MACRO;" ); |
1723 | verifyFormat("@property(weak) id delegateWithLongName\n" |
1724 | " ATTRIBUTE_MACRO ATTRIBUTE_MACRO;" ); |
1725 | // Reflow after first macro. |
1726 | // FIXME: these should indent but don't. |
1727 | #if 0 |
1728 | verifyFormat("@property(weak) id delegate ATTRIBUTE_MACRO(X)\n" |
1729 | " ATTRIBUTE_MACRO;" ); |
1730 | verifyFormat("@property(weak) id delegate ATTRIBUTE_MACRO\n" |
1731 | " ATTRIBUTE_MACRO(X);" ); |
1732 | verifyFormat("@property(weak) id delegate __attribute__((X))\n" |
1733 | " ATTRIBUTE_MACRO;" ); |
1734 | verifyFormat("@property(weak) id delegate ATTRIBUTE_MACRO\n" |
1735 | " __attribute__((X));" ); |
1736 | verifyFormat("@property(weak) id delegate __attribute__((X))\n" |
1737 | " ATTRIBUTE_MACRO(X);" ); |
1738 | verifyFormat("@property(weak) id delegate ATTRIBUTE_MACRO(X)\n" |
1739 | " __attribute__((X));" ); |
1740 | #endif |
1741 | |
1742 | // No column limit. |
1743 | Style.ColumnLimit = 0; |
1744 | verifyFormat( |
1745 | "@property(weak) id delegate ATTRIBUTE_MACRO(X) ATTRIBUTE_MACRO;" ); |
1746 | verifyFormat( |
1747 | "@property(weak) id delegate ATTRIBUTE_MACRO ATTRIBUTE_MACRO(X);" ); |
1748 | verifyFormat( |
1749 | "@property(weak) id delegate __attribute__((X)) ATTRIBUTE_MACRO;" ); |
1750 | verifyFormat( |
1751 | "@property(weak) id delegate ATTRIBUTE_MACRO __attribute__((X));" ); |
1752 | verifyFormat( |
1753 | "@property(weak) id delegate __attribute__((X)) ATTRIBUTE_MACRO(X);" ); |
1754 | verifyFormat( |
1755 | "@property(weak) id delegate ATTRIBUTE_MACRO(X) __attribute__((X));" ); |
1756 | } |
1757 | |
1758 | } // end namespace |
1759 | } // namespace test |
1760 | } // end namespace format |
1761 | } // end namespace clang |
1762 | |