diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 48d734763be..eaa53f738f5 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -828,43 +828,71 @@ ClassOrNamespace *ResolveExpression::findClass(const FullySpecifiedType &origina return binding; } -static void resolveTypedefs(const LookupContext &context, - FullySpecifiedType *type, - Scope **scope, ClassOrNamespace *binding) +class TypedefsResolver { - QSet visited; - while (NamedType *namedTy = (*type)->asNamedType()) { - - // check if namedTy->name() resolves to a typedef - QList namedTypeItems; - if (binding) - namedTypeItems = binding->lookup(namedTy->name()); - if (ClassOrNamespace *scopeCon = context.lookupType(*scope)) - namedTypeItems += scopeCon->lookup(namedTy->name()); +public: + TypedefsResolver(const LookupContext &context) : _context(context) {} + void resolve(FullySpecifiedType *type, Scope **scope, ClassOrNamespace *binding) + { + QSet visited; + while (NamedType *namedTy = getNamedType(*type)) { + QList namedTypeItems = getNamedTypeItems(namedTy->name(), *scope, binding); #ifdef DEBUG_LOOKUP - qDebug() << "-- we have" << namedTypeItems.size() << "candidates"; + qDebug() << "-- we have" << namedTypeItems.size() << "candidates"; #endif // DEBUG_LOOKUP + if (!findTypedef(namedTypeItems, type, scope, visited)) + break; + } + } + +private: + NamedType *getNamedType(FullySpecifiedType& type) + { + NamedType *namedTy = type->asNamedType(); + if (! namedTy) { + if (PointerType *pointerTy = type->asPointerType()) + namedTy = pointerTy->elementType()->asNamedType(); + } + return namedTy; + } + + QList getNamedTypeItems(const Name *name, Scope *scope, ClassOrNamespace *binding) + { + QList namedTypeItems; + if (binding) + namedTypeItems = binding->lookup(name); + if (ClassOrNamespace *scopeCon = _context.lookupType(scope)) + namedTypeItems += scopeCon->lookup(name); + + return namedTypeItems; + } + + bool findTypedef(const QList& namedTypeItems, FullySpecifiedType *type, + Scope **scope, QSet& visited) + { bool foundTypedef = false; foreach (const LookupItem &it, namedTypeItems) { - if (it.declaration() && it.declaration()->isTypedef()) { - if (visited.contains(it.declaration())) + Symbol *declaration = it.declaration(); + if (declaration && declaration->isTypedef()) { + if (visited.contains(declaration)) break; - visited.insert(it.declaration()); + visited.insert(declaration); // continue working with the typedefed type and scope - *type = it.declaration()->type(); + *type = declaration->type(); *scope = it.scope(); foundTypedef = true; break; } } - if (!foundTypedef) - break; + return foundTypedef; } -} + + const LookupContext &_context; +}; ClassOrNamespace *ResolveExpression::baseExpression(const QList &baseResults, int accessOp, @@ -875,6 +903,7 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList &bas int i = 0; Overview oo; #endif // DEBUG_LOOKUP + TypedefsResolver typedefsResolver(_context); foreach (const LookupItem &r, baseResults) { FullySpecifiedType ty = r.type().simplified(); @@ -885,7 +914,7 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList &bas qDebug()<<"- before typedef resolving we have:"< &bas FullySpecifiedType retTy = instantiatedFunction->returnType().simplified(); - resolveTypedefs(_context, &retTy, &functionScope, r.binding()); + typedefsResolver.resolve(&retTy, &functionScope, r.binding()); - if (PointerType *ptrTy = retTy->asPointerType()) { - if (ClassOrNamespace *retBinding = findClass(ptrTy->elementType(), functionScope)) + if (! retTy->isPointerType() && ! retTy->isNamedType()) + continue; + + if (PointerType *ptrTy = retTy->asPointerType()) + retTy = ptrTy->elementType(); + + if (ClassOrNamespace *retBinding = findClass(retTy, functionScope)) + return retBinding; + + if (scope != functionScope) { + if (ClassOrNamespace *retBinding = findClass(retTy, scope)) return retBinding; + } - if (scope != functionScope) { - if (ClassOrNamespace *retBinding = findClass(ptrTy->elementType(), scope)) - return retBinding; - } - - if (ClassOrNamespace *origin = binding->instantiationOrigin()) { - foreach (Symbol *originSymbol, origin->symbols()) { - Scope *originScope = originSymbol->asScope(); - if (originScope && originScope != scope && originScope != functionScope) { - if (ClassOrNamespace *retBinding = findClass(ptrTy->elementType(), originScope)) - return retBinding; - } + if (ClassOrNamespace *origin = binding->instantiationOrigin()) { + foreach (Symbol *originSymbol, origin->symbols()) { + Scope *originScope = originSymbol->asScope(); + if (originScope && originScope != scope && originScope != functionScope) { + if (ClassOrNamespace *retBinding = findClass(retTy, originScope)) + return retBinding; } } } } } - } } else if (accessOp == T_DOT) { if (replacedDotOperator) { diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index 5823ad702e7..4df7400978c 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -409,6 +409,49 @@ void CppToolsPlugin::test_completion_template_6() QVERIFY(completions.contains(QLatin1String("i"))); } + +void CppToolsPlugin::test_completion_template_7() +{ + TestData data; + data.srcText = "\n" + "struct Test\n" + "{\n" + " int i;\n" + "};\n" + "\n" + "template\n" + "struct TemplateClass\n" + "{\n" + " T* ptr;\n" + "\n" + " typedef T element_type;\n" + " TemplateClass(T* t) : ptr(t) {}\n" + " element_type* operator->()\n" + " {\n" + " return ptr;\n" + " }\n" + "};\n" + "\n" + "TemplateClass p(new Test);\n" + "@\n" + ; + + setup(&data); + + Utils::ChangeSet change; + QString txt = QLatin1String("p->"); + 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("Test"))); + QVERIFY(completions.contains(QLatin1String("i"))); +} + void CppToolsPlugin::test_completion() { QFETCH(QByteArray, code); diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h index 1c026685fed..c338a24dfeb 100644 --- a/src/plugins/cpptools/cpptoolsplugin.h +++ b/src/plugins/cpptools/cpptoolsplugin.h @@ -97,6 +97,7 @@ private slots: void test_completion_template_4(); void test_completion_template_5(); void test_completion_template_6(); + void test_completion_template_7(); void test_completion_template_as_base(); void test_completion_template_as_base_data(); void test_completion_use_global_identifier_as_base_class();