diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index d34ca2fee392..6c6458b33d85 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -465,6 +465,8 @@ struct FormatStyle { LK_Java, /// Should be used for JavaScript. LK_JavaScript, + /// Should be used for ObjC code. + LK_ObjC, /// Should be used for Protocol Buffers /// (https://developers.google.com/protocol-buffers/). LK_Proto, @@ -852,13 +854,16 @@ extern const char *StyleOptionHelpDescription; /// == "file". /// \param[in] FallbackStyle The name of a predefined style used to fallback to /// in case the style can't be determined from \p StyleName. +/// \param[in] Code The actual code to be formatted. Used to determine the +/// language if the filename isn't sufficient. /// \param[in] FS The underlying file system, in which the file resides. By /// default, the file system is the real file system. /// /// \returns FormatStyle as specified by ``StyleName``. If no style could be /// determined, the default is LLVM Style (see ``getLLVMStyle()``). FormatStyle getStyle(StringRef StyleName, StringRef FileName, - StringRef FallbackStyle, vfs::FileSystem *FS = nullptr); + StringRef FallbackStyle, StringRef Code = "", + vfs::FileSystem *FS = nullptr); // \brief Returns a string representation of ``Language``. inline StringRef getLanguageName(FormatStyle::LanguageKind Language) { diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 404e3a3b4ade..aa6f37bd199d 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -560,6 +560,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, // and we need to avoid bin packing there. bool NestedBlockSpecialCase = Style.Language != FormatStyle::LK_Cpp && + Style.Language != FormatStyle::LK_ObjC && Current.is(tok::r_brace) && State.Stack.size() > 1 && State.Stack[State.Stack.size() - 2].NestedBlockInlined; if (!NestedBlockSpecialCase) diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index bcea5ac411af..4879d1e818cd 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -52,6 +52,7 @@ template <> struct ScalarEnumerationTraits { IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp); IO.enumCase(Value, "Java", FormatStyle::LK_Java); IO.enumCase(Value, "JavaScript", FormatStyle::LK_JavaScript); + IO.enumCase(Value, "ObjC", FormatStyle::LK_ObjC); IO.enumCase(Value, "Proto", FormatStyle::LK_Proto); IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen); } @@ -623,6 +624,8 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { } else if (Language == FormatStyle::LK_Proto) { GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None; GoogleStyle.SpacesInContainerLiterals = false; + } else if (Language == FormatStyle::LK_ObjC) { + GoogleStyle.ColumnLimit = 100; } return GoogleStyle; @@ -1861,6 +1864,8 @@ static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) { return FormatStyle::LK_Java; if (FileName.endswith_lower(".js") || FileName.endswith_lower(".ts")) return FormatStyle::LK_JavaScript; // JavaScript or TypeScript. + if (FileName.endswith(".m") || FileName.endswith(".mm")) + return FormatStyle::LK_ObjC; if (FileName.endswith_lower(".proto") || FileName.endswith_lower(".protodevel")) return FormatStyle::LK_Proto; @@ -1870,12 +1875,21 @@ static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) { } FormatStyle getStyle(StringRef StyleName, StringRef FileName, - StringRef FallbackStyle, vfs::FileSystem *FS) { + StringRef FallbackStyle, StringRef Code, + vfs::FileSystem *FS) { if (!FS) { FS = vfs::getRealFileSystem().get(); } FormatStyle Style = getLLVMStyle(); Style.Language = getLanguageByFileName(FileName); + + // This is a very crude detection of whether a header contains ObjC code that + // should be improved over time and probably be done on tokens, not one the + // bare content of the file. + if (Style.Language == FormatStyle::LK_Cpp && FileName.endswith(".h") && + (Code.contains("\n- (") || Code.contains("\n+ ("))) + Style.Language = FormatStyle::LK_ObjC; + if (!getPredefinedStyle(FallbackStyle, Style.Language, &Style)) { llvm::errs() << "Invalid fallback style \"" << FallbackStyle << "\" using LLVM style\n"; diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index 2aa48e3f4913..46a32a917dd9 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -558,7 +558,8 @@ FormatToken *FormatTokenLexer::getNextToken() { Column = FormatTok->LastLineColumnWidth; } - if (Style.Language == FormatStyle::LK_Cpp) { + if (Style.Language == FormatStyle::LK_Cpp || + Style.Language == FormatStyle::LK_ObjC) { if (!(Tokens.size() > 0 && Tokens.back()->Tok.getIdentifierInfo() && Tokens.back()->Tok.getIdentifierInfo()->getPPKeywordID() == tok::pp_define) && diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 57f30276b364..4db0e937afc0 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -317,7 +317,8 @@ private: Contexts.back().InTemplateArgument); bool StartsObjCMethodExpr = - !CppArrayTemplates && Style.Language == FormatStyle::LK_Cpp && + !CppArrayTemplates && (Style.Language == FormatStyle::LK_Cpp || + Style.Language == FormatStyle::LK_ObjC) && Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) && CurrentToken->isNot(tok::l_brace) && (!Parent || @@ -433,7 +434,8 @@ private: FormatToken *Previous = CurrentToken->getPreviousNonComment(); if (((CurrentToken->is(tok::colon) && (!Contexts.back().ColonIsDictLiteral || - Style.Language != FormatStyle::LK_Cpp)) || + (Style.Language != FormatStyle::LK_Cpp && + Style.Language != FormatStyle::LK_ObjC))) || Style.Language == FormatStyle::LK_Proto) && (Previous->Tok.getIdentifierInfo() || Previous->is(tok::string_literal))) @@ -1174,6 +1176,7 @@ private: bool rParenEndsCast(const FormatToken &Tok) { // C-style casts are only used in C++ and Java. if (Style.Language != FormatStyle::LK_Cpp && + Style.Language != FormatStyle::LK_ObjC && Style.Language != FormatStyle::LK_Java) return false; diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index c09723928b79..6c50daf53834 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -249,7 +249,8 @@ static bool format(StringRef FileName) { if (fillRanges(Code.get(), Ranges)) return true; StringRef AssumedFileName = (FileName == "-") ? AssumeFileName : FileName; - FormatStyle FormatStyle = getStyle(Style, AssumedFileName, FallbackStyle); + FormatStyle FormatStyle = + getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer()); if (SortIncludes.getNumOccurrences() != 0) FormatStyle.SortIncludes = SortIncludes; unsigned CursorPosition = Cursor; diff --git a/clang/unittests/Format/CMakeLists.txt b/clang/unittests/Format/CMakeLists.txt index 240be6ead2a5..eb7756a0ba56 100644 --- a/clang/unittests/Format/CMakeLists.txt +++ b/clang/unittests/Format/CMakeLists.txt @@ -7,6 +7,7 @@ add_clang_unittest(FormatTests FormatTest.cpp FormatTestJava.cpp FormatTestJS.cpp + FormatTestObjC.cpp FormatTestProto.cpp FormatTestSelective.cpp SortImportsTestJS.cpp diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index e851bb2a5f5e..fe2d47042074 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -2493,42 +2493,6 @@ TEST_F(FormatTest, FormatTryCatchBraceStyles) { Style); } -TEST_F(FormatTest, FormatObjCTryCatch) { - verifyFormat("@try {\n" - " f();\n" - "} @catch (NSException e) {\n" - " @throw;\n" - "} @finally {\n" - " exit(42);\n" - "}"); - verifyFormat("DEBUG({\n" - " @try {\n" - " } @finally {\n" - " }\n" - "});\n"); -} - -TEST_F(FormatTest, FormatObjCAutoreleasepool) { - FormatStyle Style = getLLVMStyle(); - verifyFormat("@autoreleasepool {\n" - " f();\n" - "}\n" - "@autoreleasepool {\n" - " f();\n" - "}\n", - Style); - Style.BreakBeforeBraces = FormatStyle::BS_Allman; - verifyFormat("@autoreleasepool\n" - "{\n" - " f();\n" - "}\n" - "@autoreleasepool\n" - "{\n" - " f();\n" - "}\n", - Style); -} - TEST_F(FormatTest, StaticInitializers) { verifyFormat("static SomeClass SC = {1, 'a'};"); @@ -7323,704 +7287,6 @@ TEST_F(FormatTest, FormatForObjectiveCMethodDecls) { verifyGoogleFormat("- foo:(int)foo;"); } -TEST_F(FormatTest, FormatObjCInterface) { - verifyFormat("@interface Foo : NSObject {\n" - "@public\n" - " int field1;\n" - "@protected\n" - " int field2;\n" - "@private\n" - " int field3;\n" - "@package\n" - " int field4;\n" - "}\n" - "+ (id)init;\n" - "@end"); - - verifyGoogleFormat("@interface Foo : NSObject {\n" - " @public\n" - " int field1;\n" - " @protected\n" - " int field2;\n" - " @private\n" - " int field3;\n" - " @package\n" - " int field4;\n" - "}\n" - "+ (id)init;\n" - "@end"); - - verifyFormat("@interface /* wait for it */ Foo\n" - "+ (id)init;\n" - "// Look, a comment!\n" - "- (int)answerWith:(int)i;\n" - "@end"); - - verifyFormat("@interface Foo\n" - "@end\n" - "@interface Bar\n" - "@end"); - - verifyFormat("@interface Foo : Bar\n" - "+ (id)init;\n" - "@end"); - - verifyFormat("@interface Foo : /**/ Bar /**/ \n" - "+ (id)init;\n" - "@end"); - - verifyGoogleFormat("@interface Foo : Bar\n" - "+ (id)init;\n" - "@end"); - - verifyFormat("@interface Foo (HackStuff)\n" - "+ (id)init;\n" - "@end"); - - verifyFormat("@interface Foo ()\n" - "+ (id)init;\n" - "@end"); - - verifyFormat("@interface Foo (HackStuff) \n" - "+ (id)init;\n" - "@end"); - - verifyGoogleFormat("@interface Foo (HackStuff)\n" - "+ (id)init;\n" - "@end"); - - verifyFormat("@interface Foo {\n" - " int _i;\n" - "}\n" - "+ (id)init;\n" - "@end"); - - verifyFormat("@interface Foo : Bar {\n" - " int _i;\n" - "}\n" - "+ (id)init;\n" - "@end"); - - verifyFormat("@interface Foo : Bar {\n" - " int _i;\n" - "}\n" - "+ (id)init;\n" - "@end"); - - verifyFormat("@interface Foo (HackStuff) {\n" - " int _i;\n" - "}\n" - "+ (id)init;\n" - "@end"); - - verifyFormat("@interface Foo () {\n" - " int _i;\n" - "}\n" - "+ (id)init;\n" - "@end"); - - verifyFormat("@interface Foo (HackStuff) {\n" - " int _i;\n" - "}\n" - "+ (id)init;\n" - "@end"); - - FormatStyle OnePerLine = getGoogleStyle(); - OnePerLine.BinPackParameters = false; - verifyFormat("@interface aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ()<\n" - " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" - " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" - " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" - " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> {\n" - "}", - OnePerLine); -} - -TEST_F(FormatTest, FormatObjCImplementation) { - verifyFormat("@implementation Foo : NSObject {\n" - "@public\n" - " int field1;\n" - "@protected\n" - " int field2;\n" - "@private\n" - " int field3;\n" - "@package\n" - " int field4;\n" - "}\n" - "+ (id)init {\n}\n" - "@end"); - - verifyGoogleFormat("@implementation Foo : NSObject {\n" - " @public\n" - " int field1;\n" - " @protected\n" - " int field2;\n" - " @private\n" - " int field3;\n" - " @package\n" - " int field4;\n" - "}\n" - "+ (id)init {\n}\n" - "@end"); - - verifyFormat("@implementation Foo\n" - "+ (id)init {\n" - " if (true)\n" - " return nil;\n" - "}\n" - "// Look, a comment!\n" - "- (int)answerWith:(int)i {\n" - " return i;\n" - "}\n" - "+ (int)answerWith:(int)i {\n" - " return i;\n" - "}\n" - "@end"); - - verifyFormat("@implementation Foo\n" - "@end\n" - "@implementation Bar\n" - "@end"); - - EXPECT_EQ("@implementation Foo : Bar\n" - "+ (id)init {\n}\n" - "- (void)foo {\n}\n" - "@end", - format("@implementation Foo : Bar\n" - "+(id)init{}\n" - "-(void)foo{}\n" - "@end")); - - verifyFormat("@implementation Foo {\n" - " int _i;\n" - "}\n" - "+ (id)init {\n}\n" - "@end"); - - verifyFormat("@implementation Foo : Bar {\n" - " int _i;\n" - "}\n" - "+ (id)init {\n}\n" - "@end"); - - verifyFormat("@implementation Foo (HackStuff)\n" - "+ (id)init {\n}\n" - "@end"); - verifyFormat("@implementation ObjcClass\n" - "- (void)method;\n" - "{}\n" - "@end"); -} - -TEST_F(FormatTest, FormatObjCProtocol) { - verifyFormat("@protocol Foo\n" - "@property(weak) id delegate;\n" - "- (NSUInteger)numberOfThings;\n" - "@end"); - - verifyFormat("@protocol MyProtocol \n" - "- (NSUInteger)numberOfThings;\n" - "@end"); - - verifyGoogleFormat("@protocol MyProtocol\n" - "- (NSUInteger)numberOfThings;\n" - "@end"); - - verifyFormat("@protocol Foo;\n" - "@protocol Bar;\n"); - - verifyFormat("@protocol Foo\n" - "@end\n" - "@protocol Bar\n" - "@end"); - - verifyFormat("@protocol myProtocol\n" - "- (void)mandatoryWithInt:(int)i;\n" - "@optional\n" - "- (void)optional;\n" - "@required\n" - "- (void)required;\n" - "@optional\n" - "@property(assign) int madProp;\n" - "@end\n"); - - verifyFormat("@property(nonatomic, assign, readonly)\n" - " int *looooooooooooooooooooooooooooongNumber;\n" - "@property(nonatomic, assign, readonly)\n" - " NSString *looooooooooooooooooooooooooooongName;"); - - verifyFormat("@implementation PR18406\n" - "}\n" - "@end"); -} - -TEST_F(FormatTest, FormatObjCMethodDeclarations) { - verifyFormat("- (void)doSomethingWith:(GTMFoo *)theFoo\n" - " rect:(NSRect)theRect\n" - " interval:(float)theInterval {\n" - "}"); - verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n" - " longKeyword:(NSRect)theRect\n" - " longerKeyword:(float)theInterval\n" - " error:(NSError **)theError {\n" - "}"); - verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n" - " longKeyword:(NSRect)theRect\n" - " evenLongerKeyword:(float)theInterval\n" - " error:(NSError **)theError {\n" - "}"); - verifyFormat("- (instancetype)initXxxxxx:(id)x\n" - " y:(id)y\n" - " NS_DESIGNATED_INITIALIZER;", - getLLVMStyleWithColumns(60)); - - // Continuation indent width should win over aligning colons if the function - // name is long. - FormatStyle continuationStyle = getGoogleStyle(); - continuationStyle.ColumnLimit = 40; - continuationStyle.IndentWrappedFunctionNames = true; - verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n" - " dontAlignNamef:(NSRect)theRect {\n" - "}", - continuationStyle); - - // Make sure we don't break aligning for short parameter names. - verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n" - " aShortf:(NSRect)theRect {\n" - "}", - continuationStyle); - - // Format pairs correctly. - verifyFormat("- (void)drawRectOn:(id)surface\n" - " ofSize:(aaaaaaaa)height\n" - " :(size_t)width\n" - " atOrigin:(size_t)x\n" - " :(size_t)y\n" - " aaaaa:(a)yyy\n" - " bbb:(d)cccc;"); - verifyFormat("- (void)drawRectOn:(id)surface ofSize:(aaa)height:(bbb)width;"); - verifyFormat("- (void)drawRectOn:(id)surface\n" - " ofSize:(size_t)height\n" - " :(size_t)width;", - getLLVMStyleWithColumns(60)); -} - -TEST_F(FormatTest, FormatObjCMethodExpr) { - verifyFormat("[foo bar:baz];"); - verifyFormat("return [foo bar:baz];"); - verifyFormat("return (a)[foo bar:baz];"); - verifyFormat("f([foo bar:baz]);"); - verifyFormat("f(2, [foo bar:baz]);"); - verifyFormat("f(2, a ? b : c);"); - verifyFormat("[[self initWithInt:4] bar:[baz quux:arrrr]];"); - - // Unary operators. - verifyFormat("int a = +[foo bar:baz];"); - verifyFormat("int a = -[foo bar:baz];"); - verifyFormat("int a = ![foo bar:baz];"); - verifyFormat("int a = ~[foo bar:baz];"); - verifyFormat("int a = ++[foo bar:baz];"); - verifyFormat("int a = --[foo bar:baz];"); - verifyFormat("int a = sizeof [foo bar:baz];"); - verifyFormat("int a = alignof [foo bar:baz];", getGoogleStyle()); - verifyFormat("int a = &[foo bar:baz];"); - verifyFormat("int a = *[foo bar:baz];"); - // FIXME: Make casts work, without breaking f()[4]. - // verifyFormat("int a = (int)[foo bar:baz];"); - // verifyFormat("return (int)[foo bar:baz];"); - // verifyFormat("(void)[foo bar:baz];"); - verifyFormat("return (MyType *)[self.tableView cellForRowAtIndexPath:cell];"); - - // Binary operators. - verifyFormat("[foo bar:baz], [foo bar:baz];"); - verifyFormat("[foo bar:baz] = [foo bar:baz];"); - verifyFormat("[foo bar:baz] *= [foo bar:baz];"); - verifyFormat("[foo bar:baz] /= [foo bar:baz];"); - verifyFormat("[foo bar:baz] %= [foo bar:baz];"); - verifyFormat("[foo bar:baz] += [foo bar:baz];"); - verifyFormat("[foo bar:baz] -= [foo bar:baz];"); - verifyFormat("[foo bar:baz] <<= [foo bar:baz];"); - verifyFormat("[foo bar:baz] >>= [foo bar:baz];"); - verifyFormat("[foo bar:baz] &= [foo bar:baz];"); - verifyFormat("[foo bar:baz] ^= [foo bar:baz];"); - verifyFormat("[foo bar:baz] |= [foo bar:baz];"); - verifyFormat("[foo bar:baz] ? [foo bar:baz] : [foo bar:baz];"); - verifyFormat("[foo bar:baz] || [foo bar:baz];"); - verifyFormat("[foo bar:baz] && [foo bar:baz];"); - verifyFormat("[foo bar:baz] | [foo bar:baz];"); - verifyFormat("[foo bar:baz] ^ [foo bar:baz];"); - verifyFormat("[foo bar:baz] & [foo bar:baz];"); - verifyFormat("[foo bar:baz] == [foo bar:baz];"); - verifyFormat("[foo bar:baz] != [foo bar:baz];"); - verifyFormat("[foo bar:baz] >= [foo bar:baz];"); - verifyFormat("[foo bar:baz] <= [foo bar:baz];"); - verifyFormat("[foo bar:baz] > [foo bar:baz];"); - verifyFormat("[foo bar:baz] < [foo bar:baz];"); - verifyFormat("[foo bar:baz] >> [foo bar:baz];"); - verifyFormat("[foo bar:baz] << [foo bar:baz];"); - verifyFormat("[foo bar:baz] - [foo bar:baz];"); - verifyFormat("[foo bar:baz] + [foo bar:baz];"); - verifyFormat("[foo bar:baz] * [foo bar:baz];"); - verifyFormat("[foo bar:baz] / [foo bar:baz];"); - verifyFormat("[foo bar:baz] % [foo bar:baz];"); - // Whew! - - verifyFormat("return in[42];"); - verifyFormat("for (auto v : in[1]) {\n}"); - verifyFormat("for (int i = 0; i < in[a]; ++i) {\n}"); - verifyFormat("for (int i = 0; in[a] < i; ++i) {\n}"); - verifyFormat("for (int i = 0; i < n; ++i, ++in[a]) {\n}"); - verifyFormat("for (int i = 0; i < n; ++i, in[a]++) {\n}"); - verifyFormat("for (int i = 0; i < f(in[a]); ++i, in[a]++) {\n}"); - verifyFormat("for (id foo in [self getStuffFor:bla]) {\n" - "}"); - verifyFormat("[self aaaaa:MACRO(a, b:, c:)];"); - verifyFormat("[self aaaaa:(1 + 2) bbbbb:3];"); - verifyFormat("[self aaaaa:(Type)a bbbbb:3];"); - - verifyFormat("[self stuffWithInt:(4 + 2) float:4.5];"); - verifyFormat("[self stuffWithInt:a ? b : c float:4.5];"); - verifyFormat("[self stuffWithInt:a ? [self foo:bar] : c];"); - verifyFormat("[self stuffWithInt:a ? (e ? f : g) : c];"); - verifyFormat("[cond ? obj1 : obj2 methodWithParam:param]"); - verifyFormat("[button setAction:@selector(zoomOut:)];"); - verifyFormat("[color getRed:&r green:&g blue:&b alpha:&a];"); - - verifyFormat("arr[[self indexForFoo:a]];"); - verifyFormat("throw [self errorFor:a];"); - verifyFormat("@throw [self errorFor:a];"); - - verifyFormat("[(id)foo bar:(id)baz quux:(id)snorf];"); - verifyFormat("[(id)foo bar:(id) ? baz : quux];"); - verifyFormat("4 > 4 ? (id)a : (id)baz;"); - - // This tests that the formatter doesn't break after "backing" but before ":", - // which would be at 80 columns. - verifyFormat( - "void f() {\n" - " if ((self = [super initWithContentRect:contentRect\n" - " styleMask:styleMask ?: otherMask\n" - " backing:NSBackingStoreBuffered\n" - " defer:YES]))"); - - verifyFormat( - "[foo checkThatBreakingAfterColonWorksOk:\n" - " [bar ifItDoes:reduceOverallLineLengthLikeInThisCase]];"); - - verifyFormat("[myObj short:arg1 // Force line break\n" - " longKeyword:arg2 != nil ? arg2 : @\"longKeyword\"\n" - " evenLongerKeyword:arg3 ?: @\"evenLongerKeyword\"\n" - " error:arg4];"); - verifyFormat( - "void f() {\n" - " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n" - " initWithContentRect:NSMakeRect(origin_global.x, origin_global.y,\n" - " pos.width(), pos.height())\n" - " styleMask:NSBorderlessWindowMask\n" - " backing:NSBackingStoreBuffered\n" - " defer:NO]);\n" - "}"); - verifyFormat( - "void f() {\n" - " popup_wdow_.reset([[RenderWidgetPopupWindow alloc]\n" - " iniithContentRect:NSMakRet(origin_global.x, origin_global.y,\n" - " pos.width(), pos.height())\n" - " syeMask:NSBorderlessWindowMask\n" - " bking:NSBackingStoreBuffered\n" - " der:NO]);\n" - "}", - getLLVMStyleWithColumns(70)); - verifyFormat( - "void f() {\n" - " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n" - " initWithContentRect:NSMakeRect(origin_global.x, origin_global.y,\n" - " pos.width(), pos.height())\n" - " styleMask:NSBorderlessWindowMask\n" - " backing:NSBackingStoreBuffered\n" - " defer:NO]);\n" - "}", - getChromiumStyle(FormatStyle::LK_Cpp)); - verifyFormat("[contentsContainer replaceSubview:[subviews objectAtIndex:0]\n" - " with:contentsNativeView];"); - - verifyFormat( - "[pboard addTypes:[NSArray arrayWithObject:kBookmarkButtonDragType]\n" - " owner:nillllll];"); - - verifyFormat( - "[pboard setData:[NSData dataWithBytes:&button length:sizeof(button)]\n" - " forType:kBookmarkButtonDragType];"); - - verifyFormat("[defaultCenter addObserver:self\n" - " selector:@selector(willEnterFullscreen)\n" - " name:kWillEnterFullscreenNotification\n" - " object:nil];"); - verifyFormat("[image_rep drawInRect:drawRect\n" - " fromRect:NSZeroRect\n" - " operation:NSCompositeCopy\n" - " fraction:1.0\n" - " respectFlipped:NO\n" - " hints:nil];"); - verifyFormat("[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" - " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];"); - verifyFormat("[aaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaa)\n" - " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];"); - verifyFormat("[aaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaa[aaaaaaaaaaaaaaaaaaaaa]\n" - " aaaaaaaaaaaaaaaaaaaaaa];"); - verifyFormat("[call aaaaaaaa.aaaaaa.aaaaaaaa.aaaaaaaa.aaaaaaaa.aaaaaaaa\n" - " .aaaaaaaa];", // FIXME: Indentation seems off. - getLLVMStyleWithColumns(60)); - - verifyFormat( - "scoped_nsobject message(\n" - " // The frame will be fixed up when |-setMessageText:| is called.\n" - " [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]);"); - verifyFormat("[self aaaaaa:bbbbbbbbbbbbb\n" - " aaaaaaaaaa:bbbbbbbbbbbbbbbbb\n" - " aaaaa:bbbbbbbbbbb + bbbbbbbbbbbb\n" - " aaaa:bbb];"); - verifyFormat("[self param:function( //\n" - " parameter)]"); - verifyFormat( - "[self aaaaaaaaaa:aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa |\n" - " aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa |\n" - " aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa];"); - - // FIXME: This violates the column limit. - verifyFormat( - "[aaaaaaaaaaaaaaaaaaaaaaaaa\n" - " aaaaaaaaaaaaaaaaa:aaaaaaaa\n" - " aaa:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];", - getLLVMStyleWithColumns(60)); - - // Variadic parameters. - verifyFormat( - "NSArray *myStrings = [NSArray stringarray:@\"a\", @\"b\", nil];"); - verifyFormat( - "[self aaaaaaaaaaaaa:aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa,\n" - " aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa,\n" - " aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa];"); - verifyFormat("[self // break\n" - " a:a\n" - " aaa:aaa];"); - verifyFormat("bool a = ([aaaaaaaa aaaaa] == aaaaaaaaaaaaaaaaa ||\n" - " [aaaaaaaa aaaaa] == aaaaaaaaaaaaaaaaaaaa);"); - - // Formats pair-parameters. - verifyFormat("[I drawRectOn:surface ofSize:aa:bbb atOrigin:cc:dd];"); - verifyFormat("[I drawRectOn:surface //\n" - " ofSize:aa:bbb\n" - " atOrigin:cc:dd];"); -} - -TEST_F(FormatTest, ObjCAt) { - verifyFormat("@autoreleasepool"); - verifyFormat("@catch"); - verifyFormat("@class"); - verifyFormat("@compatibility_alias"); - verifyFormat("@defs"); - verifyFormat("@dynamic"); - verifyFormat("@encode"); - verifyFormat("@end"); - verifyFormat("@finally"); - verifyFormat("@implementation"); - verifyFormat("@import"); - verifyFormat("@interface"); - verifyFormat("@optional"); - verifyFormat("@package"); - verifyFormat("@private"); - verifyFormat("@property"); - verifyFormat("@protected"); - verifyFormat("@protocol"); - verifyFormat("@public"); - verifyFormat("@required"); - verifyFormat("@selector"); - verifyFormat("@synchronized"); - verifyFormat("@synthesize"); - verifyFormat("@throw"); - verifyFormat("@try"); - - EXPECT_EQ("@interface", format("@ interface")); - - // The precise formatting of this doesn't matter, nobody writes code like - // this. - verifyFormat("@ /*foo*/ interface"); -} - -TEST_F(FormatTest, ObjCSnippets) { - verifyFormat("@autoreleasepool {\n" - " foo();\n" - "}"); - verifyFormat("@class Foo, Bar;"); - verifyFormat("@compatibility_alias AliasName ExistingClass;"); - verifyFormat("@dynamic textColor;"); - verifyFormat("char *buf1 = @encode(int *);"); - verifyFormat("char *buf1 = @encode(typeof(4 * 5));"); - verifyFormat("char *buf1 = @encode(int **);"); - verifyFormat("Protocol *proto = @protocol(p1);"); - verifyFormat("SEL s = @selector(foo:);"); - verifyFormat("@synchronized(self) {\n" - " f();\n" - "}"); - - verifyFormat("@synthesize dropArrowPosition = dropArrowPosition_;"); - verifyGoogleFormat("@synthesize dropArrowPosition = dropArrowPosition_;"); - - verifyFormat("@property(assign, nonatomic) CGFloat hoverAlpha;"); - verifyFormat("@property(assign, getter=isEditable) BOOL editable;"); - verifyGoogleFormat("@property(assign, getter=isEditable) BOOL editable;"); - verifyFormat("@property (assign, getter=isEditable) BOOL editable;", - getMozillaStyle()); - verifyFormat("@property BOOL editable;", getMozillaStyle()); - verifyFormat("@property (assign, getter=isEditable) BOOL editable;", - getWebKitStyle()); - verifyFormat("@property BOOL editable;", getWebKitStyle()); - - verifyFormat("@import foo.bar;\n" - "@import baz;"); -} - -TEST_F(FormatTest, ObjCForIn) { - verifyFormat("- (void)test {\n" - " for (NSString *n in arrayOfStrings) {\n" - " foo(n);\n" - " }\n" - "}"); - verifyFormat("- (void)test {\n" - " for (NSString *n in (__bridge NSArray *)arrayOfStrings) {\n" - " foo(n);\n" - " }\n" - "}"); -} - -TEST_F(FormatTest, ObjCLiterals) { - verifyFormat("@\"String\""); - verifyFormat("@1"); - verifyFormat("@+4.8"); - verifyFormat("@-4"); - verifyFormat("@1LL"); - verifyFormat("@.5"); - verifyFormat("@'c'"); - verifyFormat("@true"); - - verifyFormat("NSNumber *smallestInt = @(-INT_MAX - 1);"); - verifyFormat("NSNumber *piOverTwo = @(M_PI / 2);"); - verifyFormat("NSNumber *favoriteColor = @(Green);"); - verifyFormat("NSString *path = @(getenv(\"PATH\"));"); - - verifyFormat("[dictionary setObject:@(1) forKey:@\"number\"];"); -} - -TEST_F(FormatTest, ObjCDictLiterals) { - verifyFormat("@{"); - verifyFormat("@{}"); - verifyFormat("@{@\"one\" : @1}"); - verifyFormat("return @{@\"one\" : @1;"); - verifyFormat("@{@\"one\" : @1}"); - - verifyFormat("@{@\"one\" : @{@2 : @1}}"); - verifyFormat("@{\n" - " @\"one\" : @{@2 : @1},\n" - "}"); - - verifyFormat("@{1 > 2 ? @\"one\" : @\"two\" : 1 > 2 ? @1 : @2}"); - verifyIncompleteFormat("[self setDict:@{}"); - verifyIncompleteFormat("[self setDict:@{@1 : @2}"); - verifyFormat("NSLog(@\"%@\", @{@1 : @2, @2 : @3}[@1]);"); - verifyFormat( - "NSDictionary *masses = @{@\"H\" : @1.0078, @\"He\" : @4.0026};"); - verifyFormat( - "NSDictionary *settings = @{AVEncoderKey : @(AVAudioQualityMax)};"); - - verifyFormat("NSDictionary *d = @{\n" - " @\"nam\" : NSUserNam(),\n" - " @\"dte\" : [NSDate date],\n" - " @\"processInfo\" : [NSProcessInfo processInfo]\n" - "};"); - verifyFormat( - "@{\n" - " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee : " - "regularFont,\n" - "};"); - verifyGoogleFormat( - "@{\n" - " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee : " - "regularFont,\n" - "};"); - verifyFormat( - "@{\n" - " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee :\n" - " reeeeeeeeeeeeeeeeeeeeeeeegularFont,\n" - "};"); - - // We should try to be robust in case someone forgets the "@". - verifyFormat("NSDictionary *d = {\n" - " @\"nam\" : NSUserNam(),\n" - " @\"dte\" : [NSDate date],\n" - " @\"processInfo\" : [NSProcessInfo processInfo]\n" - "};"); - verifyFormat("NSMutableDictionary *dictionary =\n" - " [NSMutableDictionary dictionaryWithDictionary:@{\n" - " aaaaaaaaaaaaaaaaaaaaa : aaaaaaaaaaaaa,\n" - " bbbbbbbbbbbbbbbbbb : bbbbb,\n" - " cccccccccccccccc : ccccccccccccccc\n" - " }];"); - - // Ensure that casts before the key are kept on the same line as the key. - verifyFormat( - "NSDictionary *d = @{\n" - " (aaaaaaaa id)aaaaaaaaa : (aaaaaaaa id)aaaaaaaaaaaaaaaaaaaaaaaa,\n" - " (aaaaaaaa id)aaaaaaaaaaaaaa : (aaaaaaaa id)aaaaaaaaaaaaaa,\n" - "};"); -} - -TEST_F(FormatTest, ObjCArrayLiterals) { - verifyIncompleteFormat("@["); - verifyFormat("@[]"); - verifyFormat( - "NSArray *array = @[ @\" Hey \", NSApp, [NSNumber numberWithInt:42] ];"); - verifyFormat("return @[ @3, @[], @[ @4, @5 ] ];"); - verifyFormat("NSArray *array = @[ [foo description] ];"); - - verifyFormat( - "NSArray *some_variable = @[\n" - " aaaa == bbbbbbbbbbb ? @\"aaaaaaaaaaaa\" : @\"aaaaaaaaaaaaaa\",\n" - " @\"aaaaaaaaaaaaaaaaa\",\n" - " @\"aaaaaaaaaaaaaaaaa\",\n" - " @\"aaaaaaaaaaaaaaaaa\",\n" - "];"); - verifyFormat( - "NSArray *some_variable = @[\n" - " aaaa == bbbbbbbbbbb ? @\"aaaaaaaaaaaa\" : @\"aaaaaaaaaaaaaa\",\n" - " @\"aaaaaaaaaaaaaaaa\", @\"aaaaaaaaaaaaaaaa\", @\"aaaaaaaaaaaaaaaa\"\n" - "];"); - verifyFormat("NSArray *some_variable = @[\n" - " @\"aaaaaaaaaaaaaaaaa\",\n" - " @\"aaaaaaaaaaaaaaaaa\",\n" - " @\"aaaaaaaaaaaaaaaaa\",\n" - " @\"aaaaaaaaaaaaaaaaa\",\n" - "];"); - verifyFormat("NSArray *array = @[\n" - " @\"a\",\n" - " @\"a\",\n" // Trailing comma -> one per line. - "];"); - - // We should try to be robust in case someone forgets the "@". - verifyFormat("NSArray *some_variable = [\n" - " @\"aaaaaaaaaaaaaaaaa\",\n" - " @\"aaaaaaaaaaaaaaaaa\",\n" - " @\"aaaaaaaaaaaaaaaaa\",\n" - " @\"aaaaaaaaaaaaaaaaa\",\n" - "];"); - verifyFormat( - "- (NSAttributedString *)attributedStringForSegment:(NSUInteger)segment\n" - " index:(NSUInteger)index\n" - " nonDigitAttributes:\n" - " (NSDictionary *)noDigitAttributes;"); - verifyFormat("[someFunction someLooooooooooooongParameter:@[\n" - " NSBundle.mainBundle.infoDictionary[@\"a\"]\n" - "]];"); -} TEST_F(FormatTest, BreaksStringLiterals) { EXPECT_EQ("\"some text \"\n" @@ -11630,13 +10896,13 @@ TEST(FormatStyle, GetStyleOfFile) { llvm::MemoryBuffer::getMemBuffer("BasedOnStyle: LLVM"))); ASSERT_TRUE( FS.addFile("/a/test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int i;"))); - auto Style1 = getStyle("file", "/a/.clang-format", "Google", &FS); + auto Style1 = getStyle("file", "/a/.clang-format", "Google", "", &FS); ASSERT_EQ(Style1, getLLVMStyle()); // Test 2: fallback to default. ASSERT_TRUE( FS.addFile("/b/test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int i;"))); - auto Style2 = getStyle("file", "/b/test.cpp", "Mozilla", &FS); + auto Style2 = getStyle("file", "/b/test.cpp", "Mozilla", "", &FS); ASSERT_EQ(Style2, getMozillaStyle()); // Test 3: format file in parent directory. @@ -11645,7 +10911,7 @@ TEST(FormatStyle, GetStyleOfFile) { llvm::MemoryBuffer::getMemBuffer("BasedOnStyle: Google"))); ASSERT_TRUE(FS.addFile("/c/sub/sub/sub/test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int i;"))); - auto Style3 = getStyle("file", "/c/sub/sub/sub/test.cpp", "LLVM", &FS); + auto Style3 = getStyle("file", "/c/sub/sub/sub/test.cpp", "LLVM", "", &FS); ASSERT_EQ(Style3, getGoogleStyle()); } diff --git a/clang/unittests/Format/FormatTestObjC.cpp b/clang/unittests/Format/FormatTestObjC.cpp new file mode 100644 index 000000000000..6a530f921e6d --- /dev/null +++ b/clang/unittests/Format/FormatTestObjC.cpp @@ -0,0 +1,822 @@ +//===- unittest/Format/FormatTestObjC.cpp - Formatting unit tests----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Format/Format.h" + +#include "../Tooling/ReplacementTest.h" +#include "FormatTestUtils.h" + +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MemoryBuffer.h" +#include "gtest/gtest.h" + +#define DEBUG_TYPE "format-test" + +using clang::tooling::ReplacementTest; +using clang::tooling::toReplacements; + +namespace clang { +namespace format { +namespace { + +class FormatTestObjC : public ::testing::Test { +protected: + FormatTestObjC() { + Style = getLLVMStyle(); + Style.Language = FormatStyle::LK_ObjC; + } + + enum IncompleteCheck { + IC_ExpectComplete, + IC_ExpectIncomplete, + IC_DoNotCheck + }; + + std::string format(llvm::StringRef Code, + IncompleteCheck CheckIncomplete = IC_ExpectComplete) { + DEBUG(llvm::errs() << "---\n"); + DEBUG(llvm::errs() << Code << "\n\n"); + std::vector Ranges(1, tooling::Range(0, Code.size())); + bool IncompleteFormat = false; + tooling::Replacements Replaces = + reformat(Style, Code, Ranges, "", &IncompleteFormat); + if (CheckIncomplete != IC_DoNotCheck) { + bool ExpectedIncompleteFormat = CheckIncomplete == IC_ExpectIncomplete; + EXPECT_EQ(ExpectedIncompleteFormat, IncompleteFormat) << Code << "\n\n"; + } + auto Result = applyAllReplacements(Code, Replaces); + EXPECT_TRUE(static_cast(Result)); + DEBUG(llvm::errs() << "\n" << *Result << "\n\n"); + return *Result; + } + + void verifyFormat(StringRef Code) { + EXPECT_EQ(Code.str(), format(test::messUp(Code))); + } + + void verifyIncompleteFormat(StringRef Code) { + EXPECT_EQ(Code.str(), format(test::messUp(Code), IC_ExpectIncomplete)); + } + + FormatStyle Style; +}; + +TEST_F(FormatTestObjC, DetectsObjCInHeaders) { + Style = getStyle("LLVM", "a.h", "none", "@interface\n" + "- (id)init;"); + EXPECT_EQ(FormatStyle::LK_ObjC, Style.Language); + Style = getStyle("LLVM", "a.h", "none", "@interface\n" + "+ (id)init;"); + EXPECT_EQ(FormatStyle::LK_ObjC, Style.Language); + + // No recognizable ObjC. + Style = getStyle("LLVM", "a.h", "none", "void f() {}"); + EXPECT_EQ(FormatStyle::LK_Cpp, Style.Language); +} + +TEST_F(FormatTestObjC, FormatObjCTryCatch) { + verifyFormat("@try {\n" + " f();\n" + "} @catch (NSException e) {\n" + " @throw;\n" + "} @finally {\n" + " exit(42);\n" + "}"); + verifyFormat("DEBUG({\n" + " @try {\n" + " } @finally {\n" + " }\n" + "});\n"); +} + +TEST_F(FormatTestObjC, FormatObjCAutoreleasepool) { + verifyFormat("@autoreleasepool {\n" + " f();\n" + "}\n" + "@autoreleasepool {\n" + " f();\n" + "}\n"); + Style.BreakBeforeBraces = FormatStyle::BS_Allman; + verifyFormat("@autoreleasepool\n" + "{\n" + " f();\n" + "}\n" + "@autoreleasepool\n" + "{\n" + " f();\n" + "}\n"); +} + +TEST_F(FormatTestObjC, FormatObjCInterface) { + verifyFormat("@interface Foo : NSObject {\n" + "@public\n" + " int field1;\n" + "@protected\n" + " int field2;\n" + "@private\n" + " int field3;\n" + "@package\n" + " int field4;\n" + "}\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface /* wait for it */ Foo\n" + "+ (id)init;\n" + "// Look, a comment!\n" + "- (int)answerWith:(int)i;\n" + "@end"); + + verifyFormat("@interface Foo\n" + "@end\n" + "@interface Bar\n" + "@end"); + + verifyFormat("@interface Foo : Bar\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo : /**/ Bar /**/ \n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo (HackStuff)\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo ()\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo (HackStuff) \n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo {\n" + " int _i;\n" + "}\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo : Bar {\n" + " int _i;\n" + "}\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo : Bar {\n" + " int _i;\n" + "}\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo (HackStuff) {\n" + " int _i;\n" + "}\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo () {\n" + " int _i;\n" + "}\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo (HackStuff) {\n" + " int _i;\n" + "}\n" + "+ (id)init;\n" + "@end"); + + Style = getGoogleStyle(FormatStyle::LK_ObjC); + verifyFormat("@interface Foo : NSObject {\n" + " @public\n" + " int field1;\n" + " @protected\n" + " int field2;\n" + " @private\n" + " int field3;\n" + " @package\n" + " int field4;\n" + "}\n" + "+ (id)init;\n" + "@end"); + verifyFormat("@interface Foo : Bar\n" + "+ (id)init;\n" + "@end"); + verifyFormat("@interface Foo (HackStuff)\n" + "+ (id)init;\n" + "@end"); + Style.BinPackParameters = false; + Style.ColumnLimit = 80; + verifyFormat("@interface aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ()<\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> {\n" + "}"); +} + +TEST_F(FormatTestObjC, FormatObjCImplementation) { + verifyFormat("@implementation Foo : NSObject {\n" + "@public\n" + " int field1;\n" + "@protected\n" + " int field2;\n" + "@private\n" + " int field3;\n" + "@package\n" + " int field4;\n" + "}\n" + "+ (id)init {\n}\n" + "@end"); + + verifyFormat("@implementation Foo\n" + "+ (id)init {\n" + " if (true)\n" + " return nil;\n" + "}\n" + "// Look, a comment!\n" + "- (int)answerWith:(int)i {\n" + " return i;\n" + "}\n" + "+ (int)answerWith:(int)i {\n" + " return i;\n" + "}\n" + "@end"); + + verifyFormat("@implementation Foo\n" + "@end\n" + "@implementation Bar\n" + "@end"); + + EXPECT_EQ("@implementation Foo : Bar\n" + "+ (id)init {\n}\n" + "- (void)foo {\n}\n" + "@end", + format("@implementation Foo : Bar\n" + "+(id)init{}\n" + "-(void)foo{}\n" + "@end")); + + verifyFormat("@implementation Foo {\n" + " int _i;\n" + "}\n" + "+ (id)init {\n}\n" + "@end"); + + verifyFormat("@implementation Foo : Bar {\n" + " int _i;\n" + "}\n" + "+ (id)init {\n}\n" + "@end"); + + verifyFormat("@implementation Foo (HackStuff)\n" + "+ (id)init {\n}\n" + "@end"); + verifyFormat("@implementation ObjcClass\n" + "- (void)method;\n" + "{}\n" + "@end"); + + Style = getGoogleStyle(FormatStyle::LK_ObjC); + verifyFormat("@implementation Foo : NSObject {\n" + " @public\n" + " int field1;\n" + " @protected\n" + " int field2;\n" + " @private\n" + " int field3;\n" + " @package\n" + " int field4;\n" + "}\n" + "+ (id)init {\n}\n" + "@end"); +} + +TEST_F(FormatTestObjC, FormatObjCProtocol) { + verifyFormat("@protocol Foo\n" + "@property(weak) id delegate;\n" + "- (NSUInteger)numberOfThings;\n" + "@end"); + + verifyFormat("@protocol MyProtocol \n" + "- (NSUInteger)numberOfThings;\n" + "@end"); + + verifyFormat("@protocol Foo;\n" + "@protocol Bar;\n"); + + verifyFormat("@protocol Foo\n" + "@end\n" + "@protocol Bar\n" + "@end"); + + verifyFormat("@protocol myProtocol\n" + "- (void)mandatoryWithInt:(int)i;\n" + "@optional\n" + "- (void)optional;\n" + "@required\n" + "- (void)required;\n" + "@optional\n" + "@property(assign) int madProp;\n" + "@end\n"); + + verifyFormat("@property(nonatomic, assign, readonly)\n" + " int *looooooooooooooooooooooooooooongNumber;\n" + "@property(nonatomic, assign, readonly)\n" + " NSString *looooooooooooooooooooooooooooongName;"); + + verifyFormat("@implementation PR18406\n" + "}\n" + "@end"); + + Style = getGoogleStyle(FormatStyle::LK_ObjC); + verifyFormat("@protocol MyProtocol\n" + "- (NSUInteger)numberOfThings;\n" + "@end"); +} + +TEST_F(FormatTestObjC, FormatObjCMethodDeclarations) { + verifyFormat("- (void)doSomethingWith:(GTMFoo *)theFoo\n" + " rect:(NSRect)theRect\n" + " interval:(float)theInterval {\n" + "}"); + verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n" + " longKeyword:(NSRect)theRect\n" + " longerKeyword:(float)theInterval\n" + " error:(NSError **)theError {\n" + "}"); + verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n" + " longKeyword:(NSRect)theRect\n" + " evenLongerKeyword:(float)theInterval\n" + " error:(NSError **)theError {\n" + "}"); + Style.ColumnLimit = 60; + verifyFormat("- (instancetype)initXxxxxx:(id)x\n" + " y:(id)y\n" + " NS_DESIGNATED_INITIALIZER;"); + verifyFormat("- (void)drawRectOn:(id)surface\n" + " ofSize:(size_t)height\n" + " :(size_t)width;"); + + // Continuation indent width should win over aligning colons if the function + // name is long. + Style = getGoogleStyle(FormatStyle::LK_ObjC); + Style.ColumnLimit = 40; + Style.IndentWrappedFunctionNames = true; + verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n" + " dontAlignNamef:(NSRect)theRect {\n" + "}"); + + // Make sure we don't break aligning for short parameter names. + verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n" + " aShortf:(NSRect)theRect {\n" + "}"); + + // Format pairs correctly. + Style.ColumnLimit = 80; + verifyFormat("- (void)drawRectOn:(id)surface\n" + " ofSize:(aaaaaaaa)height\n" + " :(size_t)width\n" + " atOrigin:(size_t)x\n" + " :(size_t)y\n" + " aaaaa:(a)yyy\n" + " bbb:(d)cccc;"); + verifyFormat("- (void)drawRectOn:(id)surface ofSize:(aaa)height:(bbb)width;"); +} + +TEST_F(FormatTestObjC, FormatObjCMethodExpr) { + verifyFormat("[foo bar:baz];"); + verifyFormat("return [foo bar:baz];"); + verifyFormat("return (a)[foo bar:baz];"); + verifyFormat("f([foo bar:baz]);"); + verifyFormat("f(2, [foo bar:baz]);"); + verifyFormat("f(2, a ? b : c);"); + verifyFormat("[[self initWithInt:4] bar:[baz quux:arrrr]];"); + + // Unary operators. + verifyFormat("int a = +[foo bar:baz];"); + verifyFormat("int a = -[foo bar:baz];"); + verifyFormat("int a = ![foo bar:baz];"); + verifyFormat("int a = ~[foo bar:baz];"); + verifyFormat("int a = ++[foo bar:baz];"); + verifyFormat("int a = --[foo bar:baz];"); + verifyFormat("int a = sizeof [foo bar:baz];"); + verifyFormat("int a = alignof [foo bar:baz];"); + verifyFormat("int a = &[foo bar:baz];"); + verifyFormat("int a = *[foo bar:baz];"); + // FIXME: Make casts work, without breaking f()[4]. + // verifyFormat("int a = (int)[foo bar:baz];"); + // verifyFormat("return (int)[foo bar:baz];"); + // verifyFormat("(void)[foo bar:baz];"); + verifyFormat("return (MyType *)[self.tableView cellForRowAtIndexPath:cell];"); + + // Binary operators. + verifyFormat("[foo bar:baz], [foo bar:baz];"); + verifyFormat("[foo bar:baz] = [foo bar:baz];"); + verifyFormat("[foo bar:baz] *= [foo bar:baz];"); + verifyFormat("[foo bar:baz] /= [foo bar:baz];"); + verifyFormat("[foo bar:baz] %= [foo bar:baz];"); + verifyFormat("[foo bar:baz] += [foo bar:baz];"); + verifyFormat("[foo bar:baz] -= [foo bar:baz];"); + verifyFormat("[foo bar:baz] <<= [foo bar:baz];"); + verifyFormat("[foo bar:baz] >>= [foo bar:baz];"); + verifyFormat("[foo bar:baz] &= [foo bar:baz];"); + verifyFormat("[foo bar:baz] ^= [foo bar:baz];"); + verifyFormat("[foo bar:baz] |= [foo bar:baz];"); + verifyFormat("[foo bar:baz] ? [foo bar:baz] : [foo bar:baz];"); + verifyFormat("[foo bar:baz] || [foo bar:baz];"); + verifyFormat("[foo bar:baz] && [foo bar:baz];"); + verifyFormat("[foo bar:baz] | [foo bar:baz];"); + verifyFormat("[foo bar:baz] ^ [foo bar:baz];"); + verifyFormat("[foo bar:baz] & [foo bar:baz];"); + verifyFormat("[foo bar:baz] == [foo bar:baz];"); + verifyFormat("[foo bar:baz] != [foo bar:baz];"); + verifyFormat("[foo bar:baz] >= [foo bar:baz];"); + verifyFormat("[foo bar:baz] <= [foo bar:baz];"); + verifyFormat("[foo bar:baz] > [foo bar:baz];"); + verifyFormat("[foo bar:baz] < [foo bar:baz];"); + verifyFormat("[foo bar:baz] >> [foo bar:baz];"); + verifyFormat("[foo bar:baz] << [foo bar:baz];"); + verifyFormat("[foo bar:baz] - [foo bar:baz];"); + verifyFormat("[foo bar:baz] + [foo bar:baz];"); + verifyFormat("[foo bar:baz] * [foo bar:baz];"); + verifyFormat("[foo bar:baz] / [foo bar:baz];"); + verifyFormat("[foo bar:baz] % [foo bar:baz];"); + // Whew! + + verifyFormat("return in[42];"); + verifyFormat("for (auto v : in[1]) {\n}"); + verifyFormat("for (int i = 0; i < in[a]; ++i) {\n}"); + verifyFormat("for (int i = 0; in[a] < i; ++i) {\n}"); + verifyFormat("for (int i = 0; i < n; ++i, ++in[a]) {\n}"); + verifyFormat("for (int i = 0; i < n; ++i, in[a]++) {\n}"); + verifyFormat("for (int i = 0; i < f(in[a]); ++i, in[a]++) {\n}"); + verifyFormat("for (id foo in [self getStuffFor:bla]) {\n" + "}"); + verifyFormat("[self aaaaa:MACRO(a, b:, c:)];"); + verifyFormat("[self aaaaa:(1 + 2) bbbbb:3];"); + verifyFormat("[self aaaaa:(Type)a bbbbb:3];"); + + verifyFormat("[self stuffWithInt:(4 + 2) float:4.5];"); + verifyFormat("[self stuffWithInt:a ? b : c float:4.5];"); + verifyFormat("[self stuffWithInt:a ? [self foo:bar] : c];"); + verifyFormat("[self stuffWithInt:a ? (e ? f : g) : c];"); + verifyFormat("[cond ? obj1 : obj2 methodWithParam:param]"); + verifyFormat("[button setAction:@selector(zoomOut:)];"); + verifyFormat("[color getRed:&r green:&g blue:&b alpha:&a];"); + + verifyFormat("arr[[self indexForFoo:a]];"); + verifyFormat("throw [self errorFor:a];"); + verifyFormat("@throw [self errorFor:a];"); + + verifyFormat("[(id)foo bar:(id)baz quux:(id)snorf];"); + verifyFormat("[(id)foo bar:(id) ? baz : quux];"); + verifyFormat("4 > 4 ? (id)a : (id)baz;"); + + // This tests that the formatter doesn't break after "backing" but before ":", + // which would be at 80 columns. + verifyFormat( + "void f() {\n" + " if ((self = [super initWithContentRect:contentRect\n" + " styleMask:styleMask ?: otherMask\n" + " backing:NSBackingStoreBuffered\n" + " defer:YES]))"); + + verifyFormat( + "[foo checkThatBreakingAfterColonWorksOk:\n" + " [bar ifItDoes:reduceOverallLineLengthLikeInThisCase]];"); + + verifyFormat("[myObj short:arg1 // Force line break\n" + " longKeyword:arg2 != nil ? arg2 : @\"longKeyword\"\n" + " evenLongerKeyword:arg3 ?: @\"evenLongerKeyword\"\n" + " error:arg4];"); + verifyFormat( + "void f() {\n" + " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n" + " initWithContentRect:NSMakeRect(origin_global.x, origin_global.y,\n" + " pos.width(), pos.height())\n" + " styleMask:NSBorderlessWindowMask\n" + " backing:NSBackingStoreBuffered\n" + " defer:NO]);\n" + "}"); + verifyFormat("[contentsContainer replaceSubview:[subviews objectAtIndex:0]\n" + " with:contentsNativeView];"); + + verifyFormat( + "[pboard addTypes:[NSArray arrayWithObject:kBookmarkButtonDragType]\n" + " owner:nillllll];"); + + verifyFormat( + "[pboard setData:[NSData dataWithBytes:&button length:sizeof(button)]\n" + " forType:kBookmarkButtonDragType];"); + + verifyFormat("[defaultCenter addObserver:self\n" + " selector:@selector(willEnterFullscreen)\n" + " name:kWillEnterFullscreenNotification\n" + " object:nil];"); + verifyFormat("[image_rep drawInRect:drawRect\n" + " fromRect:NSZeroRect\n" + " operation:NSCompositeCopy\n" + " fraction:1.0\n" + " respectFlipped:NO\n" + " hints:nil];"); + verifyFormat("[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];"); + verifyFormat("[aaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaa)\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];"); + verifyFormat("[aaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaa[aaaaaaaaaaaaaaaaaaaaa]\n" + " aaaaaaaaaaaaaaaaaaaaaa];"); + + verifyFormat( + "scoped_nsobject message(\n" + " // The frame will be fixed up when |-setMessageText:| is called.\n" + " [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]);"); + verifyFormat("[self aaaaaa:bbbbbbbbbbbbb\n" + " aaaaaaaaaa:bbbbbbbbbbbbbbbbb\n" + " aaaaa:bbbbbbbbbbb + bbbbbbbbbbbb\n" + " aaaa:bbb];"); + verifyFormat("[self param:function( //\n" + " parameter)]"); + verifyFormat( + "[self aaaaaaaaaa:aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa |\n" + " aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa |\n" + " aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa];"); + + // Variadic parameters. + verifyFormat( + "NSArray *myStrings = [NSArray stringarray:@\"a\", @\"b\", nil];"); + verifyFormat( + "[self aaaaaaaaaaaaa:aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa,\n" + " aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa,\n" + " aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa];"); + verifyFormat("[self // break\n" + " a:a\n" + " aaa:aaa];"); + verifyFormat("bool a = ([aaaaaaaa aaaaa] == aaaaaaaaaaaaaaaaa ||\n" + " [aaaaaaaa aaaaa] == aaaaaaaaaaaaaaaaaaaa);"); + + // Formats pair-parameters. + verifyFormat("[I drawRectOn:surface ofSize:aa:bbb atOrigin:cc:dd];"); + verifyFormat("[I drawRectOn:surface //\n" + " ofSize:aa:bbb\n" + " atOrigin:cc:dd];"); + + Style.ColumnLimit = 70; + verifyFormat( + "void f() {\n" + " popup_wdow_.reset([[RenderWidgetPopupWindow alloc]\n" + " iniithContentRect:NSMakRet(origin_global.x, origin_global.y,\n" + " pos.width(), pos.height())\n" + " syeMask:NSBorderlessWindowMask\n" + " bking:NSBackingStoreBuffered\n" + " der:NO]);\n" + "}"); + + Style.ColumnLimit = 60; + verifyFormat("[call aaaaaaaa.aaaaaa.aaaaaaaa.aaaaaaaa.aaaaaaaa.aaaaaaaa\n" + " .aaaaaaaa];"); // FIXME: Indentation seems off. + // FIXME: This violates the column limit. + verifyFormat( + "[aaaaaaaaaaaaaaaaaaaaaaaaa\n" + " aaaaaaaaaaaaaaaaa:aaaaaaaa\n" + " aaa:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];"); + + Style = getChromiumStyle(FormatStyle::LK_ObjC); + Style.ColumnLimit = 80; + verifyFormat( + "void f() {\n" + " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n" + " initWithContentRect:NSMakeRect(origin_global.x, origin_global.y,\n" + " pos.width(), pos.height())\n" + " styleMask:NSBorderlessWindowMask\n" + " backing:NSBackingStoreBuffered\n" + " defer:NO]);\n" + "}"); +} + +TEST_F(FormatTestObjC, ObjCAt) { + verifyFormat("@autoreleasepool"); + verifyFormat("@catch"); + verifyFormat("@class"); + verifyFormat("@compatibility_alias"); + verifyFormat("@defs"); + verifyFormat("@dynamic"); + verifyFormat("@encode"); + verifyFormat("@end"); + verifyFormat("@finally"); + verifyFormat("@implementation"); + verifyFormat("@import"); + verifyFormat("@interface"); + verifyFormat("@optional"); + verifyFormat("@package"); + verifyFormat("@private"); + verifyFormat("@property"); + verifyFormat("@protected"); + verifyFormat("@protocol"); + verifyFormat("@public"); + verifyFormat("@required"); + verifyFormat("@selector"); + verifyFormat("@synchronized"); + verifyFormat("@synthesize"); + verifyFormat("@throw"); + verifyFormat("@try"); + + EXPECT_EQ("@interface", format("@ interface")); + + // The precise formatting of this doesn't matter, nobody writes code like + // this. + verifyFormat("@ /*foo*/ interface"); +} + +TEST_F(FormatTestObjC, ObjCSnippets) { + verifyFormat("@autoreleasepool {\n" + " foo();\n" + "}"); + verifyFormat("@class Foo, Bar;"); + verifyFormat("@compatibility_alias AliasName ExistingClass;"); + verifyFormat("@dynamic textColor;"); + verifyFormat("char *buf1 = @encode(int *);"); + verifyFormat("char *buf1 = @encode(typeof(4 * 5));"); + verifyFormat("char *buf1 = @encode(int **);"); + verifyFormat("Protocol *proto = @protocol(p1);"); + verifyFormat("SEL s = @selector(foo:);"); + verifyFormat("@synchronized(self) {\n" + " f();\n" + "}"); + + verifyFormat("@import foo.bar;\n" + "@import baz;"); + + verifyFormat("@synthesize dropArrowPosition = dropArrowPosition_;"); + + verifyFormat("@property(assign, nonatomic) CGFloat hoverAlpha;"); + verifyFormat("@property(assign, getter=isEditable) BOOL editable;"); + + Style = getMozillaStyle(); + verifyFormat("@property (assign, getter=isEditable) BOOL editable;"); + verifyFormat("@property BOOL editable;"); + + Style = getWebKitStyle(); + verifyFormat("@property (assign, getter=isEditable) BOOL editable;"); + verifyFormat("@property BOOL editable;"); + + Style = getGoogleStyle(FormatStyle::LK_ObjC); + verifyFormat("@synthesize dropArrowPosition = dropArrowPosition_;"); + verifyFormat("@property(assign, getter=isEditable) BOOL editable;"); +} + +TEST_F(FormatTestObjC, ObjCForIn) { + verifyFormat("- (void)test {\n" + " for (NSString *n in arrayOfStrings) {\n" + " foo(n);\n" + " }\n" + "}"); + verifyFormat("- (void)test {\n" + " for (NSString *n in (__bridge NSArray *)arrayOfStrings) {\n" + " foo(n);\n" + " }\n" + "}"); +} + +TEST_F(FormatTestObjC, ObjCLiterals) { + verifyFormat("@\"String\""); + verifyFormat("@1"); + verifyFormat("@+4.8"); + verifyFormat("@-4"); + verifyFormat("@1LL"); + verifyFormat("@.5"); + verifyFormat("@'c'"); + verifyFormat("@true"); + + verifyFormat("NSNumber *smallestInt = @(-INT_MAX - 1);"); + verifyFormat("NSNumber *piOverTwo = @(M_PI / 2);"); + verifyFormat("NSNumber *favoriteColor = @(Green);"); + verifyFormat("NSString *path = @(getenv(\"PATH\"));"); + + verifyFormat("[dictionary setObject:@(1) forKey:@\"number\"];"); +} + +TEST_F(FormatTestObjC, ObjCDictLiterals) { + verifyFormat("@{"); + verifyFormat("@{}"); + verifyFormat("@{@\"one\" : @1}"); + verifyFormat("return @{@\"one\" : @1;"); + verifyFormat("@{@\"one\" : @1}"); + + verifyFormat("@{@\"one\" : @{@2 : @1}}"); + verifyFormat("@{\n" + " @\"one\" : @{@2 : @1},\n" + "}"); + + verifyFormat("@{1 > 2 ? @\"one\" : @\"two\" : 1 > 2 ? @1 : @2}"); + verifyIncompleteFormat("[self setDict:@{}"); + verifyIncompleteFormat("[self setDict:@{@1 : @2}"); + verifyFormat("NSLog(@\"%@\", @{@1 : @2, @2 : @3}[@1]);"); + verifyFormat( + "NSDictionary *masses = @{@\"H\" : @1.0078, @\"He\" : @4.0026};"); + verifyFormat( + "NSDictionary *settings = @{AVEncoderKey : @(AVAudioQualityMax)};"); + + verifyFormat("NSDictionary *d = @{\n" + " @\"nam\" : NSUserNam(),\n" + " @\"dte\" : [NSDate date],\n" + " @\"processInfo\" : [NSProcessInfo processInfo]\n" + "};"); + verifyFormat( + "@{\n" + " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee : " + "regularFont,\n" + "};"); + verifyFormat( + "@{\n" + " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee :\n" + " reeeeeeeeeeeeeeeeeeeeeeeegularFont,\n" + "};"); + + // We should try to be robust in case someone forgets the "@". + verifyFormat("NSDictionary *d = {\n" + " @\"nam\" : NSUserNam(),\n" + " @\"dte\" : [NSDate date],\n" + " @\"processInfo\" : [NSProcessInfo processInfo]\n" + "};"); + verifyFormat("NSMutableDictionary *dictionary =\n" + " [NSMutableDictionary dictionaryWithDictionary:@{\n" + " aaaaaaaaaaaaaaaaaaaaa : aaaaaaaaaaaaa,\n" + " bbbbbbbbbbbbbbbbbb : bbbbb,\n" + " cccccccccccccccc : ccccccccccccccc\n" + " }];"); + + // Ensure that casts before the key are kept on the same line as the key. + verifyFormat( + "NSDictionary *d = @{\n" + " (aaaaaaaa id)aaaaaaaaa : (aaaaaaaa id)aaaaaaaaaaaaaaaaaaaaaaaa,\n" + " (aaaaaaaa id)aaaaaaaaaaaaaa : (aaaaaaaa id)aaaaaaaaaaaaaa,\n" + "};"); + + Style = getGoogleStyle(FormatStyle::LK_ObjC); + verifyFormat( + "@{\n" + " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee : " + "regularFont,\n" + "};"); +} + +TEST_F(FormatTestObjC, ObjCArrayLiterals) { + verifyIncompleteFormat("@["); + verifyFormat("@[]"); + verifyFormat( + "NSArray *array = @[ @\" Hey \", NSApp, [NSNumber numberWithInt:42] ];"); + verifyFormat("return @[ @3, @[], @[ @4, @5 ] ];"); + verifyFormat("NSArray *array = @[ [foo description] ];"); + + verifyFormat( + "NSArray *some_variable = @[\n" + " aaaa == bbbbbbbbbbb ? @\"aaaaaaaaaaaa\" : @\"aaaaaaaaaaaaaa\",\n" + " @\"aaaaaaaaaaaaaaaaa\",\n" + " @\"aaaaaaaaaaaaaaaaa\",\n" + " @\"aaaaaaaaaaaaaaaaa\",\n" + "];"); + verifyFormat( + "NSArray *some_variable = @[\n" + " aaaa == bbbbbbbbbbb ? @\"aaaaaaaaaaaa\" : @\"aaaaaaaaaaaaaa\",\n" + " @\"aaaaaaaaaaaaaaaa\", @\"aaaaaaaaaaaaaaaa\", @\"aaaaaaaaaaaaaaaa\"\n" + "];"); + verifyFormat("NSArray *some_variable = @[\n" + " @\"aaaaaaaaaaaaaaaaa\",\n" + " @\"aaaaaaaaaaaaaaaaa\",\n" + " @\"aaaaaaaaaaaaaaaaa\",\n" + " @\"aaaaaaaaaaaaaaaaa\",\n" + "];"); + verifyFormat("NSArray *array = @[\n" + " @\"a\",\n" + " @\"a\",\n" // Trailing comma -> one per line. + "];"); + + // We should try to be robust in case someone forgets the "@". + verifyFormat("NSArray *some_variable = [\n" + " @\"aaaaaaaaaaaaaaaaa\",\n" + " @\"aaaaaaaaaaaaaaaaa\",\n" + " @\"aaaaaaaaaaaaaaaaa\",\n" + " @\"aaaaaaaaaaaaaaaaa\",\n" + "];"); + verifyFormat( + "- (NSAttributedString *)attributedStringForSegment:(NSUInteger)segment\n" + " index:(NSUInteger)index\n" + " nonDigitAttributes:\n" + " (NSDictionary *)noDigitAttributes;"); + verifyFormat("[someFunction someLooooooooooooongParameter:@[\n" + " NSBundle.mainBundle.infoDictionary[@\"a\"]\n" + "]];"); +} +} // end namespace +} // end namespace format +} // end namespace clang diff --git a/clang/unittests/Tooling/ReplacementTest.h b/clang/unittests/Tooling/ReplacementTest.h index 91530f016fb5..b6fe5c79b7be 100644 --- a/clang/unittests/Tooling/ReplacementTest.h +++ b/clang/unittests/Tooling/ReplacementTest.h @@ -24,7 +24,7 @@ namespace tooling { /// \brief Converts a set of replacements to Replacements class. /// \return A Replacements class containing \p Replaces on success; otherwise, /// an empty Replacements is returned. -static tooling::Replacements +inline tooling::Replacements toReplacements(const std::set &Replaces) { tooling::Replacements Result; for (const auto &R : Replaces) {