Skip to content
Snippets Groups Projects
Commit eec18d92 authored by Francis Herne's avatar Francis Herne
Browse files

Very basic property getter support

Property decorators were ignored except for code-completion, trying to
 access properties would get a function rather than the returned type.

CCBUG: 372273

Just replace property functions with their return type in
 ExpressionVisitor::visitCall().

This only works for getter-only properties - if there's a setter function
 for the property (which idiomatically has the same name), visitCall() finds
 that declaration instead and gives the wrong return type.

Still, it's useful in a good proportion of cases.

To make this work properly, I think we need a specific declaration type
 for properties, and to update that when visiting the getter/setter
 instead of creating the function declarations directly in the class?

One new test fail->pass.
Two new tests still fail.
No test regressions.

Differential Revision: https://phabricator.kde.org/D4207
parent d41aa730
No related branches found
No related tags found
No related merge requests found
......@@ -97,15 +97,21 @@ void ExpressionVisitor::visitAttribute(AttributeAst* node)
// Like, for B.C where B is an instance of foo, find a property of foo called C.
DUChainReadLocker lock;
auto attribute = Helper::accessAttribute(v.lastType(), node->attribute->value, topContext());
if ( auto resolved = Helper::resolveAliasDeclaration(attribute) ) {
encounter(attribute->abstractType(), DeclarationPointer(attribute));
setLastIsAlias(dynamic_cast<AliasDeclaration*>(attribute) ||
resolved->isFunctionDeclaration() ||
dynamic_cast<ClassDeclaration*>(resolved));
} else {
auto resolved = Helper::resolveAliasDeclaration(attribute);
if ( ! resolved ) {
encounterUnknown();
return;
}
auto function = dynamic_cast<FunctionDeclaration*>(resolved);
if ( function && function->type<FunctionType>() &&
Helper::findDecoratorByName(function, QLatin1String("property")) ) {
encounter(function->type<FunctionType>()->returnType(), DeclarationPointer(function));
return;
}
encounter(attribute->abstractType(), DeclarationPointer(attribute));
setLastIsAlias(function ||
dynamic_cast<AliasDeclaration*>(attribute) ||
dynamic_cast<ClassDeclaration*>(resolved) );
}
void ExpressionVisitor::visitCall(CallAst* node)
......
......@@ -806,11 +806,11 @@ void PyDUChainTest::testTypes()
QFETCH(QString, code);
QFETCH(QString, expectedType);
ReferencedTopDUContext ctx = parse(code.toUtf8());
QVERIFY(ctx);
QVERIFY(m_ast);
DUChainReadLocker lock(DUChain::lock());
TypeTestVisitor* visitor = new TypeTestVisitor();
visitor->ctx = TopDUContextPointer(ctx.data());
......@@ -823,6 +823,8 @@ void PyDUChainTest::testTypes()
QEXPECT_FAIL("return_builtin_iterator", "fake builtin iter()", Continue);
QEXPECT_FAIL("parent_constructor_arg_type", "Not enough passes?", Continue);
QEXPECT_FAIL("init_class_no_decl", "aliasing info lost", Continue);
QEXPECT_FAIL("property_wrong", "visitCall uses declaration if no type", Continue);
QEXPECT_FAIL("property_setter", "very basic property support", Continue);
QCOMPARE(visitor->found, true);
}
......@@ -1105,11 +1107,25 @@ void PyDUChainTest::testTypes_data()
" return k\n"
"f = Foo.foo()\n"
"checkme = f\n" << "Foo";
QTest::newRow("property_getter") << "class Foo:\n"
" @property\n"
" def bar(self): return 35\n"
"checkme = Foo().bar" << "int";
QTest::newRow("property_wrong") << "class Foo:\n"
" @property\n"
" def bar(self): return True\n"
"checkme = Foo().bar()" << "mixed";
QTest::newRow("property_setter") << "class Foo:\n"
" @property\n"
" def bar(self): return 35\n"
" @bar.setter\n"
" def bar(self, value): return 18.3\n" // Return should be ignored
"checkme = Foo().bar" << "int";
QTest::newRow("tuple_listof") << "l = [(1, 2), (3, 4)]\ncheckme = l[1][0]" << "int";
QTest::newRow("getitem") << "class c:\n def __getitem__(self, slice): return 3.14\na = c()\ncheckme = a[2]" << "float";
QTest::newRow("constructor_type_deduction") << "class myclass:\n"
"\tdef __init__(self, param): self.foo=param\n"
"checkme = myclass(3).foo" << "int";
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment