diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 1fbe5c5e601..c2c7b5c5993 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -263,11 +263,23 @@ ClassOrNamespace *LookupContext::lookupType(const Name *name, Scope *scope) cons return 0; } else if (Block *block = scope->asBlock()) { for (unsigned i = 0; i < block->memberCount(); ++i) { - if (UsingNamespaceDirective *u = block->memberAt(i)->asUsingNamespaceDirective()) { + Symbol *m = block->memberAt(i); + if (UsingNamespaceDirective *u = m->asUsingNamespaceDirective()) { if (ClassOrNamespace *uu = lookupType(u->name(), scope->enclosingNamespace())) { if (ClassOrNamespace *r = uu->lookupType(name)) return r; } + } else if (Declaration *d = m->asDeclaration()) { + if (d->name() && d->name()->isEqualTo(name->asNameId())) { + if (d->isTypedef() && d->type()) { +#ifdef DEBUG_LOOKUP + Overview oo; + qDebug() << "Looks like" << oo(name) << "is a typedef for" << oo(d->type()); +#endif // DEBUG_LOOKUP + if (const NamedType *namedTy = d->type()->asNamedType()) + return lookupType(namedTy->name(), scope); + } + } } } return lookupType(name, scope->enclosingScope()); @@ -380,6 +392,9 @@ ClassOrNamespace *LookupContext::lookupParent(Symbol *symbol) const ClassOrNamespace::ClassOrNamespace(CreateBindings *factory, ClassOrNamespace *parent) : _factory(factory), _parent(parent), _templateId(0), _instantiationOrigin(0) +#ifdef DEBUG_LOOKUP + , _name(0) +#endif // DEBUG_LOOKUP { } @@ -574,6 +589,11 @@ void CreateBindings::lookupInScope(const Name *name, Scope *scope, else if (s->name()->isQualifiedNameId()) continue; // skip qualified ids. +#ifdef DEBUG_LOOKUP + Overview oo; + qDebug() << "Found" << id->chars() << "in" << (binding ? oo(binding->_name) : ""); +#endif // DEBUG_LOOKUP + LookupItem item; item.setDeclaration(s); item.setBinding(binding); @@ -616,6 +636,11 @@ ClassOrNamespace *ClassOrNamespace::lookupType_helper(const Name *name, bool searchInEnclosingScope, ClassOrNamespace *origin) { +#ifdef DEBUG_LOOKUP + Overview oo; + qDebug() << "Looking up" << oo(name) << "in" << oo(_name); +#endif // DEBUG_LOOKUP + if (const QualifiedNameId *q = name->asQualifiedNameId()) { QSet innerProcessed; @@ -721,6 +746,9 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac if (templId) { _alreadyConsideredTemplates.insert(templId); ClassOrNamespace *instantiation = _factory->allocClassOrNamespace(reference); +#ifdef DEBUG_LOOKUP + instantiation->_name = templId; +#endif // DEBUG_LOOKUP instantiation->_templateId = templId; instantiation->_instantiationOrigin = origin; @@ -734,6 +762,7 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac const unsigned argumentCount = templId->templateArgumentCount(); if (_factory->expandTemplates()) { + Clone cloner(_control.data()); Subst subst(_control.data()); for (unsigned i = 0, ei = std::min(argumentCount, templ->templateParameterCount()); i < ei; ++i) { const TypenameArgument *tParam = templ->templateParameterAt(i)->asTypenameArgument(); @@ -743,12 +772,16 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac if (!name) continue; const FullySpecifiedType &ty = templId->templateArgumentAt(i); - subst.bind(name, ty); + subst.bind(cloner.name(name, &subst), ty); } - Clone cloner(_control.data()); foreach (Symbol *s, reference->symbols()) { - instantiation->_symbols.append(cloner.symbol(s, &subst)); + Symbol *clone = cloner.symbol(s, &subst); + instantiation->_symbols.append(clone); +#ifdef DEBUG_LOOKUP + Overview oo;oo.setShowFunctionSignatures(true);oo.setShowReturnTypes(true);oo.setShowTemplateParameters(true); + qDebug()<<"cloned"<type()); +#endif // DEBUG_LOOKUP } } else { instantiation->_symbols.append(reference->symbols()); @@ -917,6 +950,9 @@ ClassOrNamespace *ClassOrNamespace::findOrCreateType(const Name *name, ClassOrNa if (! e) { e = _factory->allocClassOrNamespace(this); +#ifdef DEBUG_LOOKUP + e->_name = name; +#endif // DEBUG_LOOKUP _classOrNamespaces[name] = e; } diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h index c7b556de432..9b85f3c11ef 100644 --- a/src/libs/cplusplus/LookupContext.h +++ b/src/libs/cplusplus/LookupContext.h @@ -136,6 +136,10 @@ private: AlreadyConsideredClassContainer _alreadyConsideredClasses; AlreadyConsideredClassContainer _alreadyConsideredTemplates; +#ifdef DEBUG_LOOKUP + const Name *_name; +#endif // DEBUG_LOOKUP + friend class CreateBindings; }; diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 3ffed52d5c0..dfa634d799b 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -830,16 +830,22 @@ ClassOrNamespace *ResolveExpression::findClass(const FullySpecifiedType &origina static void resolveTypedefs(const LookupContext &context, FullySpecifiedType *type, - Scope **scope) + Scope **scope, ClassOrNamespace *binding) { QSet visited; while (NamedType *namedTy = (*type)->asNamedType()) { - ClassOrNamespace *scopeCoN = context.lookupType(*scope); - if (!scopeCoN) - break; // check if namedTy->name() resolves to a typedef - QList namedTypeItems = scopeCoN->lookup(namedTy->name()); + QList namedTypeItems; + if (binding) + namedTypeItems = binding->lookup(namedTy->name()); + if (ClassOrNamespace *scopeCon = context.lookupType(*scope)) + namedTypeItems += scopeCon->lookup(namedTy->name()); + +#ifdef DEBUG_LOOKUP + qDebug() << "-- we have" << namedTypeItems.size() << "candidates"; +#endif // DEBUG_LOOKUP + bool foundTypedef = false; foreach (const LookupItem &it, namedTypeItems) { if (it.declaration() && it.declaration()->isTypedef()) { @@ -864,11 +870,26 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList &bas int accessOp, bool *replacedDotOperator) const { +#ifdef DEBUG_LOOKUP + qDebug() << "In ResolveExpression::baseExpression with" << baseResults.size() << "results..."; + int i = 0; + Overview oo; +#endif // DEBUG_LOOKUP + foreach (const LookupItem &r, baseResults) { FullySpecifiedType ty = r.type().simplified(); Scope *scope = r.scope(); - resolveTypedefs(_context, &ty, &scope); +#ifdef DEBUG_LOOKUP + qDebug("trying result #%d", ++i); + qDebug()<<"- before typedef resolving we have:"<asPointerType()) { @@ -892,7 +913,7 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList &bas FullySpecifiedType retTy = instantiatedFunction->returnType().simplified(); - resolveTypedefs(_context, &retTy, &functionScope); + resolveTypedefs(_context, &retTy, &functionScope, r.binding()); if (PointerType *ptrTy = retTy->asPointerType()) { if (ClassOrNamespace *retBinding = findClass(ptrTy->elementType(), functionScope)) diff --git a/src/libs/cplusplus/cplusplus.pro b/src/libs/cplusplus/cplusplus.pro index 82ee8bfded0..4c272c5a6f2 100644 --- a/src/libs/cplusplus/cplusplus.pro +++ b/src/libs/cplusplus/cplusplus.pro @@ -2,6 +2,7 @@ TEMPLATE = lib TARGET = CPlusPlus DEFINES += NDEBUG +#DEFINES += DEBUG_LOOKUP unix:QMAKE_CXXFLAGS_DEBUG += -O2 include(../../qtcreatorlibrary.pri) diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index 72438d114bb..68229c63711 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -296,6 +296,76 @@ void CppToolsPlugin::test_completion_template_3() QVERIFY(completions.contains("Tupple")); QVERIFY(completions.contains("a")); QVERIFY(completions.contains("b")); +} + +void CppToolsPlugin::test_completion_template_4() +{ + TestData data; + data.srcText = "\n" + "template \n" + "struct List\n" + "{\n" + " typedef T U;\n" + " U u;\n" + "};\n" + "\n" + "struct Tupple { int a; int b; };\n" + "\n" + "void func() {\n" + " List l;\n" + " @\n" + " // padding so we get the scope right\n" + "}"; + + setup(&data); + + Utils::ChangeSet change; + QString txt = QLatin1String("l.u."); + change.insert(data.pos, txt); + QTextCursor cursor(data.doc); + change.apply(&cursor); + data.pos += txt.length(); + + QStringList completions = getCompletions(data); + + QCOMPARE(completions.size(), 3); + QVERIFY(completions.contains("Tupple")); + QVERIFY(completions.contains("a")); + QVERIFY(completions.contains("b")); +} + +void CppToolsPlugin::test_completion_template_5() +{ + TestData data; + data.srcText = "\n" + "template \n" + "struct List\n" + "{\n" + " T u;\n" + "};\n" + "\n" + "struct Tupple { int a; int b; };\n" + "\n" + "void func() {\n" + " typedef List LT;\n" + " LT l;" + " @\n" + " // padding so we get the scope right\n" + "}"; + + setup(&data); + + Utils::ChangeSet change; + QString txt = QLatin1String("l.u."); + change.insert(data.pos, txt); + QTextCursor cursor(data.doc); + change.apply(&cursor); + data.pos += txt.length(); + + QStringList completions = getCompletions(data); + + QCOMPARE(completions.size(), 3); + QVERIFY(completions.contains("Tupple")); QVERIFY(completions.contains("a")); QVERIFY(completions.contains("b")); } diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h index 6bc1ddef44a..4bfafddb318 100644 --- a/src/plugins/cpptools/cpptoolsplugin.h +++ b/src/plugins/cpptools/cpptoolsplugin.h @@ -74,7 +74,6 @@ public: private slots: void switchHeaderSource(); - #ifdef WITH_TESTS // codegen tests @@ -95,6 +94,8 @@ private slots: void test_completion_template_1(); void test_completion_template_2(); void test_completion_template_3(); + void test_completion_template_4(); + void test_completion_template_5(); void test_completion_template_as_base(); void test_completion_template_as_base_data(); void test_completion_use_global_identifier_as_base_class();