Bug 369364

Summary: Calling an instance method through the class deduces arg types wrong
Product: [Developer tools] kdev-python Reporter: Nicolás Alvarez <nalvarez>
Component: Language supportAssignee: Sven Brauch <mail>
Status: RESOLVED FIXED    
Severity: normal CC: mail
Priority: NOR    
Version: 5.0.1   
Target Milestone: 1.7.3   
Platform: Other   
OS: Linux   
Latest Commit: Version Fixed In:
Sentry Crash Report:

Description Nicolás Alvarez 2016-09-26 00:48:48 UTC
If an instance method is called 'directly' through the class, like this:
class MyClass:
    def method(self, arg1):
        pass

obj = MyClass()
MyClass.method(obj, 42)

The argument type is deduced wrong. It thinks the 'obj' argument matches with the 'arg1' parameter, but it should be matched with 'self'. This means it deduces 'arg1' to be of type 'MyClass', when it should be 'int'.

A notable common case where this causes problems is when a constructor calls the constructor of the base class:

class Base:
    def __init__(self, foo):
        self.foo = foo

class Derived(Base):
    def __init__(self, foo):
        Base.__init__(self, foo)
        # ...more Derived-specific initialization...

Now it thinks Base.__init__'s 'foo' argument is of type 'Derived', which also affects the type of the 'foo' attribute of the object, which cascades into breaking types in many other places :(
Comment 1 Sven Brauch 2016-10-01 18:46:33 UTC
Yep, need to fix that. Thanks for the comprehensible report.
Comment 2 Francis Herne 2016-12-14 09:07:48 UTC
Git commit b36edbb6c54a462cc6d72c344c0f760d5a7c2248 by Francis Herne.
Committed on 14/12/2016 at 09:07.
Pushed by flherne into branch 'master'.

Skip explicit `self` argument when calling via class.

Instance methods can be called via the class:
 `Class.method(instance, arg)`

Self arguments are handled separately. With an explicit `instance`
 argument as in the example, its type was wrongly used for the next
 argument with all subsequent argtypes offset by one.

Simply skip such arguments where they exist.

Test `method_explicit_self` previously failed, now passes.

Test `parent_constructor_arg_type` previously failed.
Now it fails on the first run, but gets the correct type if reloading
 the document.
Probably related to https://bugs.kde.org/show_bug.cgi?id=306213

Other new tests passed already.
No test regressions.

M  +21   -9    duchain/declarationbuilder.cpp
M  +29   -0    duchain/tests/pyduchaintest.cpp

https://commits.kde.org/kdev-python/b36edbb6c54a462cc6d72c344c0f760d5a7c2248
Comment 3 Francis Herne 2016-12-14 09:16:13 UTC
Your actually-useful example still doesn't work properly - the type of Base.foo won't be found unless the document is reparsed another couple of times, e.g. by hitting F5.

See https://bugs.kde.org/show_bug.cgi?id=306213