From 658e80d1b8471da11563a9738fa64aa32548a7db Mon Sep 17 00:00:00 2001
From: Christian Kamm <christian.d.kamm@nokia.com>
Date: Tue, 28 Feb 2012 15:04:47 +0100
Subject: [PATCH] QmlJS indenter: Improve handling of function expressions.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Task-number: QTCREATORBUG-7001

Change-Id: I254b84153b042c81008314bbebc800edfe201b89
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
(cherry picked from commit fcaf3d4f4c515e9c552357156d0a48b2c8359984)
---
 src/libs/qmljs/qmljscodeformatter.cpp         | 25 +++++--
 .../qmlcodeformatter/tst_qmlcodeformatter.cpp | 73 +++++++++++++++++++
 2 files changed, 90 insertions(+), 8 deletions(-)

diff --git a/src/libs/qmljs/qmljscodeformatter.cpp b/src/libs/qmljs/qmljscodeformatter.cpp
index 7b1a5e250bb..1ef3c80c085 100644
--- a/src/libs/qmljs/qmljscodeformatter.cpp
+++ b/src/libs/qmljs/qmljscodeformatter.cpp
@@ -396,7 +396,6 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block)
             } break;
 
         case maybe_catch_or_finally:
-            dump();
             switch (kind) {
             case Catch:             turnInto(catch_statement); break;
             case Finally:           turnInto(finally_statement); break;
@@ -1125,17 +1124,27 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
         }
         break;
 
-    case function_start:
-        if (parentState.type == expression) {
-            // undo the continuation indent of the expression
-            *indentDepth = parentState.savedIndentDepth;
-            *savedIndentDepth = *indentDepth;
-        } else {
-            // always align to function keyword
+    case function_start: {
+        // in these states, align to the 'function' keyword
+        const int parentType = parentState.type;
+        if (parentType == objectdefinition_open
+                || parentType == paren_open
+                || parentType == bracket_open) {
             *indentDepth = tokenPosition;
             *savedIndentDepth = *indentDepth;
+            break;
+        }
+
+        // otherwise find the enclosing expression end state and align to that
+        for (int i = 1; state(i).type != topmost_intro; ++i) {
+            const int type = state(i).type;
+            if (isExpressionEndState(type)) {
+                *indentDepth = state(i - 1).savedIndentDepth;
+                break;
+            }
         }
         break;
+    }
 
     case do_statement_while_paren_open:
     case statement_with_condition_paren_open:
diff --git a/tests/auto/qml/qmleditor/qmlcodeformatter/tst_qmlcodeformatter.cpp b/tests/auto/qml/qmleditor/qmlcodeformatter/tst_qmlcodeformatter.cpp
index 5a4411a1e9d..82cefa729be 100644
--- a/tests/auto/qml/qmleditor/qmlcodeformatter/tst_qmlcodeformatter.cpp
+++ b/tests/auto/qml/qmleditor/qmlcodeformatter/tst_qmlcodeformatter.cpp
@@ -56,6 +56,9 @@ private Q_SLOTS:
     void functionDeclaration();
     void functionExpression1();
     void functionExpression2();
+    void functionExpression3();
+    void functionExpression4();
+    void functionExpression5();
     void propertyDeclarations();
     void signalDeclarations();
     void ifBinding1();
@@ -415,6 +418,76 @@ void tst_QMLCodeFormatter::functionExpression2()
     checkIndent(data);
 }
 
+void tst_QMLCodeFormatter::functionExpression3()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("    function foo(a, b, c) {")
+         << Line("        var foo = {")
+         << Line("            bar: function() {")
+         << Line("                bar = 2")
+         << Line("            },")
+         << Line("            bar2: function()")
+         << Line("            {")
+         << Line("                bar = 2")
+         << Line("            }")
+         << Line("        }")
+         << Line("        Foo.proto.bar = function() {")
+         << Line("            bar = 2")
+         << Line("        }")
+         << Line("        Foo.proto.bar = function()")
+         << Line("        {")
+         << Line("            bar = 2")
+         << Line("        }")
+         << Line("    }")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_QMLCodeFormatter::functionExpression4()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("    function foo(a, b, c) {")
+         << Line("        baz = function() {")
+         << Line("            bar = 2")
+         << Line("        }")
+         << Line("        baz = function()")
+         << Line("        {")
+         << Line("            bar = 2")
+         << Line("        }")
+         << Line("        var buz = new function() {")
+         << Line("            this.bar = function() {")
+         << Line("                bar = 2")
+         << Line("            }")
+         << Line("            this.bar = function()")
+         << Line("            {")
+         << Line("                bar = 2")
+         << Line("            }")
+         << Line("        }")
+         << Line("    }")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_QMLCodeFormatter::functionExpression5()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("    property var foo: function() {")
+         << Line("        bar = 2")
+         << Line("    }")
+         << Line("    property var foo: function()")
+         << Line("    {")
+         << Line("        bar = 2")
+         << Line("    }")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
 void tst_QMLCodeFormatter::propertyDeclarations()
 {
     QList<Line> data;
-- 
GitLab