From ac9fc40645638091dcd32bcdbce7d75dc2140825 Mon Sep 17 00:00:00 2001
From: Erik Verbruggen <erik.verbruggen@nokia.com>
Date: Wed, 6 Oct 2010 15:49:59 +0200
Subject: [PATCH] C++ Editor: check for method existing decl/def when inserting
 new ones.

---
 src/libs/cplusplus/CppRewriter.cpp            |  2 +
 src/plugins/cppeditor/cppinsertdecldef.cpp    | 91 ++++++++++---------
 .../cpptools/cpprefactoringchanges.cpp        |  3 +-
 .../cpptools/insertionpointlocator.cpp        | 10 ++
 4 files changed, 60 insertions(+), 46 deletions(-)

diff --git a/src/libs/cplusplus/CppRewriter.cpp b/src/libs/cplusplus/CppRewriter.cpp
index d91f175a2a5..da87e756aed 100644
--- a/src/libs/cplusplus/CppRewriter.cpp
+++ b/src/libs/cplusplus/CppRewriter.cpp
@@ -132,6 +132,8 @@ public:
         {
             Function *funTy = control()->newFunction(0, 0);
             funTy->copy(type);
+            funTy->setConst(type->isConst());
+            funTy->setVolatile(type->isVolatile());
 
             funTy->setName(rewrite->rewriteName(type->name()));
 
diff --git a/src/plugins/cppeditor/cppinsertdecldef.cpp b/src/plugins/cppeditor/cppinsertdecldef.cpp
index cc8b93201d9..0df1a8ba802 100644
--- a/src/plugins/cppeditor/cppinsertdecldef.cpp
+++ b/src/plugins/cppeditor/cppinsertdecldef.cpp
@@ -29,12 +29,7 @@
 
 #include "cppinsertdecldef.h"
 
-#include <AST.h>
-#include <ASTVisitor.h>
-#include <CoreTypes.h>
-#include <Names.h>
-#include <Symbols.h>
-#include <TranslationUnit.h>
+#include <CPlusPlus.h>
 #include <cplusplus/ASTPath.h>
 #include <cplusplus/CppRewriter.h>
 #include <cplusplus/LookupContext.h>
@@ -42,6 +37,7 @@
 #include <cpptools/insertionpointlocator.h>
 
 #include <QtCore/QCoreApplication>
+#include <QtCore/QDir>
 
 using namespace CPlusPlus;
 using namespace CppEditor;
@@ -142,46 +138,49 @@ QList<CppQuickFixOperation::Ptr> DeclFromDef::match(const CppQuickFixState &stat
 
     Function *method = funDef->symbol;
 
-    if (ClassOrNamespace *targetBinding = state.context().lookupParent(method)) {
-        foreach (Symbol *s, targetBinding->symbols()) {
-            if (Class *clazz = s->asClass()) {
-                QList<CppQuickFixOperation::Ptr> results;
-                const QString fn = QString::fromUtf8(clazz->fileName(), clazz->fileNameLength());
+    Scope *enclosingScope = method->enclosingScope();
+    while (! (enclosingScope->isNamespace() || enclosingScope->isClass()))
+        enclosingScope = enclosingScope->enclosingScope();
+    Q_ASSERT(enclosingScope != 0);
+
+    const Name *functionName = method->name();
+    if (! functionName)
+        return noResult(); // warn, anonymous function names are not valid c++
+
+    if (! functionName->isQualifiedNameId())
+        return noResult(); // warn, trying to add a declaration for a global function
+
+    const QualifiedNameId *q = functionName->asQualifiedNameId();
+    if (!q->base())
+        return noResult();
+
+    if (ClassOrNamespace *binding = state.context().lookupType(q->base(), enclosingScope)) {
+        foreach (Symbol *s, binding->symbols()) {
+            if (Class *matchingClass = s->asClass()) {
+                for (Symbol *s = matchingClass->find(q->identifier()); s; s = s->next()) {
+                    if (! s->name())
+                        continue;
+                    else if (! q->identifier()->isEqualTo(s->identifier()))
+                        continue;
+                    else if (! s->type()->isFunctionType())
+                        continue;
+
+                    if (s->type().isEqualTo(method->type()))
+                        return noResult();
+                }
+
+                // a good candidate
+
+                const QString fn = QString::fromUtf8(matchingClass->fileName(),
+                                                     matchingClass->fileNameLength());
                 const QString decl = generateDeclaration(state,
                                                          method,
-                                                         targetBinding);
-                results.append(
-                            singleResult(
-                                new InsertDeclOperation(state, idx, fn, clazz,
-                                                        InsertionPointLocator::Public,
-                                                        decl)));
-//                results.append(
-//                            singleResult(
-//                                new InsertDeclOperation(state, idx, fn, clazz,
-//                                                        InsertionPointLocator::Protected,
-//                                                        decl)));
-//                results.append(
-//                            singleResult(
-//                                new InsertDeclOperation(state, idx, fn, clazz,
-//                                                        InsertionPointLocator::Private,
-//                                                        decl)));
-//                results.append(
-//                            singleResult(
-//                                new InsertDeclOperation(state, idx, fn, clazz,
-//                                                        InsertionPointLocator::PublicSlot,
-//                                                        decl)));
-//                results.append(
-//                            singleResult(
-//                                new InsertDeclOperation(state, idx, fn, clazz,
-//                                                        InsertionPointLocator::ProtectedSlot,
-//                                                        decl)));
-//                results.append(
-//                            singleResult(
-//                                new InsertDeclOperation(state, idx, fn, clazz,
-//                                                        InsertionPointLocator::PrivateSlot,
-//                                                        decl)));
-                return results;
-            } //! \todo support insertion of non-methods into namespaces
+                                                         binding);
+                return singleResult(
+                            new InsertDeclOperation(state, idx, fn, matchingClass,
+                                                    InsertionPointLocator::Public,
+                                                    decl));
+            }
         }
     }
 
@@ -217,9 +216,11 @@ public:
         , m_decl(decl)
         , m_loc(loc)
     {
+        const QString declFile = QString::fromUtf8(decl->fileName(), decl->fileNameLength());
+        const QDir dir = QFileInfo(declFile).dir();
         setDescription(QCoreApplication::translate("CppEditor::InsertDefOperation",
                                                    "Add definition in %1")
-                       .arg(m_loc.fileName()));
+                       .arg(dir.relativeFilePath(m_loc.fileName())));
     }
 
     void performChanges(CppRefactoringFile *,
diff --git a/src/plugins/cpptools/cpprefactoringchanges.cpp b/src/plugins/cpptools/cpprefactoringchanges.cpp
index b320b578b52..68b63f167de 100644
--- a/src/plugins/cpptools/cpprefactoringchanges.cpp
+++ b/src/plugins/cpptools/cpprefactoringchanges.cpp
@@ -104,7 +104,8 @@ CppRefactoringFile::CppRefactoringFile(TextEditor::BaseTextEditor *editor, CPlus
 
 Document::Ptr CppRefactoringFile::cppDocument() const
 {
-    if (!m_cppDocument) {
+    if (!m_cppDocument || !m_cppDocument->translationUnit() ||
+            !m_cppDocument->translationUnit()->ast()) {
         const QString source = document()->toPlainText();
         const QString name = fileName();
         const Snapshot &snapshot = refactoringChanges()->snapshot();
diff --git a/src/plugins/cpptools/insertionpointlocator.cpp b/src/plugins/cpptools/insertionpointlocator.cpp
index 8d924a37fbd..1d6a894f67c 100644
--- a/src/plugins/cpptools/insertionpointlocator.cpp
+++ b/src/plugins/cpptools/insertionpointlocator.cpp
@@ -315,6 +315,7 @@ static bool isSourceFile(const QString &fileName)
 }
 
 /// Currently, we return the end of fileName.cpp
+/// \todo take the definitions of the surrounding declarations into account
 QList<InsertionLocation> InsertionPointLocator::methodDefinition(
     Declaration *declaration) const
 {
@@ -334,6 +335,15 @@ QList<InsertionLocation> InsertionPointLocator::methodDefinition(
     if (doc.isNull())
         return result;
 
+    Snapshot simplified = m_refactoringChanges->snapshot().simplified(doc);
+    if (Symbol *s = simplified.findMatchingDefinition(declaration)) {
+        if (Function *f = s->asFunction()) {
+            if (f->isConst() == declaration->type().isConst()
+                    && f->isVolatile() == declaration->type().isVolatile())
+                return result;
+        }
+    }
+
     TranslationUnit *xUnit = doc->translationUnit();
     unsigned tokenCount = xUnit->tokenCount();
     if (tokenCount < 2) // no tokens available
-- 
GitLab