Author: djasper Date: Mon Dec 12 06:42:29 2016 New Revision: 289428 URL: http://llvm.org/viewvc/llvm-project?rev=289428&view=rev Log: clang-format: Separate out a language kind for ObjC.
While C(++) and ObjC are generally formatted the same way and can be mixed, people might want to choose different styles based on the language. This patch recognizes .m and .mm files as ObjC and also implements a very crude detection of whether or not a .h file contains ObjC code. This can be improved over time. Also move most of the ObjC tests into their own test file to keep file size maintainable. Added: cfe/trunk/unittests/Format/FormatTestObjC.cpp Modified: cfe/trunk/include/clang/Format/Format.h cfe/trunk/lib/Format/ContinuationIndenter.cpp cfe/trunk/lib/Format/Format.cpp cfe/trunk/lib/Format/FormatTokenLexer.cpp cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/tools/clang-format/ClangFormat.cpp cfe/trunk/unittests/Format/CMakeLists.txt cfe/trunk/unittests/Format/FormatTest.cpp cfe/trunk/unittests/Tooling/ReplacementTest.h Modified: cfe/trunk/include/clang/Format/Format.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Format/Format.h?rev=289428&r1=289427&r2=289428&view=diff ============================================================================== --- cfe/trunk/include/clang/Format/Format.h (original) +++ cfe/trunk/include/clang/Format/Format.h Mon Dec 12 06:42:29 2016 @@ -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 *StyleOptionHelpDescri /// == "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) { Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.cpp?rev=289428&r1=289427&r2=289428&view=diff ============================================================================== --- cfe/trunk/lib/Format/ContinuationIndenter.cpp (original) +++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Mon Dec 12 06:42:29 2016 @@ -560,6 +560,7 @@ unsigned ContinuationIndenter::addTokenO // 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) Modified: cfe/trunk/lib/Format/Format.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=289428&r1=289427&r2=289428&view=diff ============================================================================== --- cfe/trunk/lib/Format/Format.cpp (original) +++ cfe/trunk/lib/Format/Format.cpp Mon Dec 12 06:42:29 2016 @@ -52,6 +52,7 @@ template <> struct ScalarEnumerationTrai 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:: } 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 getLang 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 getLang } 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"; Modified: cfe/trunk/lib/Format/FormatTokenLexer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatTokenLexer.cpp?rev=289428&r1=289427&r2=289428&view=diff ============================================================================== --- cfe/trunk/lib/Format/FormatTokenLexer.cpp (original) +++ cfe/trunk/lib/Format/FormatTokenLexer.cpp Mon Dec 12 06:42:29 2016 @@ -558,7 +558,8 @@ FormatToken *FormatTokenLexer::getNextTo 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) && Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=289428&r1=289427&r2=289428&view=diff ============================================================================== --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Mon Dec 12 06:42:29 2016 @@ -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; Modified: cfe/trunk/tools/clang-format/ClangFormat.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-format/ClangFormat.cpp?rev=289428&r1=289427&r2=289428&view=diff ============================================================================== --- cfe/trunk/tools/clang-format/ClangFormat.cpp (original) +++ cfe/trunk/tools/clang-format/ClangFormat.cpp Mon Dec 12 06:42:29 2016 @@ -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; Modified: cfe/trunk/unittests/Format/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/CMakeLists.txt?rev=289428&r1=289427&r2=289428&view=diff ============================================================================== --- cfe/trunk/unittests/Format/CMakeLists.txt (original) +++ cfe/trunk/unittests/Format/CMakeLists.txt Mon Dec 12 06:42:29 2016 @@ -7,6 +7,7 @@ add_clang_unittest(FormatTests FormatTest.cpp FormatTestJava.cpp FormatTestJS.cpp + FormatTestObjC.cpp FormatTestProto.cpp FormatTestSelective.cpp SortImportsTestJS.cpp Modified: cfe/trunk/unittests/Format/FormatTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=289428&r1=289427&r2=289428&view=diff ============================================================================== --- cfe/trunk/unittests/Format/FormatTest.cpp (original) +++ cfe/trunk/unittests/Format/FormatTest.cpp Mon Dec 12 06:42:29 2016 @@ -2493,42 +2493,6 @@ TEST_F(FormatTest, FormatTryCatchBraceSt 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, FormatForObjectiveCMe verifyGoogleFormat("- foo:(int)foo;"); } -TEST_F(FormatTest, FormatObjCInterface) { - verifyFormat("@interface Foo : NSObject <NSSomeDelegate> {\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<NSSomeDelegate> {\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 /**/ <Baz, /**/ Quux>\n" - "+ (id)init;\n" - "@end"); - - verifyGoogleFormat("@interface Foo : Bar<Baz, Quux>\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) <MyProtocol>\n" - "+ (id)init;\n" - "@end"); - - verifyGoogleFormat("@interface Foo (HackStuff)<MyProtocol>\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 <Baz, Quux> {\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) <MyProtocol> {\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 <NSObject>\n" - "- (NSUInteger)numberOfThings;\n" - "@end"); - - verifyGoogleFormat("@protocol MyProtocol<NSObject>\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>)x\n" - " y:(id<yyyyyyyyyyyyyyyyyyyy>)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<NSTextField> 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()); } Added: cfe/trunk/unittests/Format/FormatTestObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestObjC.cpp?rev=289428&view=auto ============================================================================== --- cfe/trunk/unittests/Format/FormatTestObjC.cpp (added) +++ cfe/trunk/unittests/Format/FormatTestObjC.cpp Mon Dec 12 06:42:29 2016 @@ -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<tooling::Range> Ranges(1, tooling::Range(0, Code.size())); + bool IncompleteFormat = false; + tooling::Replacements Replaces = + reformat(Style, Code, Ranges, "<stdin>", &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<bool>(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 <NSSomeDelegate> {\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 /**/ <Baz, /**/ Quux>\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) <MyProtocol>\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 <Baz, Quux> {\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) <MyProtocol> {\n" + " int _i;\n" + "}\n" + "+ (id)init;\n" + "@end"); + + Style = getGoogleStyle(FormatStyle::LK_ObjC); + verifyFormat("@interface Foo : NSObject<NSSomeDelegate> {\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<Baz, Quux>\n" + "+ (id)init;\n" + "@end"); + verifyFormat("@interface Foo (HackStuff)<MyProtocol>\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 <NSObject>\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<NSObject>\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>)x\n" + " y:(id<yyyyyyyyyyyyyyyyyyyy>)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<NSTextField> 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 Modified: cfe/trunk/unittests/Tooling/ReplacementTest.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/ReplacementTest.h?rev=289428&r1=289427&r2=289428&view=diff ============================================================================== --- cfe/trunk/unittests/Tooling/ReplacementTest.h (original) +++ cfe/trunk/unittests/Tooling/ReplacementTest.h Mon Dec 12 06:42:29 2016 @@ -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<tooling::Replacement> &Replaces) { tooling::Replacements Result; for (const auto &R : Replaces) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits