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);
|
void instantiate(LookupScopePrivate *lookupScope, LookupScopePrivate *instantiation);
|
||||||
private:
|
private:
|
||||||
bool isInstantiationNeeded(LookupScopePrivate *lookupScope) const;
|
bool isInstantiationNeeded(LookupScopePrivate *lookupScope) const;
|
||||||
bool containsTemplateType(Declaration *declaration) const;
|
|
||||||
bool containsTemplateType(Function *function) const;
|
struct TemplateFinder : public TypeVisitor, public NameVisitor
|
||||||
NamedType *findNamedType(Type *memberType) const;
|
{
|
||||||
|
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;
|
ProcessedSet _alreadyConsideredInstantiations;
|
||||||
Clone &_cloner;
|
Clone &_cloner;
|
||||||
@@ -1461,50 +1528,16 @@ bool Instantiator::isInstantiationNeeded(LookupScopePrivate *lookupScope) const
|
|||||||
{
|
{
|
||||||
foreach (Symbol *s, lookupScope->_symbols) {
|
foreach (Symbol *s, lookupScope->_symbols) {
|
||||||
if (Class *klass = s->asClass()) {
|
if (Class *klass = s->asClass()) {
|
||||||
int memberCount = klass->memberCount();
|
TemplateFinder finder(_subst);
|
||||||
for (int i = 0; i < memberCount; ++i) {
|
finder.accept(klass);
|
||||||
Symbol *memberAsSymbol = klass->memberAt(i);
|
if (finder.found())
|
||||||
if (Declaration *declaration = memberAsSymbol->asDeclaration()) {
|
return true;
|
||||||
if (containsTemplateType(declaration))
|
|
||||||
return true;
|
|
||||||
} else if (Function *function = memberAsSymbol->asFunction()) {
|
|
||||||
if (containsTemplateType(function))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
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()
|
void LookupScopePrivate::flush()
|
||||||
{
|
{
|
||||||
if (! _todo.isEmpty()) {
|
if (! _todo.isEmpty()) {
|
||||||
|
@@ -2874,6 +2874,29 @@ void CppToolsPlugin::test_completion_data()
|
|||||||
) << _("p->") << (QStringList()
|
) << _("p->") << (QStringList()
|
||||||
<< QLatin1String("Foo")
|
<< QLatin1String("Foo")
|
||||||
<< QLatin1String("bar"));
|
<< 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()
|
void CppToolsPlugin::test_completion_member_access_operator()
|
||||||
|
Reference in New Issue
Block a user