[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-12 Thread Ben Hamilton via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
benhamilton marked an inline comment as done.
Closed by commit rC327285: [clang-format] Improve detection of Objective-C 
block types (authored by benhamilton, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D43906?vs=138024=138026#toc

Repository:
  rC Clang

https://reviews.llvm.org/D43906

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTest.cpp
  unittests/Format/FormatTestObjC.cpp


Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -141,10 +141,7 @@
 Contexts.size() == 2 && Contexts[0].ColonIsForRangeExpr;
 
 bool StartsObjCMethodExpr = false;
-if (CurrentToken->is(tok::caret)) {
-  // (^ can start a block type.
-  Left->Type = TT_ObjCBlockLParen;
-} else if (FormatToken *MaybeSel = Left->Previous) {
+if (FormatToken *MaybeSel = Left->Previous) {
   // @selector( starts a selector.
   if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous 
&&
   MaybeSel->Previous->is(tok::at)) {
@@ -210,8 +207,16 @@
   Left->Type = TT_ObjCMethodExpr;
 }
 
+// MightBeFunctionType and ProbablyFunctionType are used for
+// function pointer and reference types as well as Objective-C
+// block types:
+//
+// void (*FunctionPointer)(void);
+// void ()(void);
+// void (^ObjCBlock)(void);
 bool MightBeFunctionType = !Contexts[Contexts.size() - 2].IsExpression;
-bool ProbablyFunctionType = CurrentToken->isOneOf(tok::star, tok::amp);
+bool ProbablyFunctionType =
+CurrentToken->isOneOf(tok::star, tok::amp, tok::caret);
 bool HasMultipleLines = false;
 bool HasMultipleParametersOnALine = false;
 bool MightBeObjCForRangeLoop =
@@ -248,7 +253,8 @@
 if (MightBeFunctionType && ProbablyFunctionType && CurrentToken->Next 
&&
 (CurrentToken->Next->is(tok::l_paren) ||
  (CurrentToken->Next->is(tok::l_square) && 
Line.MustBeDeclaration)))
-  Left->Type = TT_FunctionTypeLParen;
+  Left->Type = Left->Next->is(tok::caret) ? TT_ObjCBlockLParen
+  : TT_FunctionTypeLParen;
 Left->MatchingParen = CurrentToken;
 CurrentToken->MatchingParen = Left;
 
Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -12128,6 +12128,22 @@
   EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "[[foo::bar, ...]]"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithCaret) {
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^);"));
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^, Bar);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo[10])(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo[kNumEntries])(char, float);"));
+  EXPECT_EQ(
+  FormatStyle::LK_ObjC,
+  guessLanguage("foo.h", "int(^foo[(kNumEntries + 10)])(char, float);"));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: unittests/Format/FormatTestObjC.cpp
===
--- unittests/Format/FormatTestObjC.cpp
+++ unittests/Format/FormatTestObjC.cpp
@@ -845,6 +845,15 @@
   verifyFormat("@ /*foo*/ interface");
 }
 
+TEST_F(FormatTestObjC, ObjCBlockTypesAndVariables) {
+  verifyFormat("void DoStuffWithBlockType(int (^)(char));");
+  verifyFormat("int (^foo)(char, float);");
+  verifyFormat("int (^foo[10])(char, float);");
+  verifyFormat("int (^foo[kNumEntries])(char, float);");
+  verifyFormat("int (^foo[kNumEntries + 10])(char, float);");
+  verifyFormat("int (^foo[(kNumEntries + 10)])(char, float);");
+}
+
 TEST_F(FormatTestObjC, ObjCSnippets) {
   verifyFormat("@autoreleasepool {\n"
"  foo();\n"


Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -141,10 +141,7 @@
 Contexts.size() == 2 && Contexts[0].ColonIsForRangeExpr;
 
 bool StartsObjCMethodExpr = false;
-if (CurrentToken->is(tok::caret)) {
-  // (^ can start a block type.
-  Left->Type = TT_ObjCBlockLParen;
-} else if (FormatToken *MaybeSel = Left->Previous) {
+if (FormatToken *MaybeSel = Left->Previous) {
   // @selector( starts a selector.
   if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous &&
   MaybeSel->Previous->is(tok::at)) {
@@ -210,8 

[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-12 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton updated this revision to Diff 138024.
benhamilton added a comment.

- Restore short functionn type variable names and add clarifying comment.


Repository:
  rC Clang

https://reviews.llvm.org/D43906

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTest.cpp
  unittests/Format/FormatTestObjC.cpp


Index: unittests/Format/FormatTestObjC.cpp
===
--- unittests/Format/FormatTestObjC.cpp
+++ unittests/Format/FormatTestObjC.cpp
@@ -845,6 +845,15 @@
   verifyFormat("@ /*foo*/ interface");
 }
 
+TEST_F(FormatTestObjC, ObjCBlockTypesAndVariables) {
+  verifyFormat("void DoStuffWithBlockType(int (^)(char));");
+  verifyFormat("int (^foo)(char, float);");
+  verifyFormat("int (^foo[10])(char, float);");
+  verifyFormat("int (^foo[kNumEntries])(char, float);");
+  verifyFormat("int (^foo[kNumEntries + 10])(char, float);");
+  verifyFormat("int (^foo[(kNumEntries + 10)])(char, float);");
+}
+
 TEST_F(FormatTestObjC, ObjCSnippets) {
   verifyFormat("@autoreleasepool {\n"
"  foo();\n"
Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -12128,6 +12128,22 @@
   EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "[[foo::bar, ...]]"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithCaret) {
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^);"));
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^, Bar);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo[10])(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo[kNumEntries])(char, float);"));
+  EXPECT_EQ(
+  FormatStyle::LK_ObjC,
+  guessLanguage("foo.h", "int(^foo[(kNumEntries + 10)])(char, float);"));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -141,10 +141,7 @@
 Contexts.size() == 2 && Contexts[0].ColonIsForRangeExpr;
 
 bool StartsObjCMethodExpr = false;
-if (CurrentToken->is(tok::caret)) {
-  // (^ can start a block type.
-  Left->Type = TT_ObjCBlockLParen;
-} else if (FormatToken *MaybeSel = Left->Previous) {
+if (FormatToken *MaybeSel = Left->Previous) {
   // @selector( starts a selector.
   if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous 
&&
   MaybeSel->Previous->is(tok::at)) {
@@ -210,8 +207,16 @@
   Left->Type = TT_ObjCMethodExpr;
 }
 
+// MightBeFunctionType and ProbablyFunctionType are used for
+// function pointer and reference types as well as Objective-C
+// block types:
+//
+// void (*FunctionPointer)(void);
+// void ()(void);
+// void (^ObjCBlock)(void);
 bool MightBeFunctionType = !Contexts[Contexts.size() - 2].IsExpression;
-bool ProbablyFunctionType = CurrentToken->isOneOf(tok::star, tok::amp);
+bool ProbablyFunctionType =
+CurrentToken->isOneOf(tok::star, tok::amp, tok::caret);
 bool HasMultipleLines = false;
 bool HasMultipleParametersOnALine = false;
 bool MightBeObjCForRangeLoop =
@@ -248,7 +253,8 @@
 if (MightBeFunctionType && ProbablyFunctionType && CurrentToken->Next 
&&
 (CurrentToken->Next->is(tok::l_paren) ||
  (CurrentToken->Next->is(tok::l_square) && 
Line.MustBeDeclaration)))
-  Left->Type = TT_FunctionTypeLParen;
+  Left->Type = Left->Next->is(tok::caret) ? TT_ObjCBlockLParen
+  : TT_FunctionTypeLParen;
 Left->MatchingParen = CurrentToken;
 CurrentToken->MatchingParen = Left;
 


Index: unittests/Format/FormatTestObjC.cpp
===
--- unittests/Format/FormatTestObjC.cpp
+++ unittests/Format/FormatTestObjC.cpp
@@ -845,6 +845,15 @@
   verifyFormat("@ /*foo*/ interface");
 }
 
+TEST_F(FormatTestObjC, ObjCBlockTypesAndVariables) {
+  verifyFormat("void DoStuffWithBlockType(int (^)(char));");
+  verifyFormat("int (^foo)(char, float);");
+  verifyFormat("int (^foo[10])(char, float);");
+  verifyFormat("int (^foo[kNumEntries])(char, float);");
+  verifyFormat("int (^foo[kNumEntries + 10])(char, float);");
+  verifyFormat("int (^foo[(kNumEntries + 10)])(char, float);");
+}
+
 TEST_F(FormatTestObjC, ObjCSnippets) {
   verifyFormat("@autoreleasepool {\n"
"  foo();\n"
Index: unittests/Format/FormatTest.cpp
===
--- 

[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-12 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton marked an inline comment as done.
benhamilton added inline comments.



Comment at: lib/Format/TokenAnnotator.cpp:210
 
-bool MightBeFunctionType = !Contexts[Contexts.size() - 2].IsExpression;
-bool ProbablyFunctionType = CurrentToken->isOneOf(tok::star, tok::amp);
+bool MightBeFunctionOrObjCBlockType =
+!Contexts[Contexts.size() - 2].IsExpression;

djasper wrote:
> I'd suggest to put a comment here saying that this is for both ObjC blocks 
> and Function types, because they look very similar in nature (maybe giving 
> examples) and then not actually rename the variables. To me, the long names 
> make the code harder to read.
> 
> But if you feel strongly the other way, I'd be ok with it.
Restored old names and added comment.



Repository:
  rC Clang

https://reviews.llvm.org/D43906



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-08 Thread Daniel Jasper via Phabricator via cfe-commits
djasper accepted this revision.
djasper added a comment.
This revision is now accepted and ready to land.

Nice.. Removed a lot of complexity :). Let's see whether this heuristic is good 
enough.




Comment at: lib/Format/TokenAnnotator.cpp:210
 
-bool MightBeFunctionType = !Contexts[Contexts.size() - 2].IsExpression;
-bool ProbablyFunctionType = CurrentToken->isOneOf(tok::star, tok::amp);
+bool MightBeFunctionOrObjCBlockType =
+!Contexts[Contexts.size() - 2].IsExpression;

I'd suggest to put a comment here saying that this is for both ObjC blocks and 
Function types, because they look very similar in nature (maybe giving 
examples) and then not actually rename the variables. To me, the long names 
make the code harder to read.

But if you feel strongly the other way, I'd be ok with it.


Repository:
  rC Clang

https://reviews.llvm.org/D43906



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-07 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton added inline comments.



Comment at: lib/Format/TokenAnnotator.cpp:152
+  const FormatToken *Next = CurrentToken->getNextNonComment();
+  int ParenDepth = 1;
+  // Handle nested parens in case we have an array of blocks with

djasper wrote:
> No. Don't implement yet another parenthesis counting. This function already 
> iterates over all tokens until the closing paren. Just store a pointer to the 
> caret here and mark it (or unmark it) when encountering the closing brace 
> (line 271). There is already very similar logic there to set 
> TT_FunctionTypeLParen (which is actually doing the exact same parsing now 
> that I think of it).
Oh! Yes, re-using the logic for `TT_FunctionTypeLParen` is clearly the right 
thing to do, since it has exactly the same syntax (just `*` or `&` instead of 
`^`).

Done, code is much cleaner now.


Repository:
  rC Clang

https://reviews.llvm.org/D43906



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-07 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton updated this revision to Diff 137394.
benhamilton added a comment.

- Greatly clean up ObjC block type logic by re-using `TT_FunctionTypeLParen` 
type logic.


Repository:
  rC Clang

https://reviews.llvm.org/D43906

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTest.cpp
  unittests/Format/FormatTestObjC.cpp


Index: unittests/Format/FormatTestObjC.cpp
===
--- unittests/Format/FormatTestObjC.cpp
+++ unittests/Format/FormatTestObjC.cpp
@@ -845,6 +845,15 @@
   verifyFormat("@ /*foo*/ interface");
 }
 
+TEST_F(FormatTestObjC, ObjCBlockTypesAndVariables) {
+  verifyFormat("void DoStuffWithBlockType(int (^)(char));");
+  verifyFormat("int (^foo)(char, float);");
+  verifyFormat("int (^foo[10])(char, float);");
+  verifyFormat("int (^foo[kNumEntries])(char, float);");
+  verifyFormat("int (^foo[kNumEntries + 10])(char, float);");
+  verifyFormat("int (^foo[(kNumEntries + 10)])(char, float);");
+}
+
 TEST_F(FormatTestObjC, ObjCSnippets) {
   verifyFormat("@autoreleasepool {\n"
"  foo();\n"
Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -12128,6 +12128,22 @@
   EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "[[foo::bar, ...]]"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithCaret) {
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^);"));
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^, Bar);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo[10])(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo[kNumEntries])(char, float);"));
+  EXPECT_EQ(
+  FormatStyle::LK_ObjC,
+  guessLanguage("foo.h", "int(^foo[(kNumEntries + 10)])(char, float);"));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -141,10 +141,7 @@
 Contexts.size() == 2 && Contexts[0].ColonIsForRangeExpr;
 
 bool StartsObjCMethodExpr = false;
-if (CurrentToken->is(tok::caret)) {
-  // (^ can start a block type.
-  Left->Type = TT_ObjCBlockLParen;
-} else if (FormatToken *MaybeSel = Left->Previous) {
+if (FormatToken *MaybeSel = Left->Previous) {
   // @selector( starts a selector.
   if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous 
&&
   MaybeSel->Previous->is(tok::at)) {
@@ -210,8 +207,10 @@
   Left->Type = TT_ObjCMethodExpr;
 }
 
-bool MightBeFunctionType = !Contexts[Contexts.size() - 2].IsExpression;
-bool ProbablyFunctionType = CurrentToken->isOneOf(tok::star, tok::amp);
+bool MightBeFunctionOrObjCBlockType =
+!Contexts[Contexts.size() - 2].IsExpression;
+bool ProbablyFunctionOrObjCBlockType =
+CurrentToken->isOneOf(tok::star, tok::amp, tok::caret);
 bool HasMultipleLines = false;
 bool HasMultipleParametersOnALine = false;
 bool MightBeObjCForRangeLoop =
@@ -239,16 +238,18 @@
   if (CurrentToken->Previous->is(TT_PointerOrReference) &&
   CurrentToken->Previous->Previous->isOneOf(tok::l_paren,
 tok::coloncolon))
-ProbablyFunctionType = true;
+ProbablyFunctionOrObjCBlockType = true;
   if (CurrentToken->is(tok::comma))
-MightBeFunctionType = false;
+MightBeFunctionOrObjCBlockType = false;
   if (CurrentToken->Previous->is(TT_BinaryOperator))
 Contexts.back().IsExpression = true;
   if (CurrentToken->is(tok::r_paren)) {
-if (MightBeFunctionType && ProbablyFunctionType && CurrentToken->Next 
&&
+if (MightBeFunctionOrObjCBlockType && ProbablyFunctionOrObjCBlockType 
&&
+CurrentToken->Next &&
 (CurrentToken->Next->is(tok::l_paren) ||
  (CurrentToken->Next->is(tok::l_square) && 
Line.MustBeDeclaration)))
-  Left->Type = TT_FunctionTypeLParen;
+  Left->Type = Left->Next->is(tok::caret) ? TT_ObjCBlockLParen
+  : TT_FunctionTypeLParen;
 Left->MatchingParen = CurrentToken;
 CurrentToken->MatchingParen = Left;
 


Index: unittests/Format/FormatTestObjC.cpp
===
--- unittests/Format/FormatTestObjC.cpp
+++ unittests/Format/FormatTestObjC.cpp
@@ -845,6 +845,15 @@
   verifyFormat("@ /*foo*/ interface");
 }
 
+TEST_F(FormatTestObjC, ObjCBlockTypesAndVariables) {
+  verifyFormat("void 

[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-06 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton updated this revision to Diff 137320.
benhamilton added a comment.

Fix comment.


Repository:
  rC Clang

https://reviews.llvm.org/D43906

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTest.cpp
  unittests/Format/FormatTestObjC.cpp


Index: unittests/Format/FormatTestObjC.cpp
===
--- unittests/Format/FormatTestObjC.cpp
+++ unittests/Format/FormatTestObjC.cpp
@@ -845,6 +845,15 @@
   verifyFormat("@ /*foo*/ interface");
 }
 
+TEST_F(FormatTestObjC, ObjCBlockTypesAndVariables) {
+  verifyFormat("void DoStuffWithBlockType(int (^)(char));");
+  verifyFormat("int (^foo)(char, float);");
+  verifyFormat("int (^foo[10])(char, float);");
+  verifyFormat("int (^foo[kNumEntries])(char, float);");
+  verifyFormat("int (^foo[kNumEntries + 10])(char, float);");
+  verifyFormat("int (^foo[(kNumEntries + 10)])(char, float);");
+}
+
 TEST_F(FormatTestObjC, ObjCSnippets) {
   verifyFormat("@autoreleasepool {\n"
"  foo();\n"
Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -12128,6 +12128,22 @@
   EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "[[foo::bar, ...]]"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithCaret) {
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^);"));
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^, Bar);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo[10])(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo[kNumEntries])(char, float);"));
+  EXPECT_EQ(
+  FormatStyle::LK_ObjC,
+  guessLanguage("foo.h", "int(^foo[(kNumEntries + 10)])(char, float);"));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -142,8 +142,32 @@
 
 bool StartsObjCMethodExpr = false;
 if (CurrentToken->is(tok::caret)) {
-  // (^ can start a block type.
-  Left->Type = TT_ObjCBlockLParen;
+  // The following are valid ObjC block types and block variables:
+  //
+  // int (^)(char, float)
+  // int (^block)(char, float)
+  // int (^arrayOfTenBlocks[10])(char, float)
+  // int (^arrayOfManyBlocks[(kLen + 42)])(char, float)
+  const FormatToken *Next = CurrentToken->getNextNonComment();
+  int ParenDepth = 1;
+  // Handle nested parens in case we have an array of blocks with
+  // a parenthesized length.
+  while (Next) {
+if (Next->is(tok::l_paren))
+  ++ParenDepth;
+else if (Next->is(tok::r_paren))
+  --ParenDepth;
+if (ParenDepth == 0)
+  break;
+Next = Next->getNextNonComment();
+  }
+  if (Next) {
+const FormatToken *NextNext = Next->getNextNonComment();
+// If we have an opening paren at the end of (^...)( we assume
+// we have an Objective-C block.
+if (NextNext && NextNext->is(tok::l_paren))
+  Left->Type = TT_ObjCBlockLParen;
+  }
 } else if (FormatToken *MaybeSel = Left->Previous) {
   // @selector( starts a selector.
   if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous 
&&


Index: unittests/Format/FormatTestObjC.cpp
===
--- unittests/Format/FormatTestObjC.cpp
+++ unittests/Format/FormatTestObjC.cpp
@@ -845,6 +845,15 @@
   verifyFormat("@ /*foo*/ interface");
 }
 
+TEST_F(FormatTestObjC, ObjCBlockTypesAndVariables) {
+  verifyFormat("void DoStuffWithBlockType(int (^)(char));");
+  verifyFormat("int (^foo)(char, float);");
+  verifyFormat("int (^foo[10])(char, float);");
+  verifyFormat("int (^foo[kNumEntries])(char, float);");
+  verifyFormat("int (^foo[kNumEntries + 10])(char, float);");
+  verifyFormat("int (^foo[(kNumEntries + 10)])(char, float);");
+}
+
 TEST_F(FormatTestObjC, ObjCSnippets) {
   verifyFormat("@autoreleasepool {\n"
"  foo();\n"
Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -12128,6 +12128,22 @@
   EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "[[foo::bar, ...]]"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithCaret) {
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^);"));
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^, Bar);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", 

[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-06 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton added a comment.

> Right. So the difference is that for blocks, there is always a "(" after the 
> "(^.)". That should be easy to parse, no?

Yep, I've updated this diff to implement that as you recommended. I just had to 
handle nested parens (I couldn't find an existing way to deal with these so I 
wrote my own—let me know if I missed something.)


Repository:
  rC Clang

https://reviews.llvm.org/D43906



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-06 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton updated this revision to Diff 137319.
benhamilton added a comment.

- Simplify logic and assume we have an ObjC block whenever we see rparen at the 
end of `(^...)(`.


Repository:
  rC Clang

https://reviews.llvm.org/D43906

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTest.cpp
  unittests/Format/FormatTestObjC.cpp


Index: unittests/Format/FormatTestObjC.cpp
===
--- unittests/Format/FormatTestObjC.cpp
+++ unittests/Format/FormatTestObjC.cpp
@@ -845,6 +845,15 @@
   verifyFormat("@ /*foo*/ interface");
 }
 
+TEST_F(FormatTestObjC, ObjCBlockTypesAndVariables) {
+  verifyFormat("void DoStuffWithBlockType(int (^)(char));");
+  verifyFormat("int (^foo)(char, float);");
+  verifyFormat("int (^foo[10])(char, float);");
+  verifyFormat("int (^foo[kNumEntries])(char, float);");
+  verifyFormat("int (^foo[kNumEntries + 10])(char, float);");
+  verifyFormat("int (^foo[(kNumEntries + 10)])(char, float);");
+}
+
 TEST_F(FormatTestObjC, ObjCSnippets) {
   verifyFormat("@autoreleasepool {\n"
"  foo();\n"
Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -12128,6 +12128,22 @@
   EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "[[foo::bar, ...]]"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithCaret) {
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^);"));
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^, Bar);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo[10])(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo[kNumEntries])(char, float);"));
+  EXPECT_EQ(
+  FormatStyle::LK_ObjC,
+  guessLanguage("foo.h", "int(^foo[(kNumEntries + 10)])(char, float);"));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -142,8 +142,32 @@
 
 bool StartsObjCMethodExpr = false;
 if (CurrentToken->is(tok::caret)) {
-  // (^ can start a block type.
-  Left->Type = TT_ObjCBlockLParen;
+  // The following are valid block ObjC types and block variables:
+  //
+  // int (^)(char, float)
+  // int (^block)(char, float)
+  // int (^arrayOfTenBlocks[10])(char, float)
+  // int (^arrayOfManyBlocks[(kLen + 42)])(char, float)
+  const FormatToken *Next = CurrentToken->getNextNonComment();
+  int ParenDepth = 1;
+  // Handle nested parens in case we have an array of blocks with
+  // a parenthesized length.
+  while (Next) {
+if (Next->is(tok::l_paren))
+  ++ParenDepth;
+else if (Next->is(tok::r_paren))
+  --ParenDepth;
+if (ParenDepth == 0)
+  break;
+Next = Next->getNextNonComment();
+  }
+  if (Next) {
+const FormatToken *NextNext = Next->getNextNonComment();
+// If we have an opening paren at the end of (^...)( we assume
+// we have an Objective-C block.
+if (NextNext && NextNext->is(tok::l_paren))
+  Left->Type = TT_ObjCBlockLParen;
+  }
 } else if (FormatToken *MaybeSel = Left->Previous) {
   // @selector( starts a selector.
   if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous 
&&


Index: unittests/Format/FormatTestObjC.cpp
===
--- unittests/Format/FormatTestObjC.cpp
+++ unittests/Format/FormatTestObjC.cpp
@@ -845,6 +845,15 @@
   verifyFormat("@ /*foo*/ interface");
 }
 
+TEST_F(FormatTestObjC, ObjCBlockTypesAndVariables) {
+  verifyFormat("void DoStuffWithBlockType(int (^)(char));");
+  verifyFormat("int (^foo)(char, float);");
+  verifyFormat("int (^foo[10])(char, float);");
+  verifyFormat("int (^foo[kNumEntries])(char, float);");
+  verifyFormat("int (^foo[kNumEntries + 10])(char, float);");
+  verifyFormat("int (^foo[(kNumEntries + 10)])(char, float);");
+}
+
 TEST_F(FormatTestObjC, ObjCSnippets) {
   verifyFormat("@autoreleasepool {\n"
"  foo();\n"
Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -12128,6 +12128,22 @@
   EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "[[foo::bar, ...]]"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithCaret) {
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^);"));
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", 

[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-06 Thread Daniel Jasper via Phabricator via cfe-commits
djasper added a comment.

Right. So the difference is that for blocks, there is always a "(" after the 
"(^.)". That should be easy to parse, no?


Repository:
  rC Clang

https://reviews.llvm.org/D43906



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-06 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton added inline comments.



Comment at: lib/Format/TokenAnnotator.cpp:155
+   Next->startsSequence(tok::identifier, tok::l_square,
+tok::numeric_constant, tok::r_square,
+tok::r_paren, tok::l_paren))) {

djasper wrote:
> benhamilton wrote:
> > benhamilton wrote:
> > > djasper wrote:
> > > > benhamilton wrote:
> > > > > djasper wrote:
> > > > > > This seems suspect. Does it have to be a numeric_constant?
> > > > > Probably not, any constexpr would do, I suspect. What's the best way 
> > > > > to parse that?
> > > > I think this is the same answer for both of your questions. If what you 
> > > > are trying to prevent "FOO(^)" to be parsed as a block, wouldn't it be 
> > > > enough to look for whether there is a "(" after the ")" or even only 
> > > > after "(^)", everything else is already correct IIUC? That would get 
> > > > you out of need to parse the specifics here, which will be hard.
> > > > 
> > > > Or thinking about it another way. Previously, every "(^" would be 
> > > > parsed as an ObjC block. There seems to be only a really rare corner 
> > > > case in which it isn't (macros). Thus, I'd just try to detect that 
> > > > corner case. Instead you are completely inverting the defaults 
> > > > (defaulting to "^" is not a block) and then try to exactly parse ObjC 
> > > > where there might be many cases and edge cases that you won't even 
> > > > think of now.
> > > Hmm. Well, it's not just `FOO(^);` that isn't a block:
> > > 
> > > ```
> > > #define FOO(X) operator X
> > > 
> > > SomeType FOO(^)(int x, const SomeType& y) { ... }
> > > ```
> > > 
> > > Obviously we can't get this perfect without a pre-processor, but it seems 
> > > like our best bet is to only assign mark `TT_ObjCBlockLParen` when we are 
> > > sure the syntax is a valid block type or block variable.
> > I tried the suggestion to only treat `(^)(` as a block type, but it appears 
> > this is the primary place where we set `TT_ObjCBlockLParen`, so I think we 
> > really do need to handle the other cases here.
> I don't follow your logic. I'd like you to slowly change this as opposed to 
> completely going the opposite way.
> 
> So currently, the only know real-live problem is "FOO(^);". So address this 
> somehow, but still default/error to recognizing too much stuff as a block.
> 
> Have you actually seen
> 
>   SomeType FOO(^)(int x, const SomeType& y) { ... }
> 
> in real code?
I haven't seen that example, but I have seen `FOO(^, OtherParam);`.

I'm trying to change the parser to handle this now without explicitly parsing 
all block types, but it's tricky. The following should be ObjC block types:

```
(^)(int, char);
(^foo)(int, char);
(^foo[10])(int, char);
(^foo[kNum])(int, char);
(^foo[(kNum + kOtherNum)])(int, char);
```

but the following should not:

```
FOO(^);
FOO(^, int, char);
```

I'll make it work, it's just easy to make a mistake.


Repository:
  rC Clang

https://reviews.llvm.org/D43906



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-06 Thread Daniel Jasper via Phabricator via cfe-commits
djasper added inline comments.



Comment at: lib/Format/TokenAnnotator.cpp:155
+   Next->startsSequence(tok::identifier, tok::l_square,
+tok::numeric_constant, tok::r_square,
+tok::r_paren, tok::l_paren))) {

benhamilton wrote:
> benhamilton wrote:
> > djasper wrote:
> > > benhamilton wrote:
> > > > djasper wrote:
> > > > > This seems suspect. Does it have to be a numeric_constant?
> > > > Probably not, any constexpr would do, I suspect. What's the best way to 
> > > > parse that?
> > > I think this is the same answer for both of your questions. If what you 
> > > are trying to prevent "FOO(^)" to be parsed as a block, wouldn't it be 
> > > enough to look for whether there is a "(" after the ")" or even only 
> > > after "(^)", everything else is already correct IIUC? That would get you 
> > > out of need to parse the specifics here, which will be hard.
> > > 
> > > Or thinking about it another way. Previously, every "(^" would be parsed 
> > > as an ObjC block. There seems to be only a really rare corner case in 
> > > which it isn't (macros). Thus, I'd just try to detect that corner case. 
> > > Instead you are completely inverting the defaults (defaulting to "^" is 
> > > not a block) and then try to exactly parse ObjC where there might be many 
> > > cases and edge cases that you won't even think of now.
> > Hmm. Well, it's not just `FOO(^);` that isn't a block:
> > 
> > ```
> > #define FOO(X) operator X
> > 
> > SomeType FOO(^)(int x, const SomeType& y) { ... }
> > ```
> > 
> > Obviously we can't get this perfect without a pre-processor, but it seems 
> > like our best bet is to only assign mark `TT_ObjCBlockLParen` when we are 
> > sure the syntax is a valid block type or block variable.
> I tried the suggestion to only treat `(^)(` as a block type, but it appears 
> this is the primary place where we set `TT_ObjCBlockLParen`, so I think we 
> really do need to handle the other cases here.
I don't follow your logic. I'd like you to slowly change this as opposed to 
completely going the opposite way.

So currently, the only know real-live problem is "FOO(^);". So address this 
somehow, but still default/error to recognizing too much stuff as a block.

Have you actually seen

  SomeType FOO(^)(int x, const SomeType& y) { ... }

in real code?


Repository:
  rC Clang

https://reviews.llvm.org/D43906



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-06 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton added inline comments.



Comment at: lib/Format/TokenAnnotator.cpp:155
+   Next->startsSequence(tok::identifier, tok::l_square,
+tok::numeric_constant, tok::r_square,
+tok::r_paren, tok::l_paren))) {

benhamilton wrote:
> djasper wrote:
> > benhamilton wrote:
> > > djasper wrote:
> > > > This seems suspect. Does it have to be a numeric_constant?
> > > Probably not, any constexpr would do, I suspect. What's the best way to 
> > > parse that?
> > I think this is the same answer for both of your questions. If what you are 
> > trying to prevent "FOO(^)" to be parsed as a block, wouldn't it be enough 
> > to look for whether there is a "(" after the ")" or even only after "(^)", 
> > everything else is already correct IIUC? That would get you out of need to 
> > parse the specifics here, which will be hard.
> > 
> > Or thinking about it another way. Previously, every "(^" would be parsed as 
> > an ObjC block. There seems to be only a really rare corner case in which it 
> > isn't (macros). Thus, I'd just try to detect that corner case. Instead you 
> > are completely inverting the defaults (defaulting to "^" is not a block) 
> > and then try to exactly parse ObjC where there might be many cases and edge 
> > cases that you won't even think of now.
> Hmm. Well, it's not just `FOO(^);` that isn't a block:
> 
> ```
> #define FOO(X) operator X
> 
> SomeType FOO(^)(int x, const SomeType& y) { ... }
> ```
> 
> Obviously we can't get this perfect without a pre-processor, but it seems 
> like our best bet is to only assign mark `TT_ObjCBlockLParen` when we are 
> sure the syntax is a valid block type or block variable.
I tried the suggestion to only treat `(^)(` as a block type, but it appears 
this is the primary place where we set `TT_ObjCBlockLParen`, so I think we 
really do need to handle the other cases here.


Repository:
  rC Clang

https://reviews.llvm.org/D43906



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-06 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton added inline comments.



Comment at: lib/Format/TokenAnnotator.cpp:155
+   Next->startsSequence(tok::identifier, tok::l_square,
+tok::numeric_constant, tok::r_square,
+tok::r_paren, tok::l_paren))) {

djasper wrote:
> benhamilton wrote:
> > djasper wrote:
> > > This seems suspect. Does it have to be a numeric_constant?
> > Probably not, any constexpr would do, I suspect. What's the best way to 
> > parse that?
> I think this is the same answer for both of your questions. If what you are 
> trying to prevent "FOO(^)" to be parsed as a block, wouldn't it be enough to 
> look for whether there is a "(" after the ")" or even only after "(^)", 
> everything else is already correct IIUC? That would get you out of need to 
> parse the specifics here, which will be hard.
> 
> Or thinking about it another way. Previously, every "(^" would be parsed as 
> an ObjC block. There seems to be only a really rare corner case in which it 
> isn't (macros). Thus, I'd just try to detect that corner case. Instead you 
> are completely inverting the defaults (defaulting to "^" is not a block) and 
> then try to exactly parse ObjC where there might be many cases and edge cases 
> that you won't even think of now.
Hmm. Well, it's not just `FOO(^);` that isn't a block:

```
#define FOO(X) operator X

SomeType FOO(^)(int x, const SomeType& y) { ... }
```

Obviously we can't get this perfect without a pre-processor, but it seems like 
our best bet is to only assign mark `TT_ObjCBlockLParen` when we are sure the 
syntax is a valid block type or block variable.


Repository:
  rC Clang

https://reviews.llvm.org/D43906



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-06 Thread Daniel Jasper via Phabricator via cfe-commits
djasper added inline comments.



Comment at: lib/Format/TokenAnnotator.cpp:155
+   Next->startsSequence(tok::identifier, tok::l_square,
+tok::numeric_constant, tok::r_square,
+tok::r_paren, tok::l_paren))) {

benhamilton wrote:
> djasper wrote:
> > This seems suspect. Does it have to be a numeric_constant?
> Probably not, any constexpr would do, I suspect. What's the best way to parse 
> that?
I think this is the same answer for both of your questions. If what you are 
trying to prevent "FOO(^)" to be parsed as a block, wouldn't it be enough to 
look for whether there is a "(" after the ")" or even only after "(^)", 
everything else is already correct IIUC? That would get you out of need to 
parse the specifics here, which will be hard.

Or thinking about it another way. Previously, every "(^" would be parsed as an 
ObjC block. There seems to be only a really rare corner case in which it isn't 
(macros). Thus, I'd just try to detect that corner case. Instead you are 
completely inverting the defaults (defaulting to "^" is not a block) and then 
try to exactly parse ObjC where there might be many cases and edge cases that 
you won't even think of now.


Repository:
  rC Clang

https://reviews.llvm.org/D43906



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-06 Thread Krasimir Georgiev via Phabricator via cfe-commits
krasimir added inline comments.



Comment at: unittests/Format/FormatTest.cpp:7698
 
+TEST_F(FormatTest, ObjCBlockTypesAndVariables) {
+  verifyFormat("void DoStuffWithBlockType(int (^)(char));");

This should be in `FormatTestObjC.cpp`.


Repository:
  rC Clang

https://reviews.llvm.org/D43906



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-05 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton added a comment.

> Would it be enough to only add the block type case? With the macro false 
> positive, there won't be an open paren after the closing paren, right?

Are you asking to remove the block variable cases? I was concerned those would 
no longer be handled correctly if we don't explicitly check for them.

What change are you suggesting if we remove the block variable cases to handle 
those?




Comment at: lib/Format/TokenAnnotator.cpp:155
+   Next->startsSequence(tok::identifier, tok::l_square,
+tok::numeric_constant, tok::r_square,
+tok::r_paren, tok::l_paren))) {

djasper wrote:
> This seems suspect. Does it have to be a numeric_constant?
Probably not, any constexpr would do, I suspect. What's the best way to parse 
that?



Comment at: unittests/Format/FormatTest.cpp:12027
 
+TEST_F(FormatTest, GuessLanguageWithCaret) {
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^);"));

krasimir wrote:
> Please also add formatting tests. This might require changes to the 
> formatting logic since I'd intuitively expect ``int(^)(char)`` to be 
> formatted as ``int (^)(char)``.
Added formatting tests. Tests passed with no changes to the formatting logic, 
and your intuition was correct.



Comment at: unittests/Format/FormatTest.cpp:12029
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^)(char, float);"));

djasper wrote:
> I am somewhat skeptical about all these tests now being solely about 
> guessLanguage. It might be the best choice for some of them, but also, there 
> might be other things we do to detect ObjC at some point and then all of 
> these tests become meaningless.
> 
> Does your change create a different formatting here?
I hear you. I just want to make sure the false positive case doesn't regress, 
and we don't lose the functionality of detecting ObjC for block types.

Added formatting tests.


Repository:
  rC Clang

https://reviews.llvm.org/D43906



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-05 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton updated this revision to Diff 137095.
benhamilton marked 2 inline comments as done.
benhamilton added a comment.

- Fix comments from @djasper and @krasimir.


Repository:
  rC Clang

https://reviews.llvm.org/D43906

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTest.cpp


Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -7695,6 +7695,11 @@
   verifyGoogleFormat("- foo:(int)foo;");
 }
 
+TEST_F(FormatTest, ObjCBlockTypesAndVariables) {
+  verifyFormat("void DoStuffWithBlockType(int (^)(char));");
+  verifyFormat("int (^foo)(char, float);");
+  verifyFormat("int (^foo[10])(char, float);");
+}
 
 TEST_F(FormatTest, BreaksStringLiterals) {
   EXPECT_EQ("\"some text \"\n"
@@ -12159,6 +12164,16 @@
   "for (const Foo& baz = in.value(); !baz.at_end(); ++baz) {}"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithCaret) {
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo[10])(char, float);"));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -142,8 +142,20 @@
 
 bool StartsObjCMethodExpr = false;
 if (CurrentToken->is(tok::caret)) {
-  // (^ can start a block type.
-  Left->Type = TT_ObjCBlockLParen;
+  const FormatToken *Next = CurrentToken->getNextNonComment();
+  if (Next &&
+  // int (^)(char, float)
+  (Next->startsSequence(tok::r_paren, tok::l_paren) ||
+   // int (^blockReturningIntWithCharAndFloatArguments)(char, float)
+   Next->startsSequence(tok::identifier, tok::r_paren, tok::l_paren) ||
+   // int
+   // 
(^arrayOfTenBlocksReturningIntWithCharAndFloatArguments[10])(char,
+   // float)
+   Next->startsSequence(tok::identifier, tok::l_square,
+tok::numeric_constant, tok::r_square,
+tok::r_paren, tok::l_paren))) {
+Left->Type = TT_ObjCBlockLParen;
+  }
 } else if (FormatToken *MaybeSel = Left->Previous) {
   // @selector( starts a selector.
   if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous 
&&


Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -7695,6 +7695,11 @@
   verifyGoogleFormat("- foo:(int)foo;");
 }
 
+TEST_F(FormatTest, ObjCBlockTypesAndVariables) {
+  verifyFormat("void DoStuffWithBlockType(int (^)(char));");
+  verifyFormat("int (^foo)(char, float);");
+  verifyFormat("int (^foo[10])(char, float);");
+}
 
 TEST_F(FormatTest, BreaksStringLiterals) {
   EXPECT_EQ("\"some text \"\n"
@@ -12159,6 +12164,16 @@
   "for (const Foo& baz = in.value(); !baz.at_end(); ++baz) {}"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithCaret) {
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo[10])(char, float);"));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -142,8 +142,20 @@
 
 bool StartsObjCMethodExpr = false;
 if (CurrentToken->is(tok::caret)) {
-  // (^ can start a block type.
-  Left->Type = TT_ObjCBlockLParen;
+  const FormatToken *Next = CurrentToken->getNextNonComment();
+  if (Next &&
+  // int (^)(char, float)
+  (Next->startsSequence(tok::r_paren, tok::l_paren) ||
+   // int (^blockReturningIntWithCharAndFloatArguments)(char, float)
+   Next->startsSequence(tok::identifier, tok::r_paren, tok::l_paren) ||
+   // int
+   // (^arrayOfTenBlocksReturningIntWithCharAndFloatArguments[10])(char,
+   // float)
+   Next->startsSequence(tok::identifier, tok::l_square,
+tok::numeric_constant, tok::r_square,
+tok::r_paren, tok::l_paren))) {
+Left->Type = TT_ObjCBlockLParen;
+  }
 } else if (FormatToken *MaybeSel = Left->Previous) {
   // @selector( starts a 

[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-05 Thread Daniel Jasper via Phabricator via cfe-commits
djasper added a comment.

Would it be enough to only add the block type case? With the macro false 
positive, there won't be an open paren after the closing paren, right?




Comment at: lib/Format/TokenAnnotator.cpp:155
+   Next->startsSequence(tok::identifier, tok::l_square,
+tok::numeric_constant, tok::r_square,
+tok::r_paren, tok::l_paren))) {

This seems suspect. Does it have to be a numeric_constant?



Comment at: unittests/Format/FormatTest.cpp:12029
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^)(char, float);"));

I am somewhat skeptical about all these tests now being solely about 
guessLanguage. It might be the best choice for some of them, but also, there 
might be other things we do to detect ObjC at some point and then all of these 
tests become meaningless.

Does your change create a different formatting here?


Repository:
  rC Clang

https://reviews.llvm.org/D43906



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-03-05 Thread Krasimir Georgiev via Phabricator via cfe-commits
krasimir added inline comments.



Comment at: unittests/Format/FormatTest.cpp:12027
 
+TEST_F(FormatTest, GuessLanguageWithCaret) {
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^);"));

Please also add formatting tests. This might require changes to the formatting 
logic since I'd intuitively expect ``int(^)(char)`` to be formatted as ``int 
(^)(char)``.


Repository:
  rC Clang

https://reviews.llvm.org/D43906



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43906: [clang-format] Improve detection of Objective-C block types

2018-02-28 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton created this revision.
benhamilton added reviewers: krasimir, jolesiak.
Herald added a subscriber: cfe-commits.

Previously, clang-format would detect the following as an
Objective-C block type:

  FOO(^);

when it actually must be a C or C++ macro dealing with an XOR
statement or an XOR operator overload.

According to the Clang Block Language Spec:

https://clang.llvm.org/docs/BlockLanguageSpec.html

block types are of the form:

  int (^)(char, float)

and block variables of block type are of the form:

  void (^blockReturningVoidWithVoidArgument)(void);
  int (^blockReturningIntWithIntAndCharArguments)(int, char);
  void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);

This tightens up the detection so we don't unnecessarily detect
C macros which pass in the XOR operator.

Depends On https://reviews.llvm.org/D43904

Test Plan: New tests added. Ran tests with:

  make -j12 FormatTests &&
  ./tools/clang/unittests/Format/FormatTests


Repository:
  rC Clang

https://reviews.llvm.org/D43906

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTest.cpp


Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -12024,6 +12024,16 @@
   "for (const Foo& baz = in.value(); !baz.at_end(); ++baz) {}"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithCaret) {
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo[10])(char, float);"));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -142,8 +142,20 @@
 
 bool StartsObjCMethodExpr = false;
 if (CurrentToken->is(tok::caret)) {
-  // (^ can start a block type.
-  Left->Type = TT_ObjCBlockLParen;
+  const FormatToken *Next = CurrentToken->getNextNonComment();
+  if (Next &&
+  // int (^)(char, float)
+  (Next->startsSequence(tok::r_paren, tok::l_paren) ||
+   // int (^blockReturningIntWithCharAndFloatArguments)(char, float)
+   Next->startsSequence(tok::identifier, tok::r_paren, tok::l_paren) ||
+   // int
+   // 
(^arrayOfTenBlocksReturningIntWithCharAndFloatArguments[10])(char,
+   // float)
+   Next->startsSequence(tok::identifier, tok::l_square,
+tok::numeric_constant, tok::r_square,
+tok::r_paren, tok::l_paren))) {
+Left->Type = TT_ObjCBlockLParen;
+  }
 } else if (FormatToken *MaybeSel = Left->Previous) {
   // @selector( starts a selector.
   if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous 
&&


Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -12024,6 +12024,16 @@
   "for (const Foo& baz = in.value(); !baz.at_end(); ++baz) {}"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithCaret) {
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo)(char, float);"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "int(^foo[10])(char, float);"));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -142,8 +142,20 @@
 
 bool StartsObjCMethodExpr = false;
 if (CurrentToken->is(tok::caret)) {
-  // (^ can start a block type.
-  Left->Type = TT_ObjCBlockLParen;
+  const FormatToken *Next = CurrentToken->getNextNonComment();
+  if (Next &&
+  // int (^)(char, float)
+  (Next->startsSequence(tok::r_paren, tok::l_paren) ||
+   // int (^blockReturningIntWithCharAndFloatArguments)(char, float)
+   Next->startsSequence(tok::identifier, tok::r_paren, tok::l_paren) ||
+   // int
+   // (^arrayOfTenBlocksReturningIntWithCharAndFloatArguments[10])(char,
+   // float)
+   Next->startsSequence(tok::identifier, tok::l_square,
+tok::numeric_constant, tok::r_square,
+tok::r_paren, tok::l_paren))) {
+Left->Type = TT_ObjCBlockLParen;
+  }