diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 452aa88aa41..23c9b201b86 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -848,7 +848,7 @@ public: } private: - NamedType *getNamedType(FullySpecifiedType& type) + NamedType *getNamedType(FullySpecifiedType& type) const { NamedType *namedTy = type->asNamedType(); if (! namedTy) { @@ -858,19 +858,57 @@ private: return namedTy; } - QList getNamedTypeItems(const Name *name, Scope *scope, ClassOrNamespace *binding) + QList getNamedTypeItems(const Name *name, Scope *scope, + ClassOrNamespace *binding) const { - QList namedTypeItems; - if (binding) - namedTypeItems = binding->lookup(name); - if (ClassOrNamespace *scopeCon = _context.lookupType(scope)) - namedTypeItems += scopeCon->lookup(name); + QList namedTypeItems = typedefsFromScopeUpToFunctionScope(name, scope); + if (namedTypeItems.isEmpty()) { + if (binding) + namedTypeItems = binding->lookup(name); + if (ClassOrNamespace *scopeCon = _context.lookupType(scope)) + namedTypeItems += scopeCon->lookup(name); + } return namedTypeItems; } + /// Return all typedefs with given name from given scope up to function scope. + static QList typedefsFromScopeUpToFunctionScope(const Name *name, Scope *scope) + { + QList results; + Scope *enclosingBlockScope = 0; + for (Block *block = scope->asBlock(); block; + block = enclosingBlockScope ? enclosingBlockScope->asBlock() : 0) { + const unsigned memberCount = block->memberCount(); + for (unsigned i = 0; i < memberCount; ++i) { + Symbol *symbol = block->memberAt(i); + if (Declaration *declaration = symbol->asDeclaration()) { + if (isTypedefWithName(declaration, name)) { + LookupItem item; + item.setDeclaration(declaration); + item.setScope(block); + item.setType(declaration->type()); + results.append(item); + } + } + } + enclosingBlockScope = block->enclosingScope(); + } + return results; + } + + static bool isTypedefWithName(const Declaration *declaration, const Name *name) + { + if (declaration->isTypedef()) { + const Identifier *identifier = declaration->name()->identifier(); + if (name->identifier()->isEqualTo(identifier)) + return true; + } + return false; + } + bool findTypedef(const QList& namedTypeItems, FullySpecifiedType *type, - Scope **scope, QSet& visited) + Scope **scope, QSet& visited) const { bool foundTypedef = false; foreach (const LookupItem &it, namedTypeItems) { @@ -931,6 +969,11 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList &bas if (ClassOrNamespace *binding = findClass(type, scope)) return binding; + } else if (PointerType *ptrTy = ty->asPointerType()) { + FullySpecifiedType type = ptrTy->elementType(); + if (ClassOrNamespace *binding = findClass(type, scope)) + return binding; + } else if (ClassOrNamespace *binding = findClass(ty, scope)) { // lookup for overloads of operator-> diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index 20b02c435c5..19267fa6e8e 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -1483,3 +1483,90 @@ void CppToolsPlugin::test_completion_typedef_of_pointer_of_type_and_replace_acce QVERIFY(completions.contains(QLatin1String("m"))); QVERIFY(replaceAccessOperator); } + +void CppToolsPlugin::test_completion_typedef_of_pointer() +{ + TestData data; + data.srcText = "\n" + "struct Foo { int bar; };\n" + "typedef Foo *FooPtr;\n" + "void main()\n" + "{\n" + " FooPtr ptr;\n" + " @\n" + " // padding so we get the scope right\n" + "}"; + setup(&data); + + Utils::ChangeSet change; + QString txt = QLatin1String("ptr->"); + 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("bar"))); +} + +void CppToolsPlugin::test_completion_typedef_of_pointer_inside_function() +{ + TestData data; + data.srcText = "\n" + "struct Foo { int bar; };\n" + "void f()\n" + "{\n" + " typedef Foo *FooPtr;\n" + " FooPtr ptr;\n" + " @\n" + " // padding so we get the scope right\n" + "}"; + setup(&data); + + Utils::ChangeSet change; + QString txt = QLatin1String("ptr->"); + 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("bar"))); +} + +void CppToolsPlugin::test_completion_typedef_is_inside_function_before_declaration_block() +{ + TestData data; + data.srcText = "\n" + "struct Foo { int bar; };\n" + "void f()\n" + "{\n" + " typedef Foo *FooPtr;\n" + " if (true) {\n" + " FooPtr ptr;\n" + " @\n" + " // padding so we get the scope right\n" + " }" + "}" + ; + setup(&data); + + Utils::ChangeSet change; + QString txt = QLatin1String("ptr->"); + 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("bar"))); +} diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h index 1477e4ae23b..a26ae0ef271 100644 --- a/src/plugins/cpptools/cpptoolsplugin.h +++ b/src/plugins/cpptools/cpptoolsplugin.h @@ -118,6 +118,9 @@ private slots: void test_completion_member_access_operator_1(); void test_completion_typedef_of_type_and_replace_access_operator(); void test_completion_typedef_of_pointer_of_type_and_replace_access_operator(); + void test_completion_typedef_of_pointer(); + void test_completion_typedef_of_pointer_inside_function(); + void test_completion_typedef_is_inside_function_before_declaration_block(); void test_format_pointerdeclaration_in_simpledeclarations(); void test_format_pointerdeclaration_in_simpledeclarations_data();