From 1a61ae01cb4ac0eaa175cd6d7859e0a3b49c6a05 Mon Sep 17 00:00:00 2001
From: Christian Kamm <christian.d.kamm@nokia.com>
Date: Thu, 15 Jul 2010 16:14:22 +0200
Subject: [PATCH] C++ indenter: Respect user indent with stream operators.

Reviewed-by: Erik Verbruggen
---
 src/plugins/cpptools/cppcodeformatter.cpp     | 20 ++++++++++++-----
 src/plugins/cpptools/cppcodeformatter.h       |  3 ++-
 .../codeformatter/tst_codeformatter.cpp       | 22 +++++++++++++++++++
 3 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/src/plugins/cpptools/cppcodeformatter.cpp b/src/plugins/cpptools/cppcodeformatter.cpp
index 75fe53fda81..a17488ac1d3 100644
--- a/src/plugins/cpptools/cppcodeformatter.cpp
+++ b/src/plugins/cpptools/cppcodeformatter.cpp
@@ -203,9 +203,17 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block)
             } break;
 
         case stream_op:
-            if (tryExpression())
+        case stream_op_cont:
+            if (kind != T_LESS_LESS && kind != T_GREATER_GREATER && tryExpression())
                 break;
             switch (kind) {
+            case T_LESS_LESS:
+            case T_GREATER_GREATER:
+                if (m_currentState.top().type == stream_op)
+                    enter(stream_op_cont);
+                else // stream_op_cont already
+                    turnInto(stream_op_cont);
+                break;
             case T_COMMA:
             case T_SEMICOLON:   leave(); continue; // always nested, propagate semicolon
             } break;
@@ -604,12 +612,10 @@ bool CodeFormatter::tryExpression(bool alsoExpression)
 
     case T_LESS_LESS:
     case T_GREATER_GREATER:
-        // don't go into stream operator state inside arglist_open
-        // or another stream_op
         newState = stream_op;
         for (int i = m_currentState.size() - 1; i >= 0; --i) {
             const int type = m_currentState.at(i).type;
-            if (type == arglist_open || type == stream_op) {
+            if (type == arglist_open) { // likely a left-shift instead
                 newState = -1;
                 break;
             }
@@ -1020,6 +1026,10 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
     case stream_op:
         *indentDepth = tokenPosition + tk.length() + 1;
         break;
+    case stream_op_cont:
+        if (firstToken)
+            *savedIndentDepth = *indentDepth = tokenPosition + tk.length() + 1;
+        break;
 
     case member_init_open:
         // undo the continuation indent of the parent
@@ -1257,7 +1267,7 @@ void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, i
         break;
     case T_LESS_LESS:
     case T_GREATER_GREATER:
-        if (topState.type == stream_op)
+        if (topState.type == stream_op || topState.type == stream_op_cont)
             *indentDepth -= 3; // to align << with <<
         break;
     case T_COMMENT:
diff --git a/src/plugins/cpptools/cppcodeformatter.h b/src/plugins/cpptools/cppcodeformatter.h
index fb3db4997fc..6508ad8f6dc 100644
--- a/src/plugins/cpptools/cppcodeformatter.h
+++ b/src/plugins/cpptools/cppcodeformatter.h
@@ -149,7 +149,8 @@ protected:
         substatement_open, // The brace that opens a substatement block.
 
         arglist_open, // after the lparen. TODO: check if this is enough.
-        stream_op, // Lines continuing a stream operator (C++ only).
+        stream_op, // After a '<<' or '>>' in a context where it's likely a stream operator.
+        stream_op_cont, // When finding another stream operator in stream_op
         ternary_op, // The ? : operator
 
         condition_open, // Start of a condition in 'if', 'while', entered after opening paren
diff --git a/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp b/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp
index c8216f90bac..796de10e52f 100644
--- a/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp
+++ b/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp
@@ -44,6 +44,7 @@ private Q_SLOTS:
     void whitesmithsStyle();
     void singleLineEnum();
     void functionReturnType();
+    void streamOp();
 };
 
 struct Line {
@@ -786,6 +787,27 @@ void tst_CodeFormatter::functionReturnType()
     checkIndent(data);
 }
 
+void tst_CodeFormatter::streamOp()
+{
+    QList<Line> data;
+    data
+         << Line("void foo () {")
+         << Line("    qDebug() << foo")
+         << Line("             << bar << moose")
+         << Line("             << bar +")
+         << Line("                foo - blah(1)")
+         << Line("             << '?'")
+         << Line("             << \"\\n\";")
+         << Line("    qDebug() << foo")
+         << Line("        << bar << moose", 13)
+         << Line("        << bar +")
+         << Line("           foo - blah(1)")
+         << Line("        << '?'")
+         << Line("        << \"\\n\";")
+         ;
+    checkIndent(data);
+}
+
 QTEST_APPLESS_MAIN(tst_CodeFormatter)
 #include "tst_codeformatter.moc"
 
-- 
GitLab