diff --git a/languages/cpp/CMakeLists.txt b/languages/cpp/CMakeLists.txt
index 8b47acc..8b45493 100644
--- a/languages/cpp/CMakeLists.txt
+++ b/languages/cpp/CMakeLists.txt
@@ -52,6 +52,7 @@ set(kdevcpplanguagesupport_PART_SRCS
     codegen/progressdialogs.cpp
     codegen/codeassistant.cpp
     codegen/signatureassistant.cpp
+    codegen/renameassistant.cpp
     codegen/unresolvedincludeassistant.cpp
 #     codegen/makeimplementationprivate.cpp
 )
diff --git a/languages/cpp/codegen/codeassistant.cpp b/languages/cpp/codegen/codeassistant.cpp
index 6339a66..36e94ce 100644
--- a/languages/cpp/codegen/codeassistant.cpp
+++ b/languages/cpp/codegen/codeassistant.cpp
@@ -61,7 +61,7 @@ void StaticCodeAssistant::documentLoaded(KDevelop::IDocument* document) {
   {
     ///@todo Make these connections non-queued, and then reach forward using a QPointer, since else a crash may happen when the document is destroyed before the message is processed
     connect(document->textDocument(), SIGNAL(textInserted(KTextEditor::Document*,KTextEditor::Range)), SLOT(textInserted(KTextEditor::Document*,KTextEditor::Range)));
-    connect(document->textDocument(), SIGNAL(textRemoved(KTextEditor::Document*,KTextEditor::Range)), SLOT(textRemoved(KTextEditor::Document*,KTextEditor::Range)));
+    connect(document->textDocument(), SIGNAL(textRemoved(KTextEditor::Document*,KTextEditor::Range, const QString&)), SLOT(textRemoved(KTextEditor::Document*,KTextEditor::Range, const QString&)));
   }
 }
 
@@ -75,33 +75,46 @@ void StaticCodeAssistant::textInserted(KTextEditor::Document* document, KTextEdi
   QMetaObject::invokeMethod(this, "eventuallyStartAssistant", Qt::QueuedConnection, Q_ARG(SafeDocumentPointer, document), Q_ARG(KTextEditor::Range, range));
 }
 
-void StaticCodeAssistant::textRemoved(KTextEditor::Document* document, KTextEditor::Range range) {
-  range = KTextEditor::Range(range.start(), range.start());
-  QMetaObject::invokeMethod(this, "eventuallyStartAssistant", Qt::QueuedConnection, Q_ARG(SafeDocumentPointer, document), Q_ARG(KTextEditor::Range, range));
+void StaticCodeAssistant::textRemoved(KTextEditor::Document* document, KTextEditor::Range range, const QString &removedText) {
+  QMetaObject::invokeMethod(this, "eventuallyStartAssistant", Qt::QueuedConnection, Q_ARG(SafeDocumentPointer, document), Q_ARG(KTextEditor::Range, range), Q_ARG(const QString&, removedText));
 }
 
-void StaticCodeAssistant::eventuallyStartAssistant(SafeDocumentPointer document, KTextEditor::Range range) {
+void StaticCodeAssistant::eventuallyStartAssistant(SafeDocumentPointer document, KTextEditor::Range range, const QString& removedText) {
 
   if(!document)
     return;
   
-  if(m_activeAssistant) {
-//     kDebug() << "there still is an active assistant";
-//     if(abs(m_activeAssistant->invocationCursor().line() < range.start().line()) >= 1) {
-//       kDebug() << "assistant was not deleted in time";
-//     }else{
-//       return;
-//     }
-  }
   //Eventually pop up an assistant
   if(!document->activeView())
     return;
-  
-  KSharedPtr<AdaptDefinitionSignatureAssistant> signatureAssistant(new AdaptDefinitionSignatureAssistant(document->activeView(), range));
+
+  //FIXME: update signature assistant to play well with the rename assistant
+  KTextEditor::Range sigAssistRange = removedText.isEmpty() ? range : KTextEditor::Range(range.start(), range.start());
+  KSharedPtr<AdaptDefinitionSignatureAssistant> signatureAssistant(new AdaptDefinitionSignatureAssistant(document->activeView(), sigAssistRange));
   
   if(signatureAssistant->isUseful()) {
     startAssistant(KSharedPtr<IAssistant>(signatureAssistant.data()));
   }
+
+  if (!m_renameAssistants.contains(document->activeView())) {
+    m_renameAssistants[document->activeView()].attach(new RenameAssistant(document->activeView()));
+    connect(document, SIGNAL(aboutToClose(KTextEditor::Document*)),
+            SLOT(deleteRenameAssistantsForDocument(KTextEditor::Document*)));
+  }
+
+  m_renameAssistants[document->activeView()]->textChanged(range, removedText);
+
+  if(m_renameAssistants[document->activeView()]->isUseful()) {
+    startAssistant(KSharedPtr<IAssistant>(m_renameAssistants[document->activeView()].data()));
+  }
+}
+
+void StaticCodeAssistant::deleteRenameAssistantsForDocument(KTextEditor::Document* document)
+{
+  foreach(KTextEditor::View *view, document->views()) {
+    if (m_renameAssistants.contains(view))
+      m_renameAssistants.remove(view);
+  }
 }
 
 void StaticCodeAssistant::startAssistant(KSharedPtr< KDevelop::IAssistant > assistant, bool manage) {
@@ -163,10 +176,7 @@ void StaticCodeAssistant::documentActivated(KDevelop::IDocument* doc) {
 }
 
 void StaticCodeAssistant::checkAssistantForProblems(KDevelop::TopDUContext* top) {
-    //Check whether one of the problems is in the current line, and if yes, show its assistant
-//     kDebug() << "checking, problem-count:" << top->problems().size();
     foreach(KDevelop::ProblemPointer problem, top->problems()) {
-//       kDebug() << "range of problem:" << problem->range().textRange() << "matching to" << m_currentView->cursorPosition().line();
       if(m_currentView && m_currentView->cursorPosition().line() == problem->range().start.line) {
         IAssistant::Ptr solution = problem->solutionAssistant();
         if(solution) {
diff --git a/languages/cpp/codegen/codeassistant.h b/languages/cpp/codegen/codeassistant.h
index 8443b6f..6e46d60 100644
--- a/languages/cpp/codegen/codeassistant.h
+++ b/languages/cpp/codegen/codeassistant.h
@@ -27,6 +27,7 @@
 #include <language/duchain/indexedstring.h>
 #include <language/duchain/types/indexedtype.h>
 #include <QTimer>
+#include "renameassistant.h"
 
 typedef QPointer<KTextEditor::Document> SafeDocumentPointer;
 
@@ -51,12 +52,13 @@ class StaticCodeAssistant : public QObject {
     void assistantHide();
     void documentLoaded(KDevelop::IDocument*);
     void textInserted(KTextEditor::Document*,KTextEditor::Range);
-    void textRemoved(KTextEditor::Document*,KTextEditor::Range);
+    void textRemoved(KTextEditor::Document*,KTextEditor::Range,const QString& removedText);
     void parseJobFinished(KDevelop::ParseJob*);
     void documentActivated(KDevelop::IDocument*);
     void cursorPositionChanged(KTextEditor::View*,KTextEditor::Cursor);
     void timeout();
-    void eventuallyStartAssistant(SafeDocumentPointer, KTextEditor::Range range);
+    void eventuallyStartAssistant(SafeDocumentPointer document, KTextEditor::Range range, const QString& removedText = QString());
+    void deleteRenameAssistantsForDocument(KTextEditor::Document*);
   private:
     void checkAssistantForProblems(KDevelop::TopDUContext* top);
     ///@param manage If this is true, the static code-assistant manages the hiding of the assistant
@@ -66,6 +68,7 @@ class StaticCodeAssistant : public QObject {
     KTextEditor::Cursor m_assistantStartedAt;
     KDevelop::IndexedString m_currentDocument;
     KSharedPtr<KDevelop::IAssistant> m_activeAssistant;
+    QHash< KTextEditor::View*, KSharedPtr<RenameAssistant> > m_renameAssistants;
     bool m_activeProblemAssistant;
     QTimer* m_timer;
     
diff --git a/languages/cpp/codegen/renameassistant.cpp b/languages/cpp/codegen/renameassistant.cpp
new file mode 100644
index 0000000..e92f89f
--- /dev/null
+++ b/languages/cpp/codegen/renameassistant.cpp
@@ -0,0 +1,171 @@
+/*
+   Copyright 2010 Olivier de Gaalon <olivier.jg@gmail.com>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License version 2 as published by the Free Software Foundation.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public License
+   along with this library; see the file COPYING.LIB.  If not, write to
+   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.
+*/
+
+#include "renameassistant.h"
+#include <language/duchain/duchainutils.h>
+#include <interfaces/icore.h>
+#include <interfaces/idocumentcontroller.h>
+#include <ktexteditor/document.h>
+#include <ktexteditor/view.h>
+#include <language/duchain/duchainlock.h>
+#include <language/duchain/duchain.h>
+#include <interfaces/ilanguagecontroller.h>
+#include <language/duchain/declaration.h>
+#include <klocalizedstring.h>
+#include <language/codegen/documentchangeset.h>
+#include <kmessagebox.h>
+#include <language/backgroundparser/parsejob.h>
+#include <language/backgroundparser/backgroundparser.h>
+#include <language/duchain/functiondefinition.h>
+#include <language/duchain/classfunctiondeclaration.h>
+
+using namespace  KDevelop;
+using namespace Cpp;
+
+typedef QMap<IndexedString, QList <RangeInRevision> > UsesList;
+
+class RenameAction : public KDevelop::IAssistantAction {
+public:
+  RenameAction(Identifier oldDeclarationName, QString newDeclarationName, UsesList oldDeclarationUses)
+  : m_oldDeclarationName(oldDeclarationName),
+    m_newDeclarationName(newDeclarationName),
+    m_oldDeclarationUses(oldDeclarationUses)
+  { }
+
+  virtual QString description() const {
+    return i18n("Rename \"%1\" to \"%2\"", m_oldDeclarationName.toString(), m_newDeclarationName);
+  }
+
+  virtual void execute() {
+    UsesList::iterator it;
+    DocumentChangeSet changes;
+    for (it = m_oldDeclarationUses.begin(); it != m_oldDeclarationUses.end(); ++it) {
+      foreach (RangeInRevision range, it.value()) {
+        DocumentChange useRename
+            (it.key(), range.castToSimpleRange(), m_oldDeclarationName.toString(), m_newDeclarationName);
+        changes.addChange( useRename );
+        changes.setReplacementPolicy(DocumentChangeSet::WarnOnFailedChange);
+      }
+    }
+
+    DocumentChangeSet::ChangeResult result = changes.applyAllChanges();
+    if(!result)
+      KMessageBox::error(0, i18n("Failed to apply changes: %1", result.m_failureReason));
+  }
+private:
+  Identifier m_oldDeclarationName;
+  QString m_newDeclarationName;
+  UsesList m_oldDeclarationUses;
+};
+
+RenameAssistant::RenameAssistant(KTextEditor::View *view) :
+ITextAssistant(view),
+m_documentUrl(IndexedString(view->document()->url())),
+m_isUseful(false)
+{}
+
+void RenameAssistant::reset() {
+  m_oldDeclarationName = Identifier();
+  m_newDeclarationRange.clear();
+  m_oldDeclarationUses.clear();
+  m_isUseful = false;
+}
+
+bool rangesConnect(const KTextEditor::Range &firstRange, const KTextEditor::Range &secondRange) {
+  KTextEditor::Range expanded = KTextEditor::Range(
+      secondRange.start().line(), secondRange.start().column() - 1,
+      secondRange.end().line(), secondRange.end().column() + 1
+  );
+  return !firstRange.intersect(expanded).isEmpty();
+}
+
+Declaration* RenameAssistant::getValidDeclarationForChangedRange(KTextEditor::Range changed) {
+  SimpleCursor cursor(changed.start());
+
+  Declaration* declaration = DUChainUtils::itemUnderCursor(m_documentUrl.toUrl(), cursor);
+
+  //If it's null we could be appending, but there's a case where appending gives a wrong decl
+  //and not a null declaration ... "type var(init)", so check for that too
+  if (!declaration || !rangesConnect(declaration->rangeInCurrentRevision().textRange(), changed))
+    declaration = DUChainUtils::itemUnderCursor(m_documentUrl.toUrl(), SimpleCursor(cursor.line, --cursor.column));
+
+  //In this case, we may either not have a decl at the cursor, or we got a decl, but are editing its use.
+  //In either of those cases, give up and return 0
+  if (!declaration || !rangesConnect(declaration->rangeInCurrentRevision().textRange(), changed))
+    return 0;
+
+  //Now we know we're editing a declaration, but some declarations we don't offer a rename for
+  //basically that's any declaration that wouldn't be fully renamed just by renaming its uses.
+  //FIXME: the following may not be exactly the desired filter
+  if (declaration->internalContext() || declaration->isForwardDeclaration()) {
+    //make an exception for non-class functions
+    if(!declaration->isFunctionDeclaration() || dynamic_cast<ClassFunctionDeclaration*>(declaration))
+      return 0;
+  }
+
+  return declaration;
+}
+
+void RenameAssistant::textChanged(KTextEditor::Range invocationRange, QString removedText) {
+  clearActions();
+
+  //If the inserted text isn't valid for a variable name, consider the editing ended
+  QRegExp validDeclName("^[0-9a-zA-Z_]*$");
+  if (removedText.isEmpty() && !validDeclName.exactMatch(view()->document()->text(invocationRange))) {
+    reset();
+    return;
+  }
+
+  KDevelop::DUChainReadLocker lock(KDevelop::DUChain::lock());
+
+  //If we've stopped editing m_newDeclarationRange, reset and see if there's another declaration being edited
+  if (!m_newDeclarationRange.data() || !rangesConnect(m_newDeclarationRange->range().textRange(), invocationRange)) {
+    reset();
+
+    if (Declaration* declAtCursor = getValidDeclarationForChangedRange(invocationRange)) {
+      QMap< IndexedString, QList<RangeInRevision> > declUses = declAtCursor->uses();
+      if (declUses.size() > 0) {
+        m_oldDeclarationName = declAtCursor->identifier();
+        m_oldDeclarationUses = declUses;
+
+        KTextEditor::Range newRange = declAtCursor->rangeInCurrentRevision().textRange();
+        if (removedText.isEmpty() && newRange.intersect(invocationRange).isEmpty())
+          newRange = newRange.encompass(invocationRange); //if text was added to the ends, encompass it
+
+        m_newDeclarationRange.attach(new PersistentMovingRange(newRange, m_documentUrl, true));
+      }
+      else  return; //new declaration is use-less
+    }
+    else return; //not editing a declaration
+  }
+
+  //Unfortunately this happens when you make a selection including one end of the decl's range and replace it
+  if (removedText.isEmpty() && m_newDeclarationRange->range().textRange().intersect(invocationRange).isEmpty())
+    m_newDeclarationRange.attach(m_newDeclarationRange->range().textRange().encompass(invocationRange));
+
+  m_newDeclarationName = view()->document()->text(m_newDeclarationRange->range().textRange());
+
+  if (m_newDeclarationName == m_oldDeclarationName.toString())
+    return;
+
+  m_isUseful = true;
+  addAction(IAssistantAction::Ptr(new RenameAction(m_oldDeclarationName, m_newDeclarationName, m_oldDeclarationUses)));
+  emit actionsChanged();
+}
+
+#include "renameassistant.moc"
diff --git a/languages/cpp/codegen/renameassistant.h b/languages/cpp/codegen/renameassistant.h
new file mode 100644
index 0000000..885ce1b
--- /dev/null
+++ b/languages/cpp/codegen/renameassistant.h
@@ -0,0 +1,56 @@
+/*
+   Copyright 2010 Olivier de Gaalon <olivier.jg@gmail.com>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License version 2 as published by the Free Software Foundation.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public License
+   along with this library; see the file COPYING.LIB.  If not, write to
+   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CPP_RENAMEEASSISTANT_H
+#define CPP_RENAMEEASSISTANT_H
+
+#include <interfaces/iassistant.h>
+#include <language/duchain/identifier.h>
+#include <language/duchain/topducontext.h>
+#include <language/duchain/types/indexedtype.h>
+#include <language/duchain/indexedstring.h>
+#include <language/duchain/declaration.h>
+
+
+namespace KDevelop {
+class ParseJob;
+}
+namespace Cpp {
+
+class RenameAssistant : public KDevelop::ITextAssistant {
+Q_OBJECT
+public:
+  RenameAssistant(KTextEditor::View *view);
+  void textChanged(KTextEditor::Range invocationRange, QString removedText = QString());
+  bool isUseful() { return m_isUseful; }
+
+private:
+  void reset();
+  KDevelop::Declaration* getValidDeclarationForChangedRange(KTextEditor::Range changed);
+
+  KDevelop::Identifier m_oldDeclarationName;
+  QString m_newDeclarationName;
+  KDevelop::PersistentMovingRange::Ptr m_newDeclarationRange;
+  QMap <KDevelop::IndexedString, QList <KDevelop::RangeInRevision > > m_oldDeclarationUses;
+  KDevelop::IndexedString m_documentUrl;
+  bool m_isUseful;
+};
+
+}
+
+#endif // CPP_RENAMEEASSISTANT_H
