Commit 8be26d07 authored by Orgad Shaneh's avatar Orgad Shaneh Committed by Orgad Shaneh
Browse files

C++: Improve template argument detection for nested types



Change-Id: I7dd3f552f0e85413de8e58047d1fba39c7237182
Reviewed-by: default avatarNikolai Kosjar <nikolai.kosjar@theqtcompany.com>
parent e1393c71
......@@ -605,9 +605,76 @@ public:
void instantiate(LookupScopePrivate *lookupScope, LookupScopePrivate *instantiation);
private:
bool isInstantiationNeeded(LookupScopePrivate *lookupScope) const;
bool containsTemplateType(Declaration *declaration) const;
bool containsTemplateType(Function *function) const;
NamedType *findNamedType(Type *memberType) const;
struct TemplateFinder : public TypeVisitor, public NameVisitor
{
public:
TemplateFinder(Subst &subst) : _subst(subst), _found(false) {}
inline void accept(Type *type) { TypeVisitor::accept(type); }
inline void accept(const Name *name) { NameVisitor::accept(name); }
bool found() const { return _found; }
private:
void visit(PointerType *type) override { accept(type->elementType().type()); }
void visit(ReferenceType *type) override { accept(type->elementType().type()); }
void visit(NamedType *type) override { accept(type->name()); }
void visit(Function *type) override
{
accept(type->returnType().type());
if (_found)
return;
for (int i = 0, total = type->argumentCount(); i < total; ++i) {
accept(type->argumentAt(i)->type().type());
if (_found)
return;
}
}
void visit(Class *type) override
{
for (int i = 0, total = type->memberCount(); i < total; ++i) {
accept(type->memberAt(i)->type().type());
if (_found)
return;
}
}
void visit(const Identifier *name) override
{
if (_subst.contains(name))
_found = true;
}
void visit(const TemplateNameId *name) override
{
if (const Identifier *identifier = name->identifier())
visit(identifier);
if (_found)
return;
for (unsigned i = 0, total = name->templateArgumentCount(); i < total; ++i) {
accept(name->templateArgumentAt(i).type());
if (_found)
return;
}
}
void visit(const ConversionNameId *name) override
{
accept(name->type().type());
}
void visit(const QualifiedNameId *name) override
{
accept(name->base());
if (!_found)
accept(name->name());
}
Subst &_subst;
bool _found;
};
ProcessedSet _alreadyConsideredInstantiations;
Clone &_cloner;
......@@ -1461,50 +1528,16 @@ bool Instantiator::isInstantiationNeeded(LookupScopePrivate *lookupScope) const
{
foreach (Symbol *s, lookupScope->_symbols) {
if (Class *klass = s->asClass()) {
int memberCount = klass->memberCount();
for (int i = 0; i < memberCount; ++i) {
Symbol *memberAsSymbol = klass->memberAt(i);
if (Declaration *declaration = memberAsSymbol->asDeclaration()) {
if (containsTemplateType(declaration))
return true;
} else if (Function *function = memberAsSymbol->asFunction()) {
if (containsTemplateType(function))
return true;
}
}
TemplateFinder finder(_subst);
finder.accept(klass);
if (finder.found())
return true;
}
}
return false;
}
bool Instantiator::containsTemplateType(Declaration *declaration) const
{
Type *memberType = declaration->type().type();
NamedType *namedType = findNamedType(memberType);
return namedType && _subst.contains(namedType->name());
}
bool Instantiator::containsTemplateType(Function *function) const
{
Type *returnType = function->returnType().type();
NamedType *namedType = findNamedType(returnType);
return namedType && _subst.contains(namedType->name());
//TODO: in future we will need also check function arguments, for now returned value is enough
}
NamedType *Instantiator::findNamedType(Type *memberType) const
{
if (NamedType *namedType = memberType->asNamedType())
return namedType;
else if (PointerType *pointerType = memberType->asPointerType())
return findNamedType(pointerType->elementType().type());
else if (ReferenceType *referenceType = memberType->asReferenceType())
return findNamedType(referenceType->elementType().type());
return 0;
}
void LookupScopePrivate::flush()
{
if (! _todo.isEmpty()) {
......
......@@ -2874,6 +2874,29 @@ void CppToolsPlugin::test_completion_data()
) << _("p->") << (QStringList()
<< QLatin1String("Foo")
<< QLatin1String("bar"));
QTest::newRow("qualified_name_in_nested_type") << _(
"template<typename _Tp>\n"
"struct Temp {\n"
" struct Nested {\n"
" typedef typename _Tp::Nested2 N;\n"
" };\n"
"};\n"
"\n"
"struct Foo {\n"
" struct Nested2 {\n"
" int bar;\n"
" };\n"
"};\n"
"\n"
"void func()\n"
"{\n"
" Temp<Foo>::Nested::N p;\n"
" @;\n"
"}\n"
) << _("p.") << (QStringList()
<< QLatin1String("Nested2")
<< QLatin1String("bar"));
}
void CppToolsPlugin::test_completion_member_access_operator()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment