Fix layout of blocks inside statements.
authorManuel Klimek <klimek@google.com>
Thu, 10 Jan 2013 11:52:21 +0000 (11:52 +0000)
committerManuel Klimek <klimek@google.com>
Thu, 10 Jan 2013 11:52:21 +0000 (11:52 +0000)
Previously, we would not indent:
SOME_MACRO({
  int i;
});
correctly. This is fixed by adding the trailing }); to the unwrapped
line starting with SOME_MACRO({, so the formatter can correctly match
the braces and indent accordingly.

Also fixes incorrect parsing of initializer lists, like:
int a[] = { 1 };

llvm-svn: 172058

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

index dfb43af..00a4b77 100644 (file)
@@ -279,7 +279,9 @@ private:
 
     if (Newline) {
       unsigned WhitespaceStartColumn = State.Column;
-      if (Previous.is(tok::l_brace)) {
+      if (Current.is(tok::r_brace)) {
+        State.Column = Line.Level * 2;
+      } else if (Previous.is(tok::l_brace)) {
         // FIXME: This does not work with nested static initializers.
         // Implement a better handling for static initializers and similar
         // constructs.
index c09ee31..736178e 100644 (file)
@@ -76,6 +76,40 @@ private:
   FormatToken Token;
 };
 
+class ScopedLineState {
+public:
+  ScopedLineState(UnwrappedLineParser &Parser) : Parser(Parser) {
+    PreBlockLine = Parser.Line.take();
+    Parser.Line.reset(new UnwrappedLine(*PreBlockLine));
+    assert(Parser.LastInCurrentLine == NULL ||
+           Parser.LastInCurrentLine->Children.empty());
+    PreBlockLastToken = Parser.LastInCurrentLine;
+    PreBlockRootTokenInitialized = Parser.RootTokenInitialized;
+    Parser.RootTokenInitialized = false;
+    Parser.LastInCurrentLine = NULL;
+  }
+
+  ~ScopedLineState() {
+    if (Parser.RootTokenInitialized) {
+      Parser.addUnwrappedLine();
+    }
+    assert(!Parser.RootTokenInitialized);
+    Parser.Line.reset(PreBlockLine);
+    Parser.RootTokenInitialized = PreBlockRootTokenInitialized;
+    Parser.LastInCurrentLine = PreBlockLastToken;
+    assert(Parser.LastInCurrentLine == NULL ||
+           Parser.LastInCurrentLine->Children.empty());
+    Parser.MustBreakBeforeNextToken = true;
+  }
+
+private:
+  UnwrappedLineParser &Parser;
+
+  UnwrappedLine *PreBlockLine;
+  FormatToken* PreBlockLastToken;
+  bool PreBlockRootTokenInitialized;
+};
+
 UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
                                          FormatTokenSource &Tokens,
                                          UnwrappedLineConsumer &Callback)
@@ -204,6 +238,7 @@ void UnwrappedLineParser::parseComments() {
 }
 
 void UnwrappedLineParser::parseStructuralElement() {
+  assert(!FormatTok.Tok.is(tok::l_brace));
   parseComments();
 
   int TokenNumber = 0;
@@ -289,6 +324,10 @@ void UnwrappedLineParser::parseStructuralElement() {
       parseParens();
       break;
     case tok::l_brace:
+      // A block outside of parentheses must be the last part of a
+      // structural element.
+      // FIXME: Figure out cases where this is not true, and add projections for
+      // them (the one we know is missing are lambdas).
       parseBlock();
       addUnwrappedLine();
       return;
@@ -301,10 +340,28 @@ void UnwrappedLineParser::parseStructuralElement() {
       break;
     case tok::equal:
       nextToken();
-      // Skip initializers as they will be formatted by a later step.
-      if (FormatTok.Tok.is(tok::l_brace))
-        nextToken();
+      if (FormatTok.Tok.is(tok::l_brace)) {
+        parseBracedList();
+      }
+      break;
+    default:
+      nextToken();
+      break;
+    }
+  } while (!eof());
+}
+
+void UnwrappedLineParser::parseBracedList() {
+  nextToken();
+
+  do {
+    switch (FormatTok.Tok.getKind()) {
+    case tok::l_brace:
+      parseBracedList();
       break;
+    case tok::r_brace:
+      nextToken();
+      return;
     default:
       nextToken();
       break;
@@ -323,6 +380,15 @@ void UnwrappedLineParser::parseParens() {
     case tok::r_paren:
       nextToken();
       return;
+    case tok::l_brace:
+      {
+        nextToken();
+        ScopedLineState LineState(*this);
+        Line->Level += 1;
+        parseLevel(/*HasOpeningBrace=*/true);
+        Line->Level -= 1;
+      }
+      break;
     default:
       nextToken();
       break;
@@ -626,22 +692,8 @@ void UnwrappedLineParser::readToken() {
   while (!Line->InPPDirective && FormatTok.Tok.is(tok::hash) &&
          ((FormatTok.NewlinesBefore > 0 && FormatTok.HasUnescapedNewline) ||
           FormatTok.IsFirst)) {
-    UnwrappedLine* StoredLine = Line.take();
-    Line.reset(new UnwrappedLine(*StoredLine));
-    assert(LastInCurrentLine == NULL || LastInCurrentLine->Children.empty());
-    FormatToken *StoredLastInCurrentLine = LastInCurrentLine;
-    bool PreviousInitialized = RootTokenInitialized;
-    RootTokenInitialized = false;
-    LastInCurrentLine = NULL;
-
+    ScopedLineState BlockState(*this);
     parsePPDirective();
-
-    assert(!RootTokenInitialized);
-    Line.reset(StoredLine);
-    RootTokenInitialized = PreviousInitialized;
-    LastInCurrentLine = StoredLastInCurrentLine;
-    assert(LastInCurrentLine == NULL || LastInCurrentLine->Children.empty());
-    MustBreakBeforeNextToken = true;
   }
 }
 
index 16ad37e..017daf5 100644 (file)
@@ -131,6 +131,7 @@ private:
   void parsePPUnknown();
   void parseComments();
   void parseStructuralElement();
+  void parseBracedList();
   void parseParens();
   void parseIfThenElse();
   void parseForOrWhileLoop();
@@ -163,6 +164,8 @@ private:
   const FormatStyle &Style;
   FormatTokenSource *Tokens;
   UnwrappedLineConsumer &Callback;
+
+  friend class ScopedLineState;
 };
 
 } // end namespace format
index 51a0bd6..860661b 100644 (file)
@@ -615,6 +615,30 @@ TEST_F(FormatTest, LayoutStatementsAroundPreprocessorDirectives) {
       "               trailing);", getLLVMStyleWithColumns(69));
 }
 
+TEST_F(FormatTest, LayoutBlockInsideParens) {
+  EXPECT_EQ("functionCall({\n"
+            "  int i;\n"
+            "});", format(" functionCall ( {int i;} );"));
+}
+
+TEST_F(FormatTest, LayoutBlockInsideStatement) {
+  EXPECT_EQ("SOME_MACRO {\n"
+            "  int i;\n"
+            "}\n"
+            "int i;", format("  SOME_MACRO  {int i;}  int i;"));
+}
+
+TEST_F(FormatTest, LayoutNestedBlocks) {
+  verifyFormat("void AddOsStrings(unsigned bitmask) {\n"
+               "  struct s {\n"
+               "    int i;\n"
+               "  };\n"
+               "  s kBitsToOs[] = { { 10 } };\n"
+               "  for (int i = 0; i < 10; ++i)\n"
+               "    return;\n"
+               "}");
+}
+
 //===----------------------------------------------------------------------===//
 // Line break tests.
 //===----------------------------------------------------------------------===//