From 642b6fb0d3511f5d125c7079f8a3db77fc3c5da4 Mon Sep 17 00:00:00 2001
From: Christian Kamm <christian.d.kamm@nokia.com>
Date: Fri, 10 Sep 2010 14:12:14 +0200
Subject: [PATCH] C++ indenter: Separate indent into logical indent and
 padding.

---
 src/plugins/cppeditor/cppeditor.cpp           |  17 +-
 .../cppeditor/cpprefactoringchanges.cpp       |   5 +-
 src/plugins/cpptools/cppcodeformatter.cpp     | 159 ++++++++-----
 src/plugins/cpptools/cppcodeformatter.h       |  31 ++-
 .../codeformatter/tst_codeformatter.cpp       | 212 ++++++++++--------
 5 files changed, 265 insertions(+), 159 deletions(-)

diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp
index ec1aafc753a..817b8198746 100644
--- a/src/plugins/cppeditor/cppeditor.cpp
+++ b/src/plugins/cppeditor/cppeditor.cpp
@@ -1499,17 +1499,21 @@ void CPPEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedCha
     CppTools::QtStyleCodeFormatter codeFormatter(ts);
 
     codeFormatter.updateStateUntil(block);
-    const int depth = codeFormatter.indentFor(block);
+    int indent;
+    int padding;
+    codeFormatter.indentFor(block, &indent, &padding);
 
     // only reindent the current line when typing electric characters if the
     // indent is the same it would be if the line were empty
     if (isElectricCharacter(typedChar)) {
-        const int newlineIndent = codeFormatter.indentForNewLineAfter(block.previous());
-        if (ts.indentationColumn(block.text()) != newlineIndent)
+        int newlineIndent;
+        int newlinePadding;
+        codeFormatter.indentForNewLineAfter(block.previous(), &newlineIndent, &newlinePadding);
+        if (ts.indentationColumn(block.text()) != newlineIndent + newlinePadding)
             return;
     }
 
-    ts.indentLine(block, depth);
+    ts.indentLine(block, indent + padding, padding);
 }
 
 void CPPEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar)
@@ -1529,7 +1533,10 @@ void CPPEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar type
         QTextCursor tc = textCursor();
         tc.beginEditBlock();
         do {
-            ts.indentLine(block, codeFormatter.indentFor(block));
+            int indent;
+            int padding;
+            codeFormatter.indentFor(block, &indent, &padding);
+            ts.indentLine(block, indent + padding, padding);
             codeFormatter.updateLineStateChange(block);
             block = block.next();
         } while (block.isValid() && block != end);
diff --git a/src/plugins/cppeditor/cpprefactoringchanges.cpp b/src/plugins/cppeditor/cpprefactoringchanges.cpp
index ff2a9127650..cac384bf337 100644
--- a/src/plugins/cppeditor/cpprefactoringchanges.cpp
+++ b/src/plugins/cppeditor/cpprefactoringchanges.cpp
@@ -72,7 +72,10 @@ void CppRefactoringChanges::indentSelection(const QTextCursor &selection) const
     codeFormatter.updateStateUntil(block);
 
     do {
-        tabSettings.indentLine(block, codeFormatter.indentFor(block));
+        int indent;
+        int padding;
+        codeFormatter.indentFor(block, &indent, &padding);
+        tabSettings.indentLine(block, indent + padding, padding);
         codeFormatter.updateLineStateChange(block);
         block = block.next();
     } while (block.isValid() && block != end);
diff --git a/src/plugins/cpptools/cppcodeformatter.cpp b/src/plugins/cpptools/cppcodeformatter.cpp
index 89c9d85f5ea..12a9ea8d144 100644
--- a/src/plugins/cpptools/cppcodeformatter.cpp
+++ b/src/plugins/cpptools/cppcodeformatter.cpp
@@ -52,6 +52,7 @@ CodeFormatter::BlockData::BlockData()
 
 CodeFormatter::CodeFormatter()
     : m_indentDepth(0)
+    , m_paddingDepth(0)
     , m_tabSize(4)
 {
 }
@@ -461,19 +462,21 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block)
     saveCurrentState(block);
 }
 
-int CodeFormatter::indentFor(const QTextBlock &block)
+void CodeFormatter::indentFor(const QTextBlock &block, int *indent, int *padding)
 {
 //    qDebug() << "indenting for" << block.blockNumber() + 1;
 
     restoreCurrentState(block.previous());
     correctIndentation(block);
-    return m_indentDepth;
+    *indent = m_indentDepth;
+    *padding = m_paddingDepth;
 }
 
-int CodeFormatter::indentForNewLineAfter(const QTextBlock &block)
+void CodeFormatter::indentForNewLineAfter(const QTextBlock &block, int *indent, int *padding)
 {
     restoreCurrentState(block);
-    return m_indentDepth;
+    *indent = m_indentDepth;
+    *padding = m_paddingDepth;
 }
 
 void CodeFormatter::updateStateUntil(const QTextBlock &endBlock)
@@ -574,8 +577,9 @@ void CodeFormatter::invalidateCache(QTextDocument *document)
 void CodeFormatter::enter(int newState)
 {
     int savedIndentDepth = m_indentDepth;
-    onEnter(newState, &m_indentDepth, &savedIndentDepth);
-    State s(newState, savedIndentDepth);
+    int savedPaddingDepth = m_paddingDepth;
+    onEnter(newState, &m_indentDepth, &savedIndentDepth, &m_paddingDepth, &savedPaddingDepth);
+    State s(newState, savedIndentDepth, savedPaddingDepth);
     m_currentState.push(s);
     m_newStates.push(s);
 }
@@ -592,6 +596,7 @@ void CodeFormatter::leave(bool statementDone)
     // restore indent depth
     State poppedState = m_currentState.pop();
     m_indentDepth = poppedState.savedIndentDepth;
+    m_paddingDepth = poppedState.savedPaddingDepth;
 
     int topState = m_currentState.top().type;
 
@@ -622,7 +627,7 @@ void CodeFormatter::correctIndentation(const QTextBlock &block)
     const int lexerState = tokenizeBlock(block);
     Q_ASSERT(m_currentState.size() >= 1);
 
-    adjustIndent(m_tokens, lexerState, &m_indentDepth);
+    adjustIndent(m_tokens, lexerState, &m_indentDepth, &m_paddingDepth);
 }
 
 bool CodeFormatter::tryExpression(bool alsoExpression)
@@ -837,6 +842,7 @@ void CodeFormatter::saveCurrentState(const QTextBlock &block)
     blockData.m_beginState = m_beginState;
     blockData.m_endState = m_currentState;
     blockData.m_indentDepth = m_indentDepth;
+    blockData.m_paddingDepth = m_paddingDepth;
 
     QTextBlock saveableBlock(block);
     saveBlockData(&saveableBlock, blockData);
@@ -848,6 +854,7 @@ void CodeFormatter::restoreCurrentState(const QTextBlock &block)
         BlockData blockData;
         if (loadBlockData(block, &blockData)) {
             m_indentDepth = blockData.m_indentDepth;
+            m_paddingDepth = blockData.m_paddingDepth;
             m_currentState = blockData.m_endState;
             m_beginState = m_currentState;
             return;
@@ -857,13 +864,14 @@ void CodeFormatter::restoreCurrentState(const QTextBlock &block)
     m_currentState = initialState();
     m_beginState = m_currentState;
     m_indentDepth = 0;
+    m_paddingDepth = 0;
 }
 
 QStack<CodeFormatter::State> CodeFormatter::initialState()
 {
     static QStack<CodeFormatter::State> initialState;
     if (initialState.isEmpty())
-        initialState.push(State(topmost_intro, 0));
+        initialState.push(State(topmost_intro, 0, 0));
     return initialState;
 }
 
@@ -892,14 +900,15 @@ int CodeFormatter::tokenizeBlock(const QTextBlock &block, bool *endedJoined)
     return lexerState;
 }
 
-void CodeFormatter::dump()
+void CodeFormatter::dump() const
 {
     qDebug() << "Current token index" << m_tokenIndex;
     qDebug() << "Current state:";
     foreach (State s, m_currentState) {
-        qDebug() << s.type << s.savedIndentDepth;
+        qDebug() << s.type << s.savedIndentDepth << s.savedPaddingDepth;
     }
     qDebug() << "Current indent depth:" << m_indentDepth;
+    qDebug() << "Current padding depth:" << m_paddingDepth;
 }
 
 
@@ -1007,7 +1016,7 @@ int QtStyleCodeFormatter::loadLexerState(const QTextBlock &block) const
     return BaseTextDocumentLayout::lexerState(block);
 }
 
-void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedIndentDepth) const
+void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedIndentDepth, int *paddingDepth, int *savedPaddingDepth) const
 {
     const State &parentState = state();
     const Token &tk = currentToken();
@@ -1018,6 +1027,9 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
     if (!lastToken)
         nextTokenStart = column(tokenAt(tokenIndex() + 1).begin());
 
+    if (shouldClearPaddingOnEnter(newState))
+        *paddingDepth = 0;
+
     switch (newState) {
     case namespace_start:
         if (firstToken)
@@ -1029,14 +1041,19 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
     case class_start:
         if (firstToken)
             *savedIndentDepth = tokenPosition;
-        *indentDepth = tokenPosition + 2*m_indentSize;
+        *indentDepth = tokenPosition;
+        *paddingDepth = 2*m_indentSize;
         break;
 
     case template_param:
         if (!lastToken)
-            *indentDepth = tokenPosition + tk.length();
-        else
-            *indentDepth += 2*m_indentSize;
+            *paddingDepth = tokenPosition-*indentDepth + tk.length();
+        else {
+            if (*paddingDepth == 0)
+                *paddingDepth = 2*m_indentSize;
+            else
+                *paddingDepth += m_indentSize;
+        }
         break;
 
     case statement_with_condition:
@@ -1046,17 +1063,18 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
     case return_statement:
         if (firstToken)
             *savedIndentDepth = tokenPosition;
-        *indentDepth = *savedIndentDepth + 2*m_indentSize;
+        *paddingDepth = 2*m_indentSize;
         break;
 
     case declaration_start:
         if (firstToken)
             *savedIndentDepth = tokenPosition;
+        *indentDepth = *savedIndentDepth;
         // continuation indent in function bodies only, to not indent
         // after the return type in "void\nfoo() {}"
         for (int i = 0; state(i).type != topmost_intro; ++i) {
             if (state(i).type == defun_open) {
-                *indentDepth = *savedIndentDepth + 2*m_indentSize;
+                *paddingDepth = 2*m_indentSize;
                 break;
             }
         }
@@ -1065,42 +1083,42 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
     case arglist_open:
     case condition_paren_open:
         if (!lastToken)
-            *indentDepth = tokenPosition + 1;
+            *paddingDepth = tokenPosition-*indentDepth + 1;
         else
-            *indentDepth += m_indentSize;
+            *paddingDepth += m_indentSize;
         break;
 
     case ternary_op:
         if (!lastToken)
-            *indentDepth = tokenPosition + tk.length() + 1;
+            *paddingDepth = tokenPosition-*indentDepth + tk.length() + 1;
         else
-            *indentDepth += m_indentSize;
+            *paddingDepth += m_indentSize;
         break;
 
     case stream_op:
-        *indentDepth = tokenPosition + tk.length() + 1;
+        *paddingDepth = tokenPosition-*indentDepth + tk.length() + 1;
         break;
     case stream_op_cont:
         if (firstToken)
-            *savedIndentDepth = *indentDepth = tokenPosition + tk.length() + 1;
+            *savedPaddingDepth = *paddingDepth = tokenPosition-*indentDepth + tk.length() + 1;
         break;
 
     case member_init_open:
         // undo the continuation indent of the parent
-        *savedIndentDepth = parentState.savedIndentDepth;
+        *savedPaddingDepth = 0;
 
         if (firstToken)
-            *indentDepth = tokenPosition;
+            *paddingDepth = tokenPosition-*indentDepth;
         else
-            *indentDepth = *savedIndentDepth + m_indentSize - 2; // they'll get another 2 from member_init
+            *paddingDepth = m_indentSize - 2; // they'll get another 2 from member_init
         break;
 
     case member_init:
-        *indentDepth = *savedIndentDepth + 2; // savedIndentDepth is the position of ':'
+        *paddingDepth += 2; // savedIndentDepth is the position of ':'
         break;
 
     case member_init_paren_open:
-        *indentDepth = *savedIndentDepth + m_indentSize;
+        *paddingDepth += m_indentSize;
         break;
 
     case case_cont:
@@ -1111,18 +1129,16 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
     case enum_open:
     case defun_open: {
         // undo the continuation indent of the parent
-        *savedIndentDepth = parentState.savedIndentDepth;
+        *savedPaddingDepth = 0;
 
         bool followedByData = (!lastToken && !tokenAt(tokenIndex() + 1).isComment());
-        if (firstToken || followedByData)
-            *savedIndentDepth = tokenPosition;
+        if (followedByData)
+            *savedPaddingDepth = tokenPosition-*indentDepth;
 
-        *indentDepth = *savedIndentDepth;
+        *indentDepth += m_indentSize;
 
         if (followedByData) {
-            *indentDepth = column(tokenAt(tokenIndex() + 1).begin());
-        } else if (m_indentDeclarationMembers) {
-            *indentDepth += m_indentSize;
+            *paddingDepth = column(tokenAt(tokenIndex() + 1).begin()) - *indentDepth;
         }
         break;
     }
@@ -1147,13 +1163,13 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
     case brace_list_open:
         if (!lastToken) {
             if (parentState.type == initializer)
-                *savedIndentDepth = tokenPosition;
-            *indentDepth = nextTokenStart;
+                *savedPaddingDepth = tokenPosition-*indentDepth;
+            *paddingDepth = nextTokenStart-*indentDepth;
         } else {
             // avoid existing continuation indents
             if (parentState.type == initializer)
-                *savedIndentDepth = state(1).savedIndentDepth;
-            *indentDepth = *savedIndentDepth + m_indentSize;
+                *savedPaddingDepth = state(1).savedPaddingDepth;
+            *paddingDepth = *savedPaddingDepth + m_indentSize;
         }
         break;
 
@@ -1164,14 +1180,14 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
 
     case condition_open:
         // undo the continuation indent of the parent
-        *indentDepth = parentState.savedIndentDepth;
-        *savedIndentDepth = *indentDepth;
+        *paddingDepth = parentState.savedPaddingDepth;
+        *savedPaddingDepth = *paddingDepth;
 
         // fixed extra indent when continuing 'if (', but not for 'else if ('
         if (tokenPosition <= *indentDepth + m_indentSize)
-            *indentDepth += 2*m_indentSize;
+            *paddingDepth = 2*m_indentSize;
         else
-            *indentDepth = tokenPosition + 1;
+            *paddingDepth = tokenPosition-*indentDepth + 1;
         break;
 
     case substatement:
@@ -1209,7 +1225,7 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
     }
 }
 
-void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, int lexerState, int *indentDepth) const
+void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, int lexerState, int *indentDepth, int *paddingDepth) const
 {
     State topState = state();
     State previousState = state(1);
@@ -1245,33 +1261,38 @@ void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, i
     case T_COLON:
         // ### ok for constructor initializer lists - what about ? and bitfields?
         if (topState.type == expression && previousState.type == declaration_start) {
-            *indentDepth = previousState.savedIndentDepth + m_indentSize;
+            *paddingDepth = 4;
         } else if (topState.type == ternary_op) {
-            *indentDepth -= 2;
+            *paddingDepth -= 2;
         }
         break;
     case T_LBRACE: {
         if (topState.type == case_cont) {
             *indentDepth = topState.savedIndentDepth;
+            *paddingDepth = 0;
         // function definition - argument list is expression state
         } else if (topState.type == expression && previousState.type == declaration_start) {
             *indentDepth = previousState.savedIndentDepth;
             if (m_indentDeclarationBraces)
                 *indentDepth += m_indentSize;
+            *paddingDepth = 0;
         } else if (topState.type == class_start) {
             *indentDepth = topState.savedIndentDepth;
             if (m_indentDeclarationBraces)
                 *indentDepth += m_indentSize;
+            *paddingDepth = 0;
         } else if (topState.type == substatement) {
             *indentDepth = topState.savedIndentDepth;
             if (m_indentSubstatementBraces)
                 *indentDepth += m_indentSize;
+            *paddingDepth = 0;
         } else if (topState.type != defun_open
                 && topState.type != block_open
                 && topState.type != substatement_open
                 && topState.type != brace_list_open
                 && !topWasMaybeElse) {
             *indentDepth = topState.savedIndentDepth;
+            *paddingDepth = 0;
         }
 
         break;
@@ -1279,18 +1300,25 @@ void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, i
     case T_RBRACE: {
         if (topState.type == block_open && previousState.type == case_cont) {
             *indentDepth = previousState.savedIndentDepth;
+            *paddingDepth = previousState.savedPaddingDepth;
             break;
         }
         for (int i = 0; state(i).type != topmost_intro; ++i) {
             const int type = state(i).type;
-            if (type == defun_open
-                    || type == substatement_open
-                    || type == class_open
-                    || type == brace_list_open
+            if (type == class_open
                     || type == namespace_open
-                    || type == block_open
-                    || type == enum_open) {
+                    || type == enum_open
+                    || type == defun_open) {
+                *indentDepth = state(i).savedIndentDepth;
+                if (m_indentDeclarationBraces)
+                    *indentDepth += m_indentSize;
+                *paddingDepth = state(i).savedPaddingDepth;
+                break;
+            } else if (type == substatement_open
+                       || type == brace_list_open
+                       || type == block_open) {
                 *indentDepth = state(i).savedIndentDepth;
+                *paddingDepth = state(i).savedPaddingDepth;
                 break;
             }
         }
@@ -1331,7 +1359,7 @@ void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, i
     case T_LESS_LESS:
     case T_GREATER_GREATER:
         if (topState.type == stream_op || topState.type == stream_op_cont)
-            *indentDepth -= 3; // to align << with <<
+            *paddingDepth -= 3; // to align << with <<
         break;
     case T_COMMENT:
     case T_DOXY_COMMENT:
@@ -1348,3 +1376,28 @@ void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, i
         break;
     }
 }
+
+bool QtStyleCodeFormatter::shouldClearPaddingOnEnter(int state)
+{
+    switch (state) {
+    case defun_open:
+    case class_start:
+    case class_open:
+    case enum_start:
+    case enum_open:
+    case namespace_start:
+    case namespace_open:
+    case template_start:
+    case if_statement:
+    case else_clause:
+    case for_statement:
+    case switch_statement:
+    case statement_with_condition:
+    case do_statement:
+    case return_statement:
+    case block_open:
+    case substatement_open:
+        return true;
+    }
+    return false;
+}
diff --git a/src/plugins/cpptools/cppcodeformatter.h b/src/plugins/cpptools/cppcodeformatter.h
index e0365cb5cf2..bb46fc6abc5 100644
--- a/src/plugins/cpptools/cppcodeformatter.h
+++ b/src/plugins/cpptools/cppcodeformatter.h
@@ -68,16 +68,16 @@ public:
     // calculates the state change introduced by changing a single line
     void updateLineStateChange(const QTextBlock &block);
 
-    int indentFor(const QTextBlock &block);
-    int indentForNewLineAfter(const QTextBlock &block);
+    void indentFor(const QTextBlock &block, int *indent, int *padding);
+    void indentForNewLineAfter(const QTextBlock &block, int *indent, int *padding);
 
     void setTabSize(int tabSize);
 
     void invalidateCache(QTextDocument *document);
 
 protected:
-    virtual void onEnter(int newState, int *indentDepth, int *savedIndentDepth) const = 0;
-    virtual void adjustIndent(const QList<CPlusPlus::Token> &tokens, int lexerState, int *indentDepth) const = 0;
+    virtual void onEnter(int newState, int *indentDepth, int *savedIndentDepth, int *paddingDepth, int *savedPaddingDepth) const = 0;
+    virtual void adjustIndent(const QList<CPlusPlus::Token> &tokens, int lexerState, int *indentDepth, int *paddingDepth) const = 0;
 
     class State;
     class BlockData
@@ -88,6 +88,7 @@ protected:
         QStack<State> m_beginState;
         QStack<State> m_endState;
         int m_indentDepth;
+        int m_paddingDepth;
         int m_blockRevision;
     };
 
@@ -174,20 +175,24 @@ protected:
     public:
         State()
             : savedIndentDepth(0)
+            , savedPaddingDepth(0)
             , type(0)
         {}
 
-        State(quint8 ty, quint16 savedDepth)
-            : savedIndentDepth(savedDepth)
+        State(quint8 ty, quint16 savedIndentDepth, qint16 savedPaddingDepth)
+            : savedIndentDepth(savedIndentDepth)
+            , savedPaddingDepth(savedPaddingDepth)
             , type(ty)
         {}
 
         quint16 savedIndentDepth;
+        quint16 savedPaddingDepth;
         quint8 type;
 
         bool operator==(const State &other) const {
             return type == other.type
-                && savedIndentDepth == other.savedIndentDepth;
+                && savedIndentDepth == other.savedIndentDepth
+                && savedPaddingDepth == other.savedPaddingDepth;
         }
     };
 
@@ -201,6 +206,8 @@ protected:
 
     bool isBracelessState(int type) const;
 
+    void dump() const;
+
 private:
     void recalculateStateAfter(const QTextBlock &block);
     void saveCurrentState(const QTextBlock &block);
@@ -220,8 +227,6 @@ private:
     void leave(bool statementDone = false);
     void correctIndentation(const QTextBlock &block);
 
-    void dump();
-
 private:
     static QStack<State> initialState();
 
@@ -234,8 +239,8 @@ private:
     CPlusPlus::Token m_currentToken;
     int m_tokenIndex;
 
-    // should store indent level and padding instead
     int m_indentDepth;
+    int m_paddingDepth;
 
     int m_tabSize;
 
@@ -256,8 +261,8 @@ public:
     void setIndentDeclarationMembers(bool onOff);
 
 protected:
-    virtual void onEnter(int newState, int *indentDepth, int *savedIndentDepth) const;
-    virtual void adjustIndent(const QList<CPlusPlus::Token> &tokens, int lexerState, int *indentDepth) const;
+    virtual void onEnter(int newState, int *indentDepth, int *savedIndentDepth, int *paddingDepth, int *savedPaddingDepth) const;
+    virtual void adjustIndent(const QList<CPlusPlus::Token> &tokens, int lexerState, int *indentDepth, int *paddingDepth) const;
 
     virtual void saveBlockData(QTextBlock *block, const BlockData &data) const;
     virtual bool loadBlockData(const QTextBlock &block, BlockData *data) const;
@@ -265,6 +270,8 @@ protected:
     virtual void saveLexerState(QTextBlock *block, int state) const;
     virtual int loadLexerState(const QTextBlock &block) const;
 
+    static bool shouldClearPaddingOnEnter(int state);
+
 private:
     int m_indentSize;
     bool m_indentSubstatementBraces;
diff --git a/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp b/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp
index 9e6b88a1ea9..50b3e73a4f6 100644
--- a/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp
+++ b/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp
@@ -52,22 +52,44 @@ private Q_SLOTS:
 struct Line {
     Line(QString l)
         : line(l)
+        , expectedIndent(-1)
+        , expectedPadding(0)
     {
         for (int i = 0; i < l.size(); ++i) {
             if (!l.at(i).isSpace()) {
                 expectedIndent = i;
-                return;
+                break;
+            }
+        }
+        if (expectedIndent == -1)
+            expectedIndent = l.size();
+        if (expectedIndent < l.size() && l.at(expectedIndent) == '~') {
+            line[expectedIndent] = ' ';
+            for (int i = expectedIndent + 1; i < l.size(); ++i) {
+                if (!l.at(i).isSpace()) {
+                    expectedPadding = i - expectedIndent;
+                    break;
+                }
             }
         }
-        expectedIndent = l.size();
     }
 
-    Line(QString l, int expect)
-        : line(l), expectedIndent(expect)
-    {}
+    Line(QString l, int expectIndent, int expectPadding = 0)
+        : line(l), expectedIndent(expectIndent), expectedPadding(expectPadding)
+    {
+        for (int i = 0; i < line.size(); ++i) {
+            if (line.at(i) == '~') {
+                line[i] = ' ';
+                break;
+            }
+            if (!line.at(i).isSpace())
+                break;
+        }
+    }
 
     QString line;
     int expectedIndent;
+    int expectedPadding;
 };
 
 QString concatLines(QList<Line> lines)
@@ -98,10 +120,15 @@ void checkIndent(QList<Line> data, int style = 0)
     foreach (const Line &l, data) {
         QTextBlock b = document.findBlockByLineNumber(i);
         if (l.expectedIndent != -1) {
-            int actualIndent = formatter.indentFor(b);
-            if (actualIndent != l.expectedIndent) {
+            int indent, padding;
+            formatter.indentFor(b, &indent, &padding);
+            if (indent != l.expectedIndent) {
                 QFAIL(QString("Wrong indent in line %1 with text '%2', expected indent %3, got %4").arg(
-                        QString::number(i+1), l.line, QString::number(l.expectedIndent), QString::number(actualIndent)).toLatin1().constData());
+                        QString::number(i+1), l.line, QString::number(l.expectedIndent), QString::number(indent)).toLatin1().constData());
+            }
+            if (padding != l.expectedPadding) {
+                QFAIL(QString("Wrong padding in line %1 with text '%2', expected padding %3, got %4").arg(
+                        QString::number(i+1), l.line, QString::number(l.expectedPadding), QString::number(padding)).toLatin1().constData());
             }
         }
         formatter.updateLineStateChange(b);
@@ -265,11 +292,11 @@ void tst_CodeFormatter::ifStatementLongCondition()
     data << Line("void foo()")
          << Line("{")
          << Line("    if (foo &&")
-         << Line("            bar")
-         << Line("            || (a + b > 4")
-         << Line("                && foo(bar)")
-         << Line("                )")
-         << Line("            ) {")
+         << Line("    ~       bar")
+         << Line("    ~       || (a + b > 4")
+         << Line("    ~           && foo(bar)")
+         << Line("    ~           )")
+         << Line("    ~       ) {")
          << Line("        foo;")
          << Line("    }")
          << Line("}");
@@ -486,31 +513,31 @@ void tst_CodeFormatter::expressionContinuation()
     QList<Line> data;
     data << Line("void foo() {")
          << Line("    return (a <= b &&")
-         << Line("            c <= d);")
+         << Line("    ~       c <= d);")
          << Line("    return (qMax <= qMin() &&")
-         << Line("            qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom()));")
+         << Line("    ~       qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom()));")
          << Line("    return a")
-         << Line("            == b && c == d;")
+         << Line("    ~       == b && c == d;")
          << Line("    return a ==")
-         << Line("            b && c == d;")
+         << Line("    ~       b && c == d;")
          << Line("    return a == b")
-         << Line("            && c == d;")
+         << Line("    ~       && c == d;")
          << Line("    return a == b &&")
-         << Line("            c == d;")
+         << Line("    ~       c == d;")
          << Line("    return a == b && c")
-         << Line("            == d;")
+         << Line("    ~       == d;")
          << Line("    return a == b && c ==")
-         << Line("            d;")
+         << Line("    ~       d;")
          << Line("    return a == b && c == d;")
          << Line("    qDebug() << foo")
-         << Line("             << bar << moose")
-         << Line("             << bar +")
-         << Line("                foo - blah(1)")
-         << Line("             << '?'")
-         << Line("             << \"\\n\";")
+         << Line("    ~        << bar << moose")
+         << Line("    ~        << bar +")
+         << Line("    ~           foo - blah(1)")
+         << Line("    ~        << '?'")
+         << Line("    ~        << \"\\n\";")
          << Line("    i += foo(")
-         << Line("                bar,")
-         << Line("                2);")
+         << Line("    ~           bar,")
+         << Line("    ~           2);")
          << Line("}")
          ;
     checkIndent(data);
@@ -545,15 +572,15 @@ void tst_CodeFormatter::ternary()
     data << Line("void foo() {")
          << Line("    int i = a ? b : c;")
          << Line("    foo += a_bigger_condition ?")
-         << Line("                b")
-         << Line("              : c;")
+         << Line("    ~           b")
+         << Line("    ~         : c;")
          << Line("    int i = a ?")
-         << Line("                b : c;")
+         << Line("    ~           b : c;")
          << Line("    int i = a ? b")
-         << Line("              : c +")
-         << Line("                2;")
+         << Line("    ~         : c +")
+         << Line("    ~           2;")
          << Line("    int i = (a ? b : c) + (foo")
-         << Line("                           bar);")
+         << Line("    ~                      bar);")
          << Line("}")
          ;
     checkIndent(data);
@@ -582,21 +609,21 @@ void tst_CodeFormatter::bug2()
     QList<Line> data;
     data << Line("void foo() {")
          << Line("    const int sourceY = foo(")
-         << Line("                bar(")
-         << Line("                    car(a,")
-         << Line("                        b),")
-         << Line("                    b),")
-         << Line("                foo);")
+         << Line("    ~           bar(")
+         << Line("    ~               car(a,")
+         << Line("    ~                   b),")
+         << Line("    ~               b),")
+         << Line("    ~           foo);")
          << Line("    const int sourceY =")
-         << Line("            foo(")
-         << Line("                bar(a,")
-         << Line("                    b),")
-         << Line("                b);")
+         << Line("    ~       foo(")
+         << Line("    ~           bar(a,")
+         << Line("    ~               b),")
+         << Line("    ~           b);")
          << Line("    int j;")
          << Line("    const int sourceY =")
-         << Line("            (direction == DirectionEast || direction == DirectionWest) ?")
-         << Line("                (sourceRect.top() + (sourceRect.bottom() - sourceRect.top()) / 2)")
-         << Line("              : (direction == DirectionSouth ? sourceRect.bottom() : sourceRect.top());")
+         << Line("    ~       (direction == DirectionEast || direction == DirectionWest) ?")
+         << Line("    ~           (sourceRect.top() + (sourceRect.bottom() - sourceRect.top()) / 2)")
+         << Line("    ~         : (direction == DirectionSouth ? sourceRect.bottom() : sourceRect.top());")
          << Line("}")
          ;
     checkIndent(data);
@@ -610,15 +637,15 @@ void tst_CodeFormatter::braceList()
          << Line("    b,")
          << Line("};")
          << Line("enum Foo { a = 2,")
-         << Line("           a = 3,")
-         << Line("           b = 4")
-         << Line("         };")
+         << Line("    ~      a = 3,")
+         << Line("    ~      b = 4")
+         << Line("~        };")
          << Line("void foo () {")
          << Line("    int a[] = { foo, bar, ")
-         << Line("                car };")
+         << Line("    ~           car };")
          << Line("    int a[] = {")
-         << Line("        a, b,")
-         << Line("        c")
+         << Line("    ~   a, b,")
+         << Line("    ~   c")
          << Line("    };")
          << Line("    int k;")
          ;
@@ -669,23 +696,23 @@ void tst_CodeFormatter::memberInitializer()
 {
     QList<Line> data;
     data << Line("void foo()")
-         << Line("    : baR()")
-         << Line("    , m_member(23)")
+         << Line("~   : baR()")
+         << Line("~   , m_member(23)")
          << Line("{")
          << Line("}")
          << Line("class Foo {")
          << Line("    Foo()")
-         << Line("        : baR(),")
-         << Line("          moodoo(barR + ")
-         << Line("              42),")
-         << Line("          xyz()")
+         << Line("    ~   : baR(),")
+         << Line("    ~     moodoo(barR + ")
+         << Line("    ~         42),")
+         << Line("    ~     xyz()")
          << Line("    {}")
          << Line("};")
          << Line("class Foo {")
          << Line("    Foo() :")
-         << Line("        baR(),")
-         << Line("        moo(barR)")
-         << Line("      , moo(barR)")
+         << Line("    ~   baR(),")
+         << Line("    ~   moo(barR)")
+         << Line("    ~ , moo(barR)")
          << Line("    {}")
          << Line("}")
          ;
@@ -700,11 +727,20 @@ void tst_CodeFormatter::templates()
          << Line("private:")
          << Line("};")
          << Line("template <class T,")
-         << Line("          typename F, int i")
-         << Line("          >")
+         << Line("~         typename F, int i")
+         << Line("~         >")
          << Line("class Foo {")
          << Line("private:")
          << Line("};")
+         << Line("template <template <class F,")
+         << Line("~                   class D>,")
+         << Line("~         typename F>")
+         << Line("class Foo { };")
+         << Line("template <")
+         << Line("~       template <")
+         << Line("~           class F, class D>,")
+         << Line("~       typename F>")
+         << Line("class Foo { };")
          ;
     checkIndent(data);
 }
@@ -806,17 +842,17 @@ void tst_CodeFormatter::streamOp()
     data
          << Line("void foo () {")
          << Line("    qDebug() << foo")
-         << Line("             << bar << moose")
-         << Line("             << bar +")
-         << Line("                foo - blah(1)")
-         << Line("             << '?'")
-         << Line("             << \"\\n\";")
+         << 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\";")
+         << Line("        << bar << moose", 4, 9)
+         << Line("    ~   << bar +")
+         << Line("    ~      foo - blah(1)")
+         << Line("    ~   << '?'")
+         << Line("    ~   << \"\\n\";")
          ;
     checkIndent(data);
 }
@@ -843,26 +879,26 @@ void tst_CodeFormatter::nestedInitializer()
     QList<Line> data;
     data
          << Line("SomeStruct v[] = {")
-         << Line("    {2}, {3},")
-         << Line("    {4}, {5},")
+         << Line("~   {2}, {3},")
+         << Line("~   {4}, {5},")
          << Line("};")
          << Line("S v[] = {{1}, {2},")
-         << Line("         {3}, {4},")
-         << Line("        };")
+         << Line("~        {3}, {4},")
+         << Line("~       };")
          << Line("SomeStruct v[] = {")
-         << Line("    {")
-         << Line("        {2, 3,")
-         << Line("         4, 5},")
-         << Line("        {1},")
-         << Line("    }")
+         << Line("~   {")
+         << Line("~       {2, 3,")
+         << Line("~        4, 5},")
+         << Line("~       {1},")
+         << Line("~   }")
          << Line("};")
          << Line("SomeStruct v[] = {{{2, 3},")
-         << Line("                   {4, 5}")
-         << Line("                  },")
-         << Line("                  {{2, 3},")
-         << Line("                   {4, 5},")
-         << Line("                  }")
-         << Line("                 };")
+         << Line("~                  {4, 5}")
+         << Line("~                 },")
+         << Line("~                 {{2, 3},")
+         << Line("~                  {4, 5},")
+         << Line("~                 }")
+         << Line("~                };")
          << Line("int i;")
          ;
     checkIndent(data);
-- 
GitLab