]> granicus.if.org Git - clang/commitdiff
First step towards correctly formatting lambdas.
authorManuel Klimek <klimek@google.com>
Tue, 3 Sep 2013 15:10:01 +0000 (15:10 +0000)
committerManuel Klimek <klimek@google.com>
Tue, 3 Sep 2013 15:10:01 +0000 (15:10 +0000)
Implements parsing of lambdas in the UnwrappedLineParser.
This introduces the correct line breaks; the formatting of
lambda captures are still incorrect, and the braces are also
still formatted as if they were braced init lists instead of
blocks.

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

lib/Format/UnwrappedLineParser.cpp
lib/Format/UnwrappedLineParser.h
unittests/Format/FormatTest.cpp

index a149c185aa8a4e02c9df810a0cb5e12685e51867..253dbf97fdc6ce693dbfd39cd4d8488c6694b7b4 100644 (file)
@@ -640,6 +640,9 @@ void UnwrappedLineParser::parseStructuralElement() {
         parseBracedList();
       }
       break;
+    case tok::l_square:
+      tryToParseLambda();
+      break;
     default:
       nextToken();
       break;
@@ -647,6 +650,77 @@ void UnwrappedLineParser::parseStructuralElement() {
   } while (!eof());
 }
 
+void UnwrappedLineParser::tryToParseLambda() {
+  if (!tryToParseLambdaIntroducer()) {
+    return;
+  }
+  if (FormatTok->is(tok::l_paren)) {
+    parseParens();
+  }
+
+  while (FormatTok->isNot(tok::l_brace)) {
+    switch (FormatTok->Tok.getKind()) {
+      case tok::l_brace:
+        break;
+        return;
+      case tok::l_paren:
+        parseParens();
+        break;
+      case tok::semi:
+      case tok::equal:
+      case tok::eof:
+        return;
+      default:
+        nextToken();
+        break;
+    }
+  }
+  nextToken();
+  {
+    ScopedLineState LineState(*this);
+    ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
+                                            /*MustBeDeclaration=*/false);
+    Line->Level += 1;
+    parseLevel(/*HasOpeningBrace=*/true);
+    Line->Level -= 1;
+  }
+  nextToken();
+}
+
+bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
+  nextToken();
+  if (FormatTok->is(tok::equal)) {
+    nextToken();
+    if (FormatTok->is(tok::r_square)) return true;
+    if (FormatTok->isNot(tok::comma)) return false;
+    nextToken();
+  } else if (FormatTok->is(tok::amp)) {
+    nextToken();
+    if (FormatTok->is(tok::r_square)) return true;
+    if (!FormatTok->isOneOf(tok::comma, tok::identifier)) {
+      return false;
+    }
+    if (FormatTok->is(tok::comma)) nextToken();
+  } else if (FormatTok->is(tok::r_square)) {
+    nextToken();
+    return true;
+  }
+  do {
+    if (FormatTok->is(tok::amp)) nextToken();
+    if (!FormatTok->isOneOf(tok::identifier, tok::kw_this)) return false;
+    nextToken();
+    if (FormatTok->is(tok::comma)) {
+      nextToken();
+    } else if (FormatTok->is(tok::r_square)) {
+      nextToken();
+      return true;
+    } else {
+      return false;
+    }
+  } while (!eof());
+  return false;
+}
+
 bool UnwrappedLineParser::tryToParseBracedList() {
   if (FormatTok->BlockKind == BK_Unknown)
     calculateBraceTypes();
@@ -667,6 +741,9 @@ void UnwrappedLineParser::parseBracedList() {
     // here, otherwise our bail-out scenarios below break. The better solution
     // might be to just implement a more or less complete expression parser.
     switch (FormatTok->Tok.getKind()) {
+      case tok::l_square:
+        tryToParseLambda();
+        break;
     case tok::l_brace:
       parseBracedList();
       break;
@@ -710,6 +787,9 @@ void UnwrappedLineParser::parseReturn() {
       nextToken();
       addUnwrappedLine();
       return;
+    case tok::l_square:
+      tryToParseLambda();
+      break;
     default:
       nextToken();
       break;
index d23d157cccdedead869241a0f41fb22156b18f48..4660b1dbac255f9139ac4fbecf18f8ff8c6571b1 100644 (file)
@@ -93,6 +93,8 @@ private:
   void parseObjCUntilAtEnd();
   void parseObjCInterfaceOrImplementation();
   void parseObjCProtocol();
+  void tryToParseLambda();
+  bool tryToParseLambdaIntroducer();
   void addUnwrappedLine();
   bool eof() const;
   void nextToken();
index bdbc1555e4282c4881a7bdba1c462efa637991e7..e9bf2c54fd3f0633586d8de0fc9c127575e1ff78 100644 (file)
@@ -3681,7 +3681,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
   verifyGoogleFormat("return sizeof(int**);");
   verifyIndependentOfContext("Type **A = static_cast<Type **>(P);");
   verifyGoogleFormat("Type** A = static_cast<Type**>(P);");
-  verifyFormat("auto a = [](int **&, int ***) {};");
+  verifyFormat("auto a = [](int **&, int ***) {\n};");
 
   verifyIndependentOfContext("InvalidRegions[*R] = 0;");
 
@@ -3865,7 +3865,7 @@ TEST_F(FormatTest, FormatsCasts) {
   verifyFormat("f(foo).b;");
   verifyFormat("f(foo)(b);");
   verifyFormat("f(foo)[b];");
-  verifyFormat("[](foo) { return 4; }(bar)];");
+  verifyFormat("[](foo) {\n  return 4;\n}(bar);");
   verifyFormat("(*funptr)(foo)[4];");
   verifyFormat("funptrs[4](foo)[4];");
   verifyFormat("void f(int *);");
@@ -6257,5 +6257,45 @@ TEST_F(FormatTest, FormatsProtocolBufferDefinitions) {
                "}");
 }
 
+TEST_F(FormatTest, FormatsLambdas) {
+  // FIXME: The formatting is incorrect; this test currently checks that
+  // parsing of the unwrapped lines doesn't regress.
+  verifyFormat(
+      "int c = [b]() mutable {\n"
+      "  return [&b]{\n"
+      "    return b++;\n"
+      "  }();\n"
+      "}();\n");
+  verifyFormat(
+      "int c = [&]{\n"
+      "  [ = ]{\n"
+      "    return b++;\n"
+      "  }();\n"
+      "}();\n");
+  verifyFormat(
+      "int c = [ &, &a, a]{\n"
+      "  [ =, c, &d]{\n"
+      "    return b++;\n"
+      "  }();\n"
+      "}();\n");
+  verifyFormat(
+      "int c = [&a, &a, a]{\n"
+      "  [ =, a, b, &c]{\n"
+      "    return b++;\n"
+      "  }();\n"
+      "}();\n");
+  verifyFormat(
+      "auto c = {[&a, &a, a]{\n"
+      "  [ =, a, b, &c]{\n"
+      "    return b++;\n"
+      "  }();\n"
+      "} }\n");
+  verifyFormat(
+      "auto c = {[&a, &a, a]{\n"
+      "  [ =, a, b, &c]{\n"
+      "  }();\n"
+      "} }\n");
+}
+
 } // end namespace tooling
 } // end namespace clang