forked from qt-creator/qt-creator
C++: Fix code completion for nested classes
Fix code completion for nested classes when enclosing is template class. Unit tests Task-number: QTCREATORBUG-8245 (only standalone) Change-Id: Ib31ad4b799db927b56debd4dc3e7403404c1839d Reviewed-by: hjk <qthjk@ovi.com>
This commit is contained in:
committed by
hjk
parent
17748280e8
commit
b1199ef0cc
2
src/libs/3rdparty/cplusplus/Symbol.cpp
vendored
2
src/libs/3rdparty/cplusplus/Symbol.cpp
vendored
@@ -105,7 +105,7 @@ Symbol::Symbol(TranslationUnit *translationUnit, unsigned sourceLocation, const
|
|||||||
|
|
||||||
Symbol::Symbol(Clone *clone, Subst *subst, Symbol *original)
|
Symbol::Symbol(Clone *clone, Subst *subst, Symbol *original)
|
||||||
: _name(clone->name(original->_name, subst)),
|
: _name(clone->name(original->_name, subst)),
|
||||||
_scope(0),
|
_scope(original->_scope),
|
||||||
_next(0),
|
_next(0),
|
||||||
_fileId(clone->control()->stringLiteral(original->fileName(), original->fileNameLength())),
|
_fileId(clone->control()->stringLiteral(original->fileName(), original->fileNameLength())),
|
||||||
_sourceLocation(original->_sourceLocation),
|
_sourceLocation(original->_sourceLocation),
|
||||||
|
|||||||
2
src/libs/3rdparty/cplusplus/Templates.h
vendored
2
src/libs/3rdparty/cplusplus/Templates.h
vendored
@@ -54,6 +54,8 @@ public:
|
|||||||
|
|
||||||
FullySpecifiedType &operator[](const Name *name) { return _map[name]; }
|
FullySpecifiedType &operator[](const Name *name) { return _map[name]; }
|
||||||
|
|
||||||
|
bool contains(const Name *name) const { return _map.find(name) != _map.end(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Control *_control;
|
Control *_control;
|
||||||
Subst *_previous;
|
Subst *_previous;
|
||||||
|
|||||||
@@ -260,7 +260,8 @@ ClassOrNamespace *LookupContext::globalNamespace() const
|
|||||||
return bindings()->globalNamespace();
|
return bindings()->globalNamespace();
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassOrNamespace *LookupContext::lookupType(const Name *name, Scope *scope) const
|
ClassOrNamespace *LookupContext::lookupType(const Name *name, Scope *scope,
|
||||||
|
ClassOrNamespace* enclosingTemplateInstantiation) const
|
||||||
{
|
{
|
||||||
if (! scope) {
|
if (! scope) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -286,16 +287,17 @@ ClassOrNamespace *LookupContext::lookupType(const Name *name, Scope *scope) cons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return lookupType(name, scope->enclosingScope());
|
return lookupType(name, scope->enclosingScope());
|
||||||
} else if (ClassOrNamespace *b = bindings()->lookupType(scope)) {
|
} else if (ClassOrNamespace *b = bindings()->lookupType(scope, enclosingTemplateInstantiation)) {
|
||||||
return b->lookupType(name);
|
return b->lookupType(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassOrNamespace *LookupContext::lookupType(Symbol *symbol) const
|
ClassOrNamespace *LookupContext::lookupType(Symbol *symbol,
|
||||||
|
ClassOrNamespace* enclosingTemplateInstantiation) const
|
||||||
{
|
{
|
||||||
return bindings()->lookupType(symbol);
|
return bindings()->lookupType(symbol, enclosingTemplateInstantiation);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
|
QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
|
||||||
@@ -587,7 +589,8 @@ void CreateBindings::lookupInScope(const Name *name, Scope *scope,
|
|||||||
|
|
||||||
#ifdef DEBUG_LOOKUP
|
#ifdef DEBUG_LOOKUP
|
||||||
Overview oo;
|
Overview oo;
|
||||||
qDebug() << "Found" << id->chars() << "in" << (binding ? oo(binding->_name) : "<null>");
|
qDebug() << "Found" << id->chars() << "in"
|
||||||
|
<< (binding ? oo(binding->_name) : QString::fromAscii("<null>"));
|
||||||
#endif // DEBUG_LOOKUP
|
#endif // DEBUG_LOOKUP
|
||||||
|
|
||||||
LookupItem item;
|
LookupItem item;
|
||||||
@@ -670,16 +673,23 @@ ClassOrNamespace *ClassOrNamespace::lookupType_helper(const Name *name,
|
|||||||
if (_usings.size() == 1) {
|
if (_usings.size() == 1) {
|
||||||
ClassOrNamespace *delegate = _usings.first();
|
ClassOrNamespace *delegate = _usings.first();
|
||||||
|
|
||||||
if (ClassOrNamespace *r = delegate->lookupType_helper(name, processed, /*searchInEnclosingScope = */ true, origin))
|
if (ClassOrNamespace *r = delegate->lookupType_helper(name,
|
||||||
|
processed,
|
||||||
|
/*searchInEnclosingScope = */ true,
|
||||||
|
origin))
|
||||||
return r;
|
return r;
|
||||||
} else {
|
} else {
|
||||||
if (debug)
|
if (debug)
|
||||||
qWarning() << "expected one using declaration. Number of using declarations is:" << _usings.size();
|
qWarning() << "expected one using declaration. Number of using declarations is:"
|
||||||
|
<< _usings.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ClassOrNamespace *u, usings()) {
|
foreach (ClassOrNamespace *u, usings()) {
|
||||||
if (ClassOrNamespace *r = u->lookupType_helper(name, processed, /*searchInEnclosingScope =*/ false, origin))
|
if (ClassOrNamespace *r = u->lookupType_helper(name,
|
||||||
|
processed,
|
||||||
|
/*searchInEnclosingScope =*/ false,
|
||||||
|
origin))
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -740,6 +750,9 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
|
|||||||
// If we are dealling with a template type, more work is required, since we need to
|
// If we are dealling with a template type, more work is required, since we need to
|
||||||
// construct all instantiation data.
|
// construct all instantiation data.
|
||||||
if (templId) {
|
if (templId) {
|
||||||
|
if (_instantiations.contains(templId))
|
||||||
|
return _instantiations[templId];
|
||||||
|
|
||||||
_alreadyConsideredTemplates.insert(templId);
|
_alreadyConsideredTemplates.insert(templId);
|
||||||
ClassOrNamespace *instantiation = _factory->allocClassOrNamespace(reference);
|
ClassOrNamespace *instantiation = _factory->allocClassOrNamespace(reference);
|
||||||
#ifdef DEBUG_LOOKUP
|
#ifdef DEBUG_LOOKUP
|
||||||
@@ -747,7 +760,6 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
|
|||||||
#endif // DEBUG_LOOKUP
|
#endif // DEBUG_LOOKUP
|
||||||
instantiation->_templateId = templId;
|
instantiation->_templateId = templId;
|
||||||
instantiation->_instantiationOrigin = origin;
|
instantiation->_instantiationOrigin = origin;
|
||||||
instantiation->_classOrNamespaces = reference->_classOrNamespaces;
|
|
||||||
|
|
||||||
// The instantiation should have all symbols, enums, and usings from the reference.
|
// The instantiation should have all symbols, enums, and usings from the reference.
|
||||||
instantiation->_enums.append(reference->unscopedEnums());
|
instantiation->_enums.append(reference->unscopedEnums());
|
||||||
@@ -780,6 +792,7 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
|
|||||||
qDebug()<<"cloned"<<oo(clone->type());
|
qDebug()<<"cloned"<<oo(clone->type());
|
||||||
#endif // DEBUG_LOOKUP
|
#endif // DEBUG_LOOKUP
|
||||||
}
|
}
|
||||||
|
instantiateNestedClasses(reference, cloner, subst, instantiation);
|
||||||
} else {
|
} else {
|
||||||
instantiation->_symbols.append(reference->symbols());
|
instantiation->_symbols.append(reference->symbols());
|
||||||
}
|
}
|
||||||
@@ -843,10 +856,12 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
|
|||||||
instantiation->addUsing(baseBinding);
|
instantiation->addUsing(baseBinding);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
instantiation->_classOrNamespaces = reference->_classOrNamespaces;
|
||||||
instantiation->_symbols.append(reference->symbols());
|
instantiation->_symbols.append(reference->symbols());
|
||||||
}
|
}
|
||||||
|
|
||||||
_alreadyConsideredTemplates.clear(templId);
|
_alreadyConsideredTemplates.clear(templId);
|
||||||
|
_instantiations[templId] = instantiation;
|
||||||
return instantiation;
|
return instantiation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -881,6 +896,104 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
|
|||||||
return reference;
|
return reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ClassOrNamespace::instantiateNestedClasses(ClassOrNamespace *enclosingTemplateClass,
|
||||||
|
Clone &cloner,
|
||||||
|
Subst &subst,
|
||||||
|
ClassOrNamespace *enclosingTemplateClassInstantiation)
|
||||||
|
{
|
||||||
|
NestedClassInstantiator nestedClassInstantiator(_factory, cloner, subst);
|
||||||
|
nestedClassInstantiator.instantiate(enclosingTemplateClass, enclosingTemplateClassInstantiation);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassOrNamespace::NestedClassInstantiator::instantiate(ClassOrNamespace *enclosingTemplateClass,
|
||||||
|
ClassOrNamespace *enclosingTemplateClassInstantiation)
|
||||||
|
{
|
||||||
|
if (_alreadyConsideredNestedClassInstantiations.contains(enclosingTemplateClass))
|
||||||
|
return;
|
||||||
|
_alreadyConsideredNestedClassInstantiations.insert(enclosingTemplateClass);
|
||||||
|
ClassOrNamespace::Table::const_iterator cit = enclosingTemplateClass->_classOrNamespaces.begin();
|
||||||
|
for (; cit != enclosingTemplateClass->_classOrNamespaces.end(); ++cit) {
|
||||||
|
const Name *nestedName = cit->first;
|
||||||
|
ClassOrNamespace *nestedClassOrNamespace = cit->second;
|
||||||
|
ClassOrNamespace *nestedClassOrNamespaceInstantiation = nestedClassOrNamespace;
|
||||||
|
|
||||||
|
if (isInstantiateNestedClassNeeded(nestedClassOrNamespace->_symbols)) {
|
||||||
|
nestedClassOrNamespaceInstantiation = _factory->allocClassOrNamespace(nestedClassOrNamespace);
|
||||||
|
nestedClassOrNamespaceInstantiation->_enums.append(nestedClassOrNamespace->unscopedEnums());
|
||||||
|
nestedClassOrNamespaceInstantiation->_usings.append(nestedClassOrNamespace->usings());
|
||||||
|
nestedClassOrNamespaceInstantiation->_instantiationOrigin = nestedClassOrNamespace;
|
||||||
|
|
||||||
|
foreach (Symbol *s, nestedClassOrNamespace->_symbols) {
|
||||||
|
Symbol *clone = _cloner.symbol(s, &_subst);
|
||||||
|
nestedClassOrNamespaceInstantiation->_symbols.append(clone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
instantiate(nestedClassOrNamespace, nestedClassOrNamespaceInstantiation);
|
||||||
|
|
||||||
|
enclosingTemplateClassInstantiation->_classOrNamespaces[nestedName] =
|
||||||
|
nestedClassOrNamespaceInstantiation;
|
||||||
|
}
|
||||||
|
_alreadyConsideredNestedClassInstantiations.remove(enclosingTemplateClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClassOrNamespace::NestedClassInstantiator::isInstantiateNestedClassNeeded(const QList<Symbol *> &symbols) const
|
||||||
|
{
|
||||||
|
foreach (Symbol *s, 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClassOrNamespace::NestedClassInstantiator::containsTemplateType(Declaration *declaration) const
|
||||||
|
{
|
||||||
|
Type *memberType = declaration->type().type();
|
||||||
|
NamedType *memberNamedType = findMemberNamedType(memberType);
|
||||||
|
if (memberNamedType) {
|
||||||
|
const Name *name = memberNamedType->name();
|
||||||
|
if (_subst.contains(name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClassOrNamespace::NestedClassInstantiator::containsTemplateType(Function * /*function*/) const
|
||||||
|
{
|
||||||
|
//TODO: make implementation
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedType *ClassOrNamespace::NestedClassInstantiator::findMemberNamedType(Type *memberType) const
|
||||||
|
{
|
||||||
|
if (NamedType *namedType = memberType->asNamedType()) {
|
||||||
|
return namedType;
|
||||||
|
}
|
||||||
|
else if (PointerType *pointerType = memberType->asPointerType()) {
|
||||||
|
return findMemberNamedType(pointerType->elementType().type());
|
||||||
|
}
|
||||||
|
else if (ReferenceType *referenceType = memberType->asReferenceType()) {
|
||||||
|
return findMemberNamedType(referenceType->elementType().type());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void ClassOrNamespace::flush()
|
void ClassOrNamespace::flush()
|
||||||
{
|
{
|
||||||
if (! _todo.isEmpty()) {
|
if (! _todo.isEmpty()) {
|
||||||
@@ -973,17 +1086,22 @@ ClassOrNamespace *CreateBindings::globalNamespace() const
|
|||||||
return _globalNamespace;
|
return _globalNamespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassOrNamespace *CreateBindings::lookupType(Symbol *symbol)
|
ClassOrNamespace *CreateBindings::lookupType(Symbol *symbol, ClassOrNamespace* enclosingTemplateInstantiation)
|
||||||
{
|
{
|
||||||
const QList<const Name *> path = LookupContext::path(symbol);
|
const QList<const Name *> path = LookupContext::path(symbol);
|
||||||
return lookupType(path);
|
return lookupType(path, enclosingTemplateInstantiation);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassOrNamespace *CreateBindings::lookupType(const QList<const Name *> &path)
|
ClassOrNamespace *CreateBindings::lookupType(const QList<const Name *> &path, ClassOrNamespace* enclosingTemplateInstantiation)
|
||||||
{
|
{
|
||||||
if (path.isEmpty())
|
if (path.isEmpty())
|
||||||
return _globalNamespace;
|
return _globalNamespace;
|
||||||
|
|
||||||
|
if (enclosingTemplateInstantiation) {
|
||||||
|
if (ClassOrNamespace *b = enclosingTemplateInstantiation->lookupType(path.last()))
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
ClassOrNamespace *b = _globalNamespace->lookupType(path.at(0));
|
ClassOrNamespace *b = _globalNamespace->lookupType(path.at(0));
|
||||||
|
|
||||||
for (int i = 1; b && i < path.size(); ++i)
|
for (int i = 1; b && i < path.size(); ++i)
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
namespace CPlusPlus {
|
namespace CPlusPlus {
|
||||||
|
|
||||||
@@ -92,8 +93,15 @@ private:
|
|||||||
|
|
||||||
ClassOrNamespace *nestedType(const Name *name, ClassOrNamespace *origin);
|
ClassOrNamespace *nestedType(const Name *name, ClassOrNamespace *origin);
|
||||||
|
|
||||||
|
void instantiateNestedClasses(ClassOrNamespace *enclosingTemplateClass,
|
||||||
|
Clone &cloner,
|
||||||
|
Subst &subst,
|
||||||
|
ClassOrNamespace *enclosingTemplateClassInstantiation);
|
||||||
|
bool isInstantiateNestedClassNeeded(const QList<Symbol *>& symbols, const Subst &subst) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::map<const Name *, ClassOrNamespace *, Name::Compare> Table;
|
typedef std::map<const Name *, ClassOrNamespace *, Name::Compare> Table;
|
||||||
|
|
||||||
CreateBindings *_factory;
|
CreateBindings *_factory;
|
||||||
ClassOrNamespace *_parent;
|
ClassOrNamespace *_parent;
|
||||||
QList<Symbol *> _symbols;
|
QList<Symbol *> _symbols;
|
||||||
@@ -102,6 +110,7 @@ private:
|
|||||||
QList<Enum *> _enums;
|
QList<Enum *> _enums;
|
||||||
QList<Symbol *> _todo;
|
QList<Symbol *> _todo;
|
||||||
QSharedPointer<Control> _control;
|
QSharedPointer<Control> _control;
|
||||||
|
QMap<const Name *, ClassOrNamespace *> _instantiations;
|
||||||
|
|
||||||
// it's an instantiation.
|
// it's an instantiation.
|
||||||
const TemplateNameId *_templateId;
|
const TemplateNameId *_templateId;
|
||||||
@@ -110,6 +119,28 @@ private:
|
|||||||
AlreadyConsideredClassContainer<Class> _alreadyConsideredClasses;
|
AlreadyConsideredClassContainer<Class> _alreadyConsideredClasses;
|
||||||
AlreadyConsideredClassContainer<TemplateNameId> _alreadyConsideredTemplates;
|
AlreadyConsideredClassContainer<TemplateNameId> _alreadyConsideredTemplates;
|
||||||
|
|
||||||
|
class NestedClassInstantiator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NestedClassInstantiator(CreateBindings *factory, Clone &cloner, Subst &subst)
|
||||||
|
: _factory(factory)
|
||||||
|
, _cloner(cloner)
|
||||||
|
, _subst(subst)
|
||||||
|
{}
|
||||||
|
void instantiate(ClassOrNamespace *enclosingTemplateClass,
|
||||||
|
ClassOrNamespace *enclosingTemplateClassInstantiation);
|
||||||
|
private:
|
||||||
|
bool isInstantiateNestedClassNeeded(const QList<Symbol *> &symbols) const;
|
||||||
|
bool containsTemplateType(Declaration *declaration) const;
|
||||||
|
bool containsTemplateType(Function *function) const;
|
||||||
|
NamedType *findMemberNamedType(Type *memberType) const;
|
||||||
|
|
||||||
|
QSet<ClassOrNamespace *> _alreadyConsideredNestedClassInstantiations;
|
||||||
|
CreateBindings *_factory;
|
||||||
|
Clone &_cloner;
|
||||||
|
Subst &_subst;
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef DEBUG_LOOKUP
|
#ifdef DEBUG_LOOKUP
|
||||||
public:
|
public:
|
||||||
const Name *_name;
|
const Name *_name;
|
||||||
@@ -130,8 +161,10 @@ public:
|
|||||||
ClassOrNamespace *globalNamespace() const;
|
ClassOrNamespace *globalNamespace() const;
|
||||||
|
|
||||||
/// Finds the binding associated to the given symbol.
|
/// Finds the binding associated to the given symbol.
|
||||||
ClassOrNamespace *lookupType(Symbol *symbol);
|
ClassOrNamespace *lookupType(Symbol *symbol,
|
||||||
ClassOrNamespace *lookupType(const QList<const Name *> &path);
|
ClassOrNamespace* enclosingTemplateInstantiation = 0);
|
||||||
|
ClassOrNamespace *lookupType(const QList<const Name *> &path,
|
||||||
|
ClassOrNamespace* enclosingTemplateInstantiation = 0);
|
||||||
|
|
||||||
/// Returns the Control that must be used to create temporary symbols.
|
/// Returns the Control that must be used to create temporary symbols.
|
||||||
/// \internal
|
/// \internal
|
||||||
@@ -228,8 +261,10 @@ public:
|
|||||||
ClassOrNamespace *globalNamespace() const;
|
ClassOrNamespace *globalNamespace() const;
|
||||||
|
|
||||||
QList<LookupItem> lookup(const Name *name, Scope *scope) const;
|
QList<LookupItem> lookup(const Name *name, Scope *scope) const;
|
||||||
ClassOrNamespace *lookupType(const Name *name, Scope *scope) const;
|
ClassOrNamespace *lookupType(const Name *name, Scope *scope,
|
||||||
ClassOrNamespace *lookupType(Symbol *symbol) const;
|
ClassOrNamespace* enclosingTemplateInstantiation = 0) const;
|
||||||
|
ClassOrNamespace *lookupType(Symbol *symbol,
|
||||||
|
ClassOrNamespace* enclosingTemplateInstantiation = 0) const;
|
||||||
ClassOrNamespace *lookupParent(Symbol *symbol) const;
|
ClassOrNamespace *lookupParent(Symbol *symbol) const;
|
||||||
|
|
||||||
/// \internal
|
/// \internal
|
||||||
|
|||||||
@@ -811,16 +811,17 @@ bool ResolveExpression::visit(MemberAccessAST *ast)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassOrNamespace *ResolveExpression::findClass(const FullySpecifiedType &originalTy, Scope *scope) const
|
ClassOrNamespace *ResolveExpression::findClass(const FullySpecifiedType &originalTy, Scope *scope,
|
||||||
|
ClassOrNamespace* enclosingTemplateInstantiation) const
|
||||||
{
|
{
|
||||||
FullySpecifiedType ty = originalTy.simplified();
|
FullySpecifiedType ty = originalTy.simplified();
|
||||||
ClassOrNamespace *binding = 0;
|
ClassOrNamespace *binding = 0;
|
||||||
|
|
||||||
if (Class *klass = ty->asClassType())
|
if (Class *klass = ty->asClassType())
|
||||||
binding = _context.lookupType(klass);
|
binding = _context.lookupType(klass, enclosingTemplateInstantiation);
|
||||||
|
|
||||||
else if (NamedType *namedTy = ty->asNamedType())
|
else if (NamedType *namedTy = ty->asNamedType())
|
||||||
binding = _context.lookupType(namedTy->name(), scope);
|
binding = _context.lookupType(namedTy->name(), scope, enclosingTemplateInstantiation);
|
||||||
|
|
||||||
else if (Function *funTy = ty->asFunctionType())
|
else if (Function *funTy = ty->asFunctionType())
|
||||||
return findClass(funTy->returnType(), scope);
|
return findClass(funTy->returnType(), scope);
|
||||||
@@ -979,7 +980,13 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList<LookupItem> &bas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ClassOrNamespace *binding = findClass(ty, scope))
|
ClassOrNamespace *enclosingTemplateInstantiation = 0;
|
||||||
|
if (ClassOrNamespace *binding = r.binding()) {
|
||||||
|
if (binding->instantiationOrigin())
|
||||||
|
enclosingTemplateInstantiation = binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ClassOrNamespace *binding = findClass(ty, scope, enclosingTemplateInstantiation))
|
||||||
return binding;
|
return binding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,8 @@ public:
|
|||||||
const LookupContext &context() const;
|
const LookupContext &context() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ClassOrNamespace *findClass(const FullySpecifiedType &ty, Scope *scope) const;
|
ClassOrNamespace *findClass(const FullySpecifiedType &ty, Scope *scope,
|
||||||
|
ClassOrNamespace* enclosingTemplateInstantiation = 0) const;
|
||||||
|
|
||||||
QList<LookupItem> expression(ExpressionAST *ast);
|
QList<LookupItem> expression(ExpressionAST *ast);
|
||||||
|
|
||||||
|
|||||||
@@ -1176,3 +1176,87 @@ void CppToolsPlugin::test_completion_enclosing_template_class_data()
|
|||||||
QTest::newRow("case: nested template class with enclosing template class")
|
QTest::newRow("case: nested template class with enclosing template class")
|
||||||
<< code << completions;
|
<< code << completions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CppToolsPlugin::test_completion_instantiate_nested_class_when_enclosing_is_template()
|
||||||
|
{
|
||||||
|
TestData data;
|
||||||
|
data.srcText = "\n"
|
||||||
|
"struct Foo \n"
|
||||||
|
"{\n"
|
||||||
|
" int foo_i;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"template <typename T>\n"
|
||||||
|
"struct Enclosing\n"
|
||||||
|
"{\n"
|
||||||
|
" struct Nested\n"
|
||||||
|
" {\n"
|
||||||
|
" T nested_t;\n"
|
||||||
|
" } nested;\n"
|
||||||
|
"\n"
|
||||||
|
" T enclosing_t;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"Enclosing<Foo> enclosing;\n"
|
||||||
|
"@\n"
|
||||||
|
;
|
||||||
|
|
||||||
|
setup(&data);
|
||||||
|
|
||||||
|
Utils::ChangeSet change;
|
||||||
|
QString txt = QLatin1String("enclosing.nested.nested_t.");
|
||||||
|
change.insert(data.pos, txt);
|
||||||
|
QTextCursor cursor(data.doc);
|
||||||
|
change.apply(&cursor);
|
||||||
|
data.pos += txt.length();
|
||||||
|
|
||||||
|
QStringList completions = getCompletions(data);
|
||||||
|
|
||||||
|
QCOMPARE(completions.size(), 2);
|
||||||
|
QVERIFY(completions.contains(QLatin1String("Foo")));
|
||||||
|
QVERIFY(completions.contains(QLatin1String("foo_i")));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CppToolsPlugin::test_completion_instantiate_nested_of_nested_class_when_enclosing_is_template()
|
||||||
|
{
|
||||||
|
TestData data;
|
||||||
|
data.srcText = "\n"
|
||||||
|
"struct Foo \n"
|
||||||
|
"{\n"
|
||||||
|
" int foo_i;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"template <typename T>\n"
|
||||||
|
"struct Enclosing\n"
|
||||||
|
"{\n"
|
||||||
|
" struct Nested\n"
|
||||||
|
" {\n"
|
||||||
|
" T nested_t;\n"
|
||||||
|
" struct NestedNested\n"
|
||||||
|
" {\n"
|
||||||
|
" T nestedNested_t;\n"
|
||||||
|
" } nestedNested;\n"
|
||||||
|
" } nested;\n"
|
||||||
|
"\n"
|
||||||
|
" T enclosing_t;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"Enclosing<Foo> enclosing;\n"
|
||||||
|
"@\n"
|
||||||
|
;
|
||||||
|
|
||||||
|
setup(&data);
|
||||||
|
|
||||||
|
Utils::ChangeSet change;
|
||||||
|
QString txt = QLatin1String("enclosing.nested.nestedNested.nestedNested_t.");
|
||||||
|
change.insert(data.pos, txt);
|
||||||
|
QTextCursor cursor(data.doc);
|
||||||
|
change.apply(&cursor);
|
||||||
|
data.pos += txt.length();
|
||||||
|
|
||||||
|
QStringList completions = getCompletions(data);
|
||||||
|
|
||||||
|
QCOMPARE(completions.size(), 2);
|
||||||
|
QVERIFY(completions.contains(QLatin1String("Foo")));
|
||||||
|
QVERIFY(completions.contains(QLatin1String("foo_i")));
|
||||||
|
}
|
||||||
|
|||||||
@@ -110,6 +110,8 @@ private slots:
|
|||||||
void test_completion_cyclic_inheritance_data();
|
void test_completion_cyclic_inheritance_data();
|
||||||
void test_completion_enclosing_template_class();
|
void test_completion_enclosing_template_class();
|
||||||
void test_completion_enclosing_template_class_data();
|
void test_completion_enclosing_template_class_data();
|
||||||
|
void test_completion_instantiate_nested_class_when_enclosing_is_template();
|
||||||
|
void test_completion_instantiate_nested_of_nested_class_when_enclosing_is_template();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void test_completion();
|
void test_completion();
|
||||||
|
|||||||
Reference in New Issue
Block a user