CPlusPlus: Improve type name minimization

... for function parameters. These are located in the scope of the
surrounding class or namespace.
This uncovered a bug in the "Insert Virtual Functions of Base Classes"
quickfix, which we also fix here.

Fixes: QTCREATORBUG-8030
Change-Id: I7f11659dc8e252e3819df8178734e8958fa1b496
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
Christian Kandeler
2021-02-02 14:01:15 +01:00
parent f47c7b2e90
commit b066b3029e
4 changed files with 103 additions and 9 deletions

View File

@@ -142,6 +142,17 @@ public:
funTy->setReturnType(rewrite->rewriteType(type->returnType()));
// Function parameters have the function's enclosing scope.
Scope *scope = nullptr;
ClassOrNamespace *target = nullptr;
if (rewrite->env->context().bindings())
target = rewrite->env->context().lookupType(type->enclosingScope());
UseMinimalNames useMinimalNames(target);
if (target) {
scope = rewrite->env->switchScope(type->enclosingScope());
rewrite->env->enter(&useMinimalNames);
}
for (unsigned i = 0, argc = type->argumentCount(); i < argc; ++i) {
Symbol *arg = type->argumentAt(i);
@@ -156,6 +167,11 @@ public:
funTy->addMember(newArg);
}
if (target) {
rewrite->env->switchScope(scope);
rewrite->env->leave();
}
temps.append(funTy);
}

View File

@@ -161,6 +161,7 @@ private slots:
void test_quickfix_InsertDefFromDecl_templateClass();
void test_quickfix_InsertDefFromDecl_templateFunction();
void test_quickfix_InsertDefFromDecl_notTriggeredForFriendFunc();
void test_quickfix_InsertDefFromDecl_minimalFunctionParameterType();
void test_quickfix_InsertDefsFromDecls_data();
void test_quickfix_InsertDefsFromDecls();

View File

@@ -823,16 +823,31 @@ public:
headerChangeSet.insert(m_insertPosDecl, comment);
first = false;
}
// Construct declaration
// setup rewriting to get minimally qualified names
SubstitutionEnvironment env;
env.setContext(context());
env.switchScope(classItem->klass->enclosingScope());
env.enter(&useMinimalNames);
QString declaration;
const FullySpecifiedType tn = rewriteType(funcItem->function->type(), &env, control);
declaration += printer.prettyType(tn, funcItem->function->unqualifiedName());
// Function type minimalization: As base class and derived class could be in
// different namespaces, we must first make the type fully qualified before
// it can get minimized.
Clone cloner(control);
Function newFunc(&cloner, nullptr, const_cast<Function *>(funcItem->function));
newFunc.setEnclosingScope(const_cast<Class *>(targetClass));
SubstitutionEnvironment envQualified;
envQualified.setContext(context());
envQualified.switchScope(classItem->klass->enclosingScope());
UseQualifiedNames useQualifiedNames;
envQualified.enter(&useQualifiedNames);
newFunc.setReturnType(rewriteType(newFunc.returnType(), &envQualified, control));
const int argc = newFunc.argumentCount();
for (int i = 0; i < argc; ++i) {
Argument * const arg = newFunc.argumentAt(i)->asArgument();
QTC_ASSERT(arg, continue);
arg->setType(rewriteType(arg->type(), &envQualified, control));
}
SubstitutionEnvironment envMinimized;
envMinimized.setContext(context());
envMinimized.switchScope(targetClass->enclosingScope());
envMinimized.enter(&useMinimalNames);
const FullySpecifiedType tn = rewriteType(newFunc.type(), &envMinimized, control);
QString declaration = printer.prettyType(tn, newFunc.unqualifiedName());
if (m_factory->settings()->insertVirtualKeyword)
declaration = QLatin1String("virtual ") + declaration;

View File

@@ -4593,6 +4593,68 @@ void CppEditorPlugin::test_quickfix_InsertDefFromDecl_notTriggeredForFriendFunc(
QuickFixOperationTest(singleDocument(contents, ""), &factory);
}
void CppEditorPlugin::test_quickfix_InsertDefFromDecl_minimalFunctionParameterType()
{
QList<QuickFixTestDocument::Ptr> testDocuments;
QByteArray original;
QByteArray expected;
// Header File
original = R"(
class C {
typedef int A;
A @foo(A);
};
)";
expected = original;
testDocuments << QuickFixTestDocument::create("file.h", original, expected);
// Source File
original = R"(
#include "file.h"
)";
expected = R"(
#include "file.h"
C::A C::foo(A)
{
}
)";
testDocuments << QuickFixTestDocument::create("file.cpp", original, expected);
InsertDefFromDecl factory;
QuickFixOperationTest(testDocuments, &factory);
testDocuments.clear();
// Header File
original = R"(
namespace N {
struct S;
S @foo(const S &s);
};
)";
expected = original;
testDocuments << QuickFixTestDocument::create("file.h", original, expected);
// Source File
original = R"(
#include "file.h"
)";
expected = R"(
#include "file.h"
N::S N::foo(const S &s)
{
}
)";
testDocuments << QuickFixTestDocument::create("file.cpp", original, expected);
QuickFixOperationTest(testDocuments, &factory);
}
void CppEditorPlugin::test_quickfix_InsertDefsFromDecls_data()
{
QTest::addColumn<QByteArrayList>("headers");