summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libs/3rdparty/cplusplus/Symbol.cpp2
-rw-r--r--src/libs/3rdparty/cplusplus/Templates.h2
-rw-r--r--src/libs/cplusplus/LookupContext.cpp142
-rw-r--r--src/libs/cplusplus/LookupContext.h43
-rw-r--r--src/libs/cplusplus/ResolveExpression.cpp15
-rw-r--r--src/libs/cplusplus/ResolveExpression.h3
-rw-r--r--src/plugins/cpptools/cppcompletion_test.cpp84
-rw-r--r--src/plugins/cpptools/cpptoolsplugin.h2
8 files changed, 271 insertions, 22 deletions
diff --git a/src/libs/3rdparty/cplusplus/Symbol.cpp b/src/libs/3rdparty/cplusplus/Symbol.cpp
index b6216f002c..cd8ec1ffdd 100644
--- a/src/libs/3rdparty/cplusplus/Symbol.cpp
+++ b/src/libs/3rdparty/cplusplus/Symbol.cpp
@@ -105,7 +105,7 @@ Symbol::Symbol(TranslationUnit *translationUnit, unsigned sourceLocation, const
Symbol::Symbol(Clone *clone, Subst *subst, Symbol *original)
: _name(clone->name(original->_name, subst)),
- _scope(0),
+ _scope(original->_scope),
_next(0),
_fileId(clone->control()->stringLiteral(original->fileName(), original->fileNameLength())),
_sourceLocation(original->_sourceLocation),
diff --git a/src/libs/3rdparty/cplusplus/Templates.h b/src/libs/3rdparty/cplusplus/Templates.h
index 04064a8906..2784f02d7f 100644
--- a/src/libs/3rdparty/cplusplus/Templates.h
+++ b/src/libs/3rdparty/cplusplus/Templates.h
@@ -54,6 +54,8 @@ public:
FullySpecifiedType &operator[](const Name *name) { return _map[name]; }
+ bool contains(const Name *name) const { return _map.find(name) != _map.end(); }
+
private:
Control *_control;
Subst *_previous;
diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp
index 446aa4ed7e..482c1c1a76 100644
--- a/src/libs/cplusplus/LookupContext.cpp
+++ b/src/libs/cplusplus/LookupContext.cpp
@@ -260,7 +260,8 @@ ClassOrNamespace *LookupContext::globalNamespace() const
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) {
return 0;
@@ -286,16 +287,17 @@ ClassOrNamespace *LookupContext::lookupType(const Name *name, Scope *scope) cons
}
}
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 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
@@ -587,7 +589,8 @@ void CreateBindings::lookupInScope(const Name *name, Scope *scope,
#ifdef DEBUG_LOOKUP
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
LookupItem item;
@@ -670,16 +673,23 @@ ClassOrNamespace *ClassOrNamespace::lookupType_helper(const Name *name,
if (_usings.size() == 1) {
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;
} else {
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()) {
- if (ClassOrNamespace *r = u->lookupType_helper(name, processed, /*searchInEnclosingScope =*/ false, origin))
+ if (ClassOrNamespace *r = u->lookupType_helper(name,
+ processed,
+ /*searchInEnclosingScope =*/ false,
+ origin))
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
// construct all instantiation data.
if (templId) {
+ if (_instantiations.contains(templId))
+ return _instantiations[templId];
+
_alreadyConsideredTemplates.insert(templId);
ClassOrNamespace *instantiation = _factory->allocClassOrNamespace(reference);
#ifdef DEBUG_LOOKUP
@@ -747,7 +760,6 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
#endif // DEBUG_LOOKUP
instantiation->_templateId = templId;
instantiation->_instantiationOrigin = origin;
- instantiation->_classOrNamespaces = reference->_classOrNamespaces;
// The instantiation should have all symbols, enums, and usings from the reference.
instantiation->_enums.append(reference->unscopedEnums());
@@ -780,6 +792,7 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
qDebug()<<"cloned"<<oo(clone->type());
#endif // DEBUG_LOOKUP
}
+ instantiateNestedClasses(reference, cloner, subst, instantiation);
} else {
instantiation->_symbols.append(reference->symbols());
}
@@ -843,10 +856,12 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
instantiation->addUsing(baseBinding);
}
} else {
+ instantiation->_classOrNamespaces = reference->_classOrNamespaces;
instantiation->_symbols.append(reference->symbols());
}
_alreadyConsideredTemplates.clear(templId);
+ _instantiations[templId] = instantiation;
return instantiation;
}
@@ -881,6 +896,104 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
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()
{
if (! _todo.isEmpty()) {
@@ -973,17 +1086,22 @@ ClassOrNamespace *CreateBindings::globalNamespace() const
return _globalNamespace;
}
-ClassOrNamespace *CreateBindings::lookupType(Symbol *symbol)
+ClassOrNamespace *CreateBindings::lookupType(Symbol *symbol, ClassOrNamespace* enclosingTemplateInstantiation)
{
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())
return _globalNamespace;
+ if (enclosingTemplateInstantiation) {
+ if (ClassOrNamespace *b = enclosingTemplateInstantiation->lookupType(path.last()))
+ return b;
+ }
+
ClassOrNamespace *b = _globalNamespace->lookupType(path.at(0));
for (int i = 1; b && i < path.size(); ++i)
diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h
index b7c84d4e25..19fec679ea 100644
--- a/src/libs/cplusplus/LookupContext.h
+++ b/src/libs/cplusplus/LookupContext.h
@@ -41,6 +41,7 @@
#include <QSet>
#include <map>
#include <functional>
+#include <QMap>
namespace CPlusPlus {
@@ -92,8 +93,15 @@ private:
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:
typedef std::map<const Name *, ClassOrNamespace *, Name::Compare> Table;
+
CreateBindings *_factory;
ClassOrNamespace *_parent;
QList<Symbol *> _symbols;
@@ -102,6 +110,7 @@ private:
QList<Enum *> _enums;
QList<Symbol *> _todo;
QSharedPointer<Control> _control;
+ QMap<const Name *, ClassOrNamespace *> _instantiations;
// it's an instantiation.
const TemplateNameId *_templateId;
@@ -110,6 +119,28 @@ private:
AlreadyConsideredClassContainer<Class> _alreadyConsideredClasses;
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
public:
const Name *_name;
@@ -130,8 +161,10 @@ public:
ClassOrNamespace *globalNamespace() const;
/// Finds the binding associated to the given symbol.
- ClassOrNamespace *lookupType(Symbol *symbol);
- ClassOrNamespace *lookupType(const QList<const Name *> &path);
+ ClassOrNamespace *lookupType(Symbol *symbol,
+ ClassOrNamespace* enclosingTemplateInstantiation = 0);
+ ClassOrNamespace *lookupType(const QList<const Name *> &path,
+ ClassOrNamespace* enclosingTemplateInstantiation = 0);
/// Returns the Control that must be used to create temporary symbols.
/// \internal
@@ -228,8 +261,10 @@ public:
ClassOrNamespace *globalNamespace() const;
QList<LookupItem> lookup(const Name *name, Scope *scope) const;
- ClassOrNamespace *lookupType(const Name *name, Scope *scope) const;
- ClassOrNamespace *lookupType(Symbol *symbol) const;
+ ClassOrNamespace *lookupType(const Name *name, Scope *scope,
+ ClassOrNamespace* enclosingTemplateInstantiation = 0) const;
+ ClassOrNamespace *lookupType(Symbol *symbol,
+ ClassOrNamespace* enclosingTemplateInstantiation = 0) const;
ClassOrNamespace *lookupParent(Symbol *symbol) const;
/// \internal
diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp
index eaa53f738f..a6c3c10141 100644
--- a/src/libs/cplusplus/ResolveExpression.cpp
+++ b/src/libs/cplusplus/ResolveExpression.cpp
@@ -811,16 +811,17 @@ bool ResolveExpression::visit(MemberAccessAST *ast)
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();
ClassOrNamespace *binding = 0;
if (Class *klass = ty->asClassType())
- binding = _context.lookupType(klass);
+ binding = _context.lookupType(klass, enclosingTemplateInstantiation);
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())
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;
}
}
diff --git a/src/libs/cplusplus/ResolveExpression.h b/src/libs/cplusplus/ResolveExpression.h
index 895a63727e..8a3fbeb072 100644
--- a/src/libs/cplusplus/ResolveExpression.h
+++ b/src/libs/cplusplus/ResolveExpression.h
@@ -56,7 +56,8 @@ public:
const LookupContext &context() const;
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);
diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp
index 9eb28dca97..3d2abd7095 100644
--- a/src/plugins/cpptools/cppcompletion_test.cpp
+++ b/src/plugins/cpptools/cppcompletion_test.cpp
@@ -1176,3 +1176,87 @@ void CppToolsPlugin::test_completion_enclosing_template_class_data()
QTest::newRow("case: nested template class with enclosing template class")
<< 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")));
+}
diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h
index b56ee4aa0d..29f119db76 100644
--- a/src/plugins/cpptools/cpptoolsplugin.h
+++ b/src/plugins/cpptools/cpptoolsplugin.h
@@ -110,6 +110,8 @@ private slots:
void test_completion_cyclic_inheritance_data();
void test_completion_enclosing_template_class();
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:
void test_completion();