[clang-format/ObjC] Do not detect "[]" as ObjC method expression
authorBen Hamilton <benhamilton@google.com>
Tue, 3 Apr 2018 14:07:11 +0000 (14:07 +0000)
committerBen Hamilton <benhamilton@google.com>
Tue, 3 Apr 2018 14:07:11 +0000 (14:07 +0000)
Summary:
The following C++ code was being detected by
`guessLanguage()` as Objective-C:

  #define FOO(...) auto bar = [] __VA_ARGS__;

This was because `[] __VA_ARGS__` is not currently detected as a C++
lambda expression (it has no parens or braces), so
`TokenAnnotator::parseSquare()` incorrectly treats the opening square
as an ObjC method expression.

We have two options to fix this:

1. Parse `[] __VA_ARGS__` explicitly as a C++ lambda
2. Make it so `[]` is never parsed as an Objective-C method expression

This diff implements option 2, which causes the `[` to be parsed
as `TT_ArraySubscriptLSquare` instead of `TT_ObjCMethodExpr`.

Note that when I fixed this, it caused one change in formatting
behavior, where the following was implicitly relying on the `[`
being parsed as `TT_ObjCMethodExpr`:

  A<int * []> a;

becomes:

  A<int *[]> a;

with `Style.PointerAlignment = Middle`.

I don't really know what the desired format is for this syntax; the
test was added by Janusz Sobczak and integrated by @djasper in
https://github.com/llvm-mirror/clang/commit/b511fe9818829d7ece0cc0b2ce1fbe04a1f0739a
.

I went ahead and changed the test for now.

Test Plan: New tests added. Ran tests with:
  % make -j12 FormatTests && ./tools/clang/unittests/Format/FormatTests

Fixes: https://bugs.llvm.org/show_bug.cgi?id=36248

Reviewers: djasper, jolesiak

Reviewed By: djasper

Subscribers: klimek, cfe-commits, djasper

Differential Revision: https://reviews.llvm.org/D45169

llvm-svn: 329070

clang/lib/Format/TokenAnnotator.cpp
clang/unittests/Format/FormatTest.cpp

index 038121e..cdf921c 100644 (file)
@@ -386,7 +386,7 @@ private:
     bool StartsObjCMethodExpr =
         !CppArrayTemplates && Style.isCpp() && !IsCpp11AttributeSpecifier &&
         Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) &&
-        CurrentToken->isNot(tok::l_brace) &&
+        !CurrentToken->isOneOf(tok::l_brace, tok::r_square) &&
         (!Parent ||
          Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
                          tok::kw_return, tok::kw_throw) ||
index 819ab3c..2d20bc0 100644 (file)
@@ -6035,6 +6035,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
   PointerMiddle.PointerAlignment = FormatStyle::PAS_Middle;
   verifyFormat("delete *x;", PointerMiddle);
   verifyFormat("int * x;", PointerMiddle);
+  verifyFormat("int *[] x;", PointerMiddle);
   verifyFormat("template <int * y> f() {}", PointerMiddle);
   verifyFormat("int * f(int * a) {}", PointerMiddle);
   verifyFormat("int main(int argc, char ** argv) {}", PointerMiddle);
@@ -6042,7 +6043,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
   verifyFormat("A<int *> a;", PointerMiddle);
   verifyFormat("A<int **> a;", PointerMiddle);
   verifyFormat("A<int *, int *> a;", PointerMiddle);
-  verifyFormat("A<int * []> a;", PointerMiddle);
+  verifyFormat("A<int *[]> a;", PointerMiddle);
   verifyFormat("A = new SomeType *[Length]();", PointerMiddle);
   verifyFormat("A = new SomeType *[Length];", PointerMiddle);
   verifyFormat("T ** t = new T *;", PointerMiddle);
@@ -12106,6 +12107,9 @@ TEST_F(FormatTest, FileAndCode) {
       FormatStyle::LK_ObjC,
       guessLanguage("foo.h",
                     "#define MY_POINT_MAKE(x, y) CGPointMake((x), (y));\n"));
+  EXPECT_EQ(
+      FormatStyle::LK_Cpp,
+      guessLanguage("foo.h", "#define FOO(...) auto bar = [] __VA_ARGS__;"));
 }
 
 TEST_F(FormatTest, GuessLanguageWithCpp11AttributeSpecifiers) {