]> granicus.if.org Git - clang/commitdiff
clang-format: Separate out a language kind for ObjC.
authorDaniel Jasper <djasper@google.com>
Mon, 12 Dec 2016 12:42:29 +0000 (12:42 +0000)
committerDaniel Jasper <djasper@google.com>
Mon, 12 Dec 2016 12:42:29 +0000 (12:42 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@289428 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Format/Format.h
lib/Format/ContinuationIndenter.cpp
lib/Format/Format.cpp
lib/Format/FormatTokenLexer.cpp
lib/Format/TokenAnnotator.cpp
tools/clang-format/ClangFormat.cpp
unittests/Format/CMakeLists.txt
unittests/Format/FormatTest.cpp
unittests/Format/FormatTestObjC.cpp [new file with mode: 0644]
unittests/Tooling/ReplacementTest.h

index d34ca2fee39291b917a14c7cabc0af443efeda28..6c6458b33d85423c18bf7ec1ef369ea00ff9f1f9 100644 (file)
@@ -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) {
index 404e3a3b4ade632daf8849add768790a3111a261..aa6f37bd199de4d494e7e7309b538cf67b62c80b 100644 (file)
@@ -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)
index bcea5ac411af2ee75a2a5e1efea862e98a51803b..4879d1e818cd9cbb329deed6201e50c784997015 100644 (file)
@@ -52,6 +52,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
     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";
index 2aa48e3f49136f090d2ddab1146eaf86455381f3..46a32a917dd93911632c507d434e50c74b0d8f5c 100644 (file)
@@ -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) &&
index 57f30276b364a622cc61f46bd73dd0e67b4180a8..4db0e937afc037c2dc79e6c68c521dd8088a03b3 100644 (file)
@@ -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;
 
index c09723928b795ef0fd701d4c919b70ee810b571e..6c50daf538344bf78cefb1c852f6da9c570df3ce 100644 (file)
@@ -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;
index 240be6ead2a5e149f2d8f00b6a22b06450410b9f..eb7756a0ba566cb7b02484db3ce38945325db950 100644 (file)
@@ -7,6 +7,7 @@ add_clang_unittest(FormatTests
   FormatTest.cpp
   FormatTestJava.cpp
   FormatTestJS.cpp
+  FormatTestObjC.cpp
   FormatTestProto.cpp
   FormatTestSelective.cpp
   SortImportsTestJS.cpp
index e851bb2a5f5ed8d14845bc7232edc65f6cee7a2d..fe2d470420748ddbacb00b9b6c484c7dc8d5b06c 100644 (file)
@@ -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 <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());
 }
 
diff --git a/unittests/Format/FormatTestObjC.cpp b/unittests/Format/FormatTestObjC.cpp
new file mode 100644 (file)
index 0000000..6a530f9
--- /dev/null
@@ -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
index 91530f016fb5f9449be705b5210f6671e29130b4..b6fe5c79b7beff4bb06c8e52cafef221e0a93b98 100644 (file)
@@ -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) {