diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -1177,7 +1177,7 @@ Declaration* attributeDeclaration = nullptr; { DUChainReadLocker lock; - attributeDeclaration = Helper::accessAttribute(parentObjectDeclaration.data(), + attributeDeclaration = Helper::accessAttribute(parentObjectDeclaration->abstractType(), attrib->attribute->value, currentContext()); } diff --git a/duchain/expressionvisitor.cpp b/duchain/expressionvisitor.cpp --- a/duchain/expressionvisitor.cpp +++ b/duchain/expressionvisitor.cpp @@ -115,8 +115,7 @@ if ( Helper::isUsefulType(current.cast()) ) { haveOneUsefulType = true; } - foundDeclaration = Helper::accessAttribute(current->declaration(context()->topContext()), - node->attribute->value, context()); + foundDeclaration = Helper::accessAttribute(current, node->attribute->value, context()); if ( foundDeclaration ) { break; } @@ -422,10 +421,8 @@ } // Otherwise, try to use __getitem__. - ExpressionVisitor v(context()); - v.visitNode(node->value); DUChainReadLocker lock; - Declaration* function = Helper::accessAttribute(v.lastDeclaration().data(), "__getitem__", context()); + Declaration* function = Helper::accessAttribute(lastType(), "__getitem__", context()); if ( function && function->isFunctionDeclaration() ) { if ( FunctionType::Ptr functionType = function->type() ) { return encounter(functionType->returnType()); @@ -682,7 +679,7 @@ if ( ! type ) { return AbstractType::Ptr(); } - Declaration* func = Helper::accessAttribute(type->declaration(context()->topContext()), op, context()); + Declaration* func = Helper::accessAttribute(type, op, context()); if ( ! func ) { return AbstractType::Ptr(); } diff --git a/duchain/helpers.h b/duchain/helpers.h --- a/duchain/helpers.h +++ b/duchain/helpers.h @@ -73,7 +73,7 @@ static AbstractType::Ptr extractTypeHints(AbstractType::Ptr type); - static Declaration* accessAttribute(Declaration* accessed, const QString& attribute, const DUContext* current); + static Declaration* accessAttribute(const AbstractType::Ptr accessed, const QString& attribute, const DUContext* current); static AbstractType::Ptr resolveAliasType(const AbstractType::Ptr eventualAlias); diff --git a/duchain/helpers.cpp b/duchain/helpers.cpp --- a/duchain/helpers.cpp +++ b/duchain/helpers.cpp @@ -109,13 +109,13 @@ return KDevelop::IndexedDeclaration(); } -Declaration* Helper::accessAttribute(Declaration* accessed, const QString& attribute, const DUContext* current) +Declaration* Helper::accessAttribute(const AbstractType::Ptr accessed, const QString& attribute, const DUContext* current) { - if ( ! accessed || ! accessed->abstractType() ) { + if ( ! accessed ) { return 0; } // if the type is unsure, search all the possibilities - auto structureTypes = Helper::filterType(accessed->abstractType(), + auto structureTypes = Helper::filterType(accessed, [](AbstractType::Ptr toFilter) { auto type = Helper::resolveAliasType(toFilter); return type && type->whichType() == AbstractType::TypeStructure; diff --git a/duchain/tests/pyduchaintest.cpp b/duchain/tests/pyduchaintest.cpp --- a/duchain/tests/pyduchaintest.cpp +++ b/duchain/tests/pyduchaintest.cpp @@ -1384,6 +1384,15 @@ QTest::newRow("comprehension_messy") << "users = {'a':19, 'b':42, 'c':35}\n" "sorted_list = sorted(users.items(), key=lambda kv: (-kv[1], kv[0]))\n" "checkme = [k for r,(k,v) in enumerate(sorted_list, 1)]" << "list of str" << true; + // From https://bugs.kde.org/show_bug.cgi?id=359912 + QTest::newRow("subscript_multi") << + "class Middle:\n def __getitem__(self, key):\n return str()\n" + "class Outer:\n def __getitem__(self, key):\n return Middle()\n" + "aaa = Outer()\ncheckme = aaa[0][0]" << "str" << true; + QTest::newRow("subscript_func_call") << + "class Foo:\n def __getitem__(self, key):\n return str()\n" + "def bar():\n return Foo()\n" + "checkme = bar()[0]" << "str" << true; } void PyDUChainTest::testVariableCreation()