From bddaab248bce70b8aac2e91fc67c3d70a94eab2f Mon Sep 17 00:00:00 2001
From: Lorenz Haas <lykurg@gmail.com>
Date: Fri, 24 May 2013 09:43:41 +0200
Subject: [PATCH] CppEditor: Consider base class namespace in "Insert Virtual
 Methods"

Change-Id: Ife5f34d410781d3c1ae75a3bf1c412f7d76dca80
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@digia.com>
---
 src/plugins/cppeditor/cppeditorplugin.h    |  1 +
 src/plugins/cppeditor/cppquickfix_test.cpp | 53 +++++++++++++++
 src/plugins/cppeditor/cppquickfixes.cpp    | 79 ++++++++--------------
 3 files changed, 84 insertions(+), 49 deletions(-)

diff --git a/src/plugins/cppeditor/cppeditorplugin.h b/src/plugins/cppeditor/cppeditorplugin.h
index 301aa880cdc..239e6dc8441 100644
--- a/src/plugins/cppeditor/cppeditorplugin.h
+++ b/src/plugins/cppeditor/cppeditorplugin.h
@@ -213,6 +213,7 @@ private slots:
     void test_quickfix_InsertVirtualMethods_outside();
     void test_quickfix_InsertVirtualMethods_implementationFile();
     void test_quickfix_InsertVirtualMethods_notrigger_allImplemented();
+    void test_quickfix_InsertVirtualMethods_BaseClassInNamespace();
 
     // The following tests depend on the projects that are loaded on startup
     // and will be skipped in case no projects are loaded.
diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp
index b68458b81e0..17823ecadef 100644
--- a/src/plugins/cppeditor/cppquickfix_test.cpp
+++ b/src/plugins/cppeditor/cppquickfix_test.cpp
@@ -2477,3 +2477,56 @@ void CppEditorPlugin::test_quickfix_InsertVirtualMethods_notrigger_allImplemente
     TestCase data(original, expected);
     data.run(&factory);
 }
+
+/// Check: Qualified names.
+void CppEditorPlugin::test_quickfix_InsertVirtualMethods_BaseClassInNamespace()
+{
+    QList<TestDocumentPtr> testFiles;
+    QByteArray original;
+    QByteArray expected;
+
+    // Header File
+    original =
+        "namespace BaseNS {enum BaseEnum {EnumA = 1};}\n"
+        "namespace BaseNS {\n"
+        "class Base {\n"
+        "public:\n"
+        "    virtual BaseEnum a(BaseEnum e);\n"
+        "};\n"
+        "}\n"
+        "class Deri@ved : public BaseNS::Base {\n"
+        "public:\n"
+        "    Derived();\n"
+        "};";
+    expected =
+        "namespace BaseNS {enum BaseEnum {EnumA = 1};}\n"
+        "namespace BaseNS {\n"
+        "class Base {\n"
+        "public:\n"
+        "    virtual BaseEnum a(BaseEnum e);\n"
+        "};\n"
+        "}\n"
+        "class Deri@ved : public BaseNS::Base {\n"
+        "public:\n"
+        "    Derived();\n"
+        "\n"
+        "    // Base interface\n"
+        "public:\n"
+        "    virtual BaseNS::BaseEnum a(BaseNS::BaseEnum e);\n"
+        "};\n";
+    testFiles << TestDocument::create(original, expected, QLatin1String("file.h"));
+
+    // Source File
+    original = "#include \"file.h\"\n";
+    expected =
+        "#include \"file.h\"\n"
+        "\n\n"
+        "BaseNS::BaseEnum Derived::a(BaseNS::BaseEnum e)\n"
+        "{\n}\n";
+    testFiles << TestDocument::create(original, expected, QLatin1String("file.cpp"));
+
+    InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest(
+                                     InsertVirtualMethodsDialog::ModeImplementationFile, true));
+    TestCase data(testFiles);
+    data.run(&factory);
+}
diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp
index b577a808604..1058fdad058 100644
--- a/src/plugins/cppeditor/cppquickfixes.cpp
+++ b/src/plugins/cppeditor/cppquickfixes.cpp
@@ -4585,12 +4585,23 @@ public:
                     QLatin1String("QuickFix/InsertVirtualMethods/hideReimplementedFunctions"),
                     m_factory->hideReimplementedFunctions());
 
-        // Insert declarations (and definition if InsideClass)
+        // Insert declarations (and definition if Inside-/OutsideClass)
         Overview printer = CppCodeStyleSettings::currentProjectCodeStyleOverview();
         printer.showFunctionSignatures = true;
         printer.showReturnTypes = true;
         printer.showArgumentNames = true;
         ChangeSet headerChangeSet;
+        const CppRefactoringChanges refactoring(assistInterface()->snapshot());
+        const QString filename = assistInterface()->currentFile()->fileName();
+        const CppRefactoringFilePtr headerFile = refactoring.file(filename);
+        const LookupContext targetContext(headerFile->cppDocument(), assistInterface()->snapshot());
+
+        const Class *targetClass = m_classAST->symbol;
+        ClassOrNamespace *targetCoN = targetContext.lookupType(targetClass->scope());
+        if (!targetCoN)
+            targetCoN = targetContext.globalNamespace();
+        UseMinimalNames useMinimalNames(targetCoN);
+        Control *control = assistInterface()->context().bindings()->control().data();
         for (int i = 0; i < m_factory->classFunctionModel->rowCount(); ++i) {
             const QStandardItem *parent =
                     m_factory->classFunctionModel->invisibleRootItem()->child(i, 0);
@@ -4614,11 +4625,23 @@ public:
                         item->data(InsertVirtualMethodsDialog::ClassOrFunction).value<void *>();
 
                 // Construct declaration
-                QString declaration = InsertDeclOperation::generateDeclaration(func);
+                // setup rewriting to get minimally qualified names
+                SubstitutionEnvironment env;
+                env.setContext(assistInterface()->context());
+                env.switchScope(clazz->enclosingScope());
+                env.enter(&useMinimalNames);
+
+                QString declaration;
+                const FullySpecifiedType tn = rewriteType(func->type(), &env, control);
+                declaration += printer.prettyType(tn, func->unqualifiedName());
+
                 if (m_factory->insertKeywordVirtual())
                     declaration = QLatin1String("virtual ") + declaration;
                 if (m_factory->implementationMode() & InsertVirtualMethodsDialog::ModeInsideClass)
-                    declaration.replace(declaration.size() - 2, 2, QLatin1String("\n{\n}\n"));
+                    declaration += QLatin1String("\n{\n}\n");
+                else
+                    declaration += QLatin1String(";\n");
+
                 const InsertionPointLocator::AccessSpec spec =
                         static_cast<InsertionPointLocator::AccessSpec>(
                             item->data(InsertVirtualMethodsDialog::AccessSpec).toInt());
@@ -4630,54 +4653,12 @@ public:
                     lastAccessSpecString = accessSpecString;
                 }
                 headerChangeSet.insert(m_insertPosDecl, declaration);
-            }
-        }
 
-        // Insert outside class
-        const QString filename = assistInterface()->currentFile()->fileName();
-        const CppRefactoringChanges refactoring(assistInterface()->snapshot());
-        const CppRefactoringFilePtr headerFile = refactoring.file(filename);
-        const Document::Ptr headerDoc = headerFile->cppDocument();
-        Class *targetClass = m_classAST->symbol;
-        if (m_factory->implementationMode() & InsertVirtualMethodsDialog::ModeOutsideClass) {
-            // make target lookup context
-            unsigned line, column;
-            headerDoc->translationUnit()->getPosition(m_insertPosOutside, &line, &column);
-            Scope *targetScope = headerDoc->scopeAt(line, column);
-            const LookupContext targetContext(headerDoc, assistInterface()->snapshot());
-            ClassOrNamespace *targetCoN = targetContext.lookupType(targetScope);
-            if (!targetCoN)
-                targetCoN = targetContext.globalNamespace();
-
-            // setup rewriting to get minimally qualified names
-            SubstitutionEnvironment env;
-            env.setContext(assistInterface()->context());
-            env.switchScope(targetClass);
-            UseMinimalNames q(targetCoN);
-            env.enter(&q);
-            Control *control = assistInterface()->context().bindings()->control().data();
-            const QString fullClassName = printer.prettyName(LookupContext::minimalName(
-                                                                 targetClass, targetCoN, control));
-
-            for (int i = 0; i < m_factory->classFunctionModel->rowCount(); ++i) {
-                const QStandardItem *parent =
-                        m_factory->classFunctionModel->invisibleRootItem()->child(i, 0);
-                if (!parent->isCheckable() || parent->checkState() == Qt::Unchecked)
-                    continue;
-
-                for (int j = 0; j < parent->rowCount(); ++j) {
-                    const QStandardItem *item = parent->child(j, 0);
-                    if (!item->isCheckable() || item->checkState() == Qt::Unchecked)
-                        continue;
-                    const Function *func = (const Function *)
-                            item->data(InsertVirtualMethodsDialog::ClassOrFunction).value<void *>();
-
-                    // rewrite the function type and name
-                    const FullySpecifiedType tn = rewriteType(func->type(), &env, control);
-                    const QString name = fullClassName + QLatin1String("::") +
-                            printer.prettyName(func->name());
+                // Insert definition outside class
+                if (m_factory->implementationMode() & InsertVirtualMethodsDialog::ModeOutsideClass) {
+                    const QString name = printer.prettyName(targetClass->name()) +
+                            QLatin1String("::") + printer.prettyName(func->name());
                     const QString defText = printer.prettyType(tn, name) + QLatin1String("\n{\n}");
-
                     headerChangeSet.insert(m_insertPosOutside,  QLatin1String("\n\n") + defText);
                 }
             }
-- 
GitLab