forked from qt-creator/qt-creator
C++: Improve template argument detection for nested types
Change-Id: I7dd3f552f0e85413de8e58047d1fba39c7237182 Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
This commit is contained in:
committed by
Orgad Shaneh
parent
e1393c71ab
commit
8be26d070e
@@ -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()
|
||||
|
Reference in New Issue
Block a user