forked from qt-creator/qt-creator
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:
12
src/libs/3rdparty/cplusplus/Control.cpp
vendored
12
src/libs/3rdparty/cplusplus/Control.cpp
vendored
@@ -844,3 +844,15 @@ void Control::addSymbol(Symbol *symbol)
|
|||||||
{
|
{
|
||||||
d->symbols.push_back(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;
|
||||||
|
}
|
||||||
|
2
src/libs/3rdparty/cplusplus/Control.h
vendored
2
src/libs/3rdparty/cplusplus/Control.h
vendored
@@ -218,6 +218,8 @@ public:
|
|||||||
bool hasSymbol(Symbol *symbol) const;
|
bool hasSymbol(Symbol *symbol) const;
|
||||||
void addSymbol(Symbol *symbol);
|
void addSymbol(Symbol *symbol);
|
||||||
|
|
||||||
|
const Name *toName(const QList<const Name *> &names);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Data;
|
class Data;
|
||||||
friend class Data;
|
friend class Data;
|
||||||
|
@@ -283,8 +283,21 @@ public:
|
|||||||
number->size()));
|
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
|
void visit(const DestructorNameId *name) override
|
||||||
@@ -317,6 +330,36 @@ public: // attributes
|
|||||||
SubstitutionEnvironment *env;
|
SubstitutionEnvironment *env;
|
||||||
RewriteType rewriteType;
|
RewriteType rewriteType;
|
||||||
RewriteName rewriteName;
|
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()
|
SubstitutionEnvironment::SubstitutionEnvironment()
|
||||||
|
@@ -241,19 +241,6 @@ static bool symbolIdentical(Symbol *s1, Symbol *s2)
|
|||||||
return QByteArray(s1->fileName()) == QByteArray(s2->fileName());
|
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)
|
static bool isInlineNamespace(ClassOrNamespace *con, const Name *name)
|
||||||
{
|
{
|
||||||
const QList<LookupItem> items = con->find(name);
|
const QList<LookupItem> items = con->find(name);
|
||||||
@@ -282,12 +269,12 @@ const Name *LookupContext::minimalName(Symbol *symbol, ClassOrNamespace *target,
|
|||||||
// eliminate inline namespaces
|
// eliminate inline namespaces
|
||||||
QList<const Name *> minimal = names;
|
QList<const Name *> minimal = names;
|
||||||
for (int i = minimal.size() - 2; i >= 0; --i) {
|
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))
|
if (isInlineNamespace(target, candidate))
|
||||||
minimal.removeAt(i);
|
minimal.removeAt(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
return toName(minimal, control);
|
return control->toName(minimal);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@@ -4707,6 +4707,43 @@ N::S N::foo(const S &s)
|
|||||||
QuickFixOperationTest(testDocuments, &factory);
|
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()
|
void QuickfixTest::testInsertDefsFromDecls_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QByteArrayList>("headers");
|
QTest::addColumn<QByteArrayList>("headers");
|
||||||
|
@@ -155,6 +155,7 @@ private slots:
|
|||||||
void testInsertDefFromDeclTemplateFunction();
|
void testInsertDefFromDeclTemplateFunction();
|
||||||
void testInsertDefFromDeclNotTriggeredForFriendFunc();
|
void testInsertDefFromDeclNotTriggeredForFriendFunc();
|
||||||
void testInsertDefFromDeclMinimalFunctionParameterType();
|
void testInsertDefFromDeclMinimalFunctionParameterType();
|
||||||
|
void testInsertDefFromDeclAliasTemplateAsReturnType();
|
||||||
void testInsertDefsFromDecls_data();
|
void testInsertDefsFromDecls_data();
|
||||||
void testInsertDefsFromDecls();
|
void testInsertDefsFromDecls();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user