From 74ed3e8a115d6a5eeaaf52e7f37eeb80d89c95c1 Mon Sep 17 00:00:00 2001
From: Christian Kamm <christian.d.kamm@nokia.com>
Date: Tue, 6 Jul 2010 14:41:34 +0200
Subject: [PATCH] C++ indenter: Add more functions to manage the indenter
 state.

---
 src/plugins/cpptools/cppcodeformatter.cpp     | 41 ++++++++++++++++++-
 src/plugins/cpptools/cppcodeformatter.h       |  6 +++
 .../codeformatter/tst_codeformatter.cpp       |  6 +--
 3 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/src/plugins/cpptools/cppcodeformatter.cpp b/src/plugins/cpptools/cppcodeformatter.cpp
index 582293ff10c..89915daef5e 100644
--- a/src/plugins/cpptools/cppcodeformatter.cpp
+++ b/src/plugins/cpptools/cppcodeformatter.cpp
@@ -455,6 +455,8 @@ void CodeFormatter::updateStateUntil(const QTextBlock &endBlock)
 {
     QStack<State> previousState = initialState();
     QTextBlock it = endBlock.document()->firstBlock();
+
+    // find the first block that needs recalculation
     for (; it.isValid() && it != endBlock; it = it.next()) {
         TextBlockUserData *userData = BaseTextDocumentLayout::userData(it);
         CppCodeFormatterData *cppData = static_cast<CppCodeFormatterData *>(userData->codeFormatterData());
@@ -469,10 +471,47 @@ void CodeFormatter::updateStateUntil(const QTextBlock &endBlock)
 
         previousState = cppData->m_endState;
     }
+
+    if (it == endBlock)
+        return;
+
+    // update everthing until endBlock
     for (; it.isValid() && it != endBlock; it = it.next()) {
-        //qDebug() << "recalc line" << it.blockNumber() + 1;
         recalculateStateAfter(it);
     }
+
+    // invalidate everything below by marking the state in endBlock as invalid
+    TextBlockUserData *userData = BaseTextDocumentLayout::userData(endBlock);
+    CppCodeFormatterData *cppData = static_cast<CppCodeFormatterData *>(userData->codeFormatterData());
+    if (cppData)
+        cppData->setBlockRevision(-1);
+}
+
+void CodeFormatter::updateLineStateChange(const QTextBlock &block)
+{
+    if (!block.isValid())
+        return;
+
+    QStack<State> oldEndState;
+
+    TextBlockUserData *userData = BaseTextDocumentLayout::userData(block);
+    CppCodeFormatterData *cppData = static_cast<CppCodeFormatterData *>(userData->codeFormatterData());
+    if (cppData)
+        oldEndState = cppData->m_endState;
+
+    recalculateStateAfter(block);
+
+    if (oldEndState.isEmpty() || oldEndState != cppData->m_endState) {
+        // invalidate everything below by marking the next block's state as invalid
+        QTextBlock next = block.next();
+        if (!next.isValid())
+            return;
+
+        userData = BaseTextDocumentLayout::userData(next);
+        cppData = static_cast<CppCodeFormatterData *>(userData->codeFormatterData());
+        if (cppData)
+            cppData->setBlockRevision(-1);
+    }
 }
 
 CodeFormatter::State CodeFormatter::state(int belowTop) const
diff --git a/src/plugins/cpptools/cppcodeformatter.h b/src/plugins/cpptools/cppcodeformatter.h
index 2475603d4d0..4fee466086c 100644
--- a/src/plugins/cpptools/cppcodeformatter.h
+++ b/src/plugins/cpptools/cppcodeformatter.h
@@ -28,7 +28,13 @@ public:
     CodeFormatter();
     virtual ~CodeFormatter();
 
+    // updates all states up until block if necessary
+    // it is safe to call indentFor on block afterwards
     void updateStateUntil(const QTextBlock &block);
+
+    // calculates the state change introduced by changing a single line
+    void updateLineStateChange(const QTextBlock &block);
+
     int indentFor(const QTextBlock &block);
 
     void setTabSize(int tabSize);
diff --git a/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp b/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp
index f604deee9c7..e8be0dcfb85 100644
--- a/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp
+++ b/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp
@@ -89,17 +89,17 @@ void checkIndent(QList<Line> data, int style = 0)
         formatter.setIndentDeclarationBraces(true);
     }
 
-    formatter.updateStateUntil(document.lastBlock());
-
     int i = 0;
     foreach (const Line &l, data) {
+        QTextBlock b = document.findBlockByLineNumber(i);
         if (l.expectedIndent != -1) {
-            int actualIndent = formatter.indentFor(document.findBlockByLineNumber(i));
+            int actualIndent = formatter.indentFor(b);
             if (actualIndent != 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());
             }
         }
+        formatter.updateLineStateChange(b);
         ++i;
     }
 }
-- 
GitLab