CppEditor: Fix "insert def from decl" for template return types

Fixes: QTCREATORBUG-26397
Change-Id: Ia215f2c2b5da708b0fd7c894987683b305f4ccec
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
Christian Kandeler
2021-10-26 15:16:23 +02:00
parent a1f088376a
commit 05e698a478
6 changed files with 99 additions and 17 deletions

View File

@@ -844,3 +844,15 @@ void Control::addSymbol(Symbol *symbol)
{
d->symbols.push_back(symbol);
}
const Name *Control::toName(const QList<const Name *> &names)
{
const Name *n = nullptr;
for (int i = names.size() - 1; i >= 0; --i) {
if (! n)
n = names.at(i);
else
n = qualifiedNameId(names.at(i), n);
}
return n;
}

View File

@@ -218,6 +218,8 @@ public:
bool hasSymbol(Symbol *symbol) const;
void addSymbol(Symbol *symbol);
const Name *toName(const QList<const Name *> &names);
private:
class Data;
friend class Data;

View File

@@ -283,8 +283,21 @@ public:
number->size()));
}
}
temps.append(control()->templateNameId(identifier(name->identifier()), name->isSpecialization(),
args.data(), args.size()));
const FullySpecifiedType ty = rewrite->env->apply(name->identifier(), rewrite);
const Name * const minName = ty->isNamedType() ? ty->asNamedType()->name() : name;
const TemplateNameId * const newTemplateNameId = control()->templateNameId(
identifier(minName->identifier()), name->isSpecialization(), args.data(),
args.size());
const QList<const Name *> names = disassembledName(minName);
if (names.size() == 1) {
temps.append(newTemplateNameId);
} else {
const Name * const newBaseName = control()->toName(names.mid(0, names.size() - 1));
const Name * const fullName = control()->qualifiedNameId(newBaseName,
newTemplateNameId);
temps.append(fullName);
}
}
void visit(const DestructorNameId *name) override
@@ -317,6 +330,36 @@ public: // attributes
SubstitutionEnvironment *env;
RewriteType rewriteType;
RewriteName rewriteName;
private:
static QList<const Name *> disassembledName(const Name *name)
{
class NameDisassembler : public NameVisitor
{
public:
QList<const Name *> names() const { return m_names; }
void visit(const AnonymousNameId *n) override { m_names << n; }
virtual void visit(const Identifier *n) override { m_names << n; }
virtual void visit(const TemplateNameId *n) override { m_names << n; }
virtual void visit(const DestructorNameId *n) override { m_names << n; }
virtual void visit(const OperatorNameId *n) override { m_names << n; }
virtual void visit(const ConversionNameId *n) override { m_names << n; }
virtual void visit(const SelectorNameId *n) override { m_names << n; }
virtual void visit(const QualifiedNameId *n) override
{
if (n->base())
n->base()->accept(this);
n->name()->accept(this);
}
private:
QList<const Name *> m_names;
};
NameDisassembler nd;
nd.accept(name);
return nd.names();
}
};
SubstitutionEnvironment::SubstitutionEnvironment()

View File

@@ -241,19 +241,6 @@ static bool symbolIdentical(Symbol *s1, Symbol *s2)
return QByteArray(s1->fileName()) == QByteArray(s2->fileName());
}
static const Name *toName(const QList<const Name *> &names, Control *control)
{
const Name *n = nullptr;
for (int i = names.size() - 1; i >= 0; --i) {
if (! n)
n = names.at(i);
else
n = control->qualifiedNameId(names.at(i), n);
}
return n;
}
static bool isInlineNamespace(ClassOrNamespace *con, const Name *name)
{
const QList<LookupItem> items = con->find(name);
@@ -282,12 +269,12 @@ const Name *LookupContext::minimalName(Symbol *symbol, ClassOrNamespace *target,
// eliminate inline namespaces
QList<const Name *> minimal = names;
for (int i = minimal.size() - 2; i >= 0; --i) {
const Name *candidate = toName(minimal.mid(0, i + 1), control);
const Name *candidate = control->toName(minimal.mid(0, i + 1));
if (isInlineNamespace(target, candidate))
minimal.removeAt(i);
}
return toName(minimal, control);
return control->toName(minimal);
}
return nullptr;

View File

@@ -4707,6 +4707,43 @@ N::S N::foo(const S &s)
QuickFixOperationTest(testDocuments, &factory);
}
void QuickfixTest::testInsertDefFromDeclAliasTemplateAsReturnType()
{
QList<TestDocumentPtr> testDocuments;
QByteArray original;
QByteArray expected;
// Header File
original = R"(
struct foo {
struct foo2 {
template <typename T> using MyType = T;
MyType<int> @bar();
};
};
)";
expected = original;
testDocuments << CppTestDocument::create("file.h", original, expected);
// Source File
original = R"(
#include "file.h"
)";
expected = R"(
#include "file.h"
foo::foo2::MyType<int> foo::foo2::bar()
{
}
)";
testDocuments << CppTestDocument::create("file.cpp", original, expected);
InsertDefFromDecl factory;
QuickFixOperationTest(testDocuments, &factory);
}
void QuickfixTest::testInsertDefsFromDecls_data()
{
QTest::addColumn<QByteArrayList>("headers");

View File

@@ -155,6 +155,7 @@ private slots:
void testInsertDefFromDeclTemplateFunction();
void testInsertDefFromDeclNotTriggeredForFriendFunc();
void testInsertDefFromDeclMinimalFunctionParameterType();
void testInsertDefFromDeclAliasTemplateAsReturnType();
void testInsertDefsFromDecls_data();
void testInsertDefsFromDecls();