When listing the definitions for a given method call, filter out those method definitions whose signatures do not match the arguments passed in the call.
Example
class A:
def foo(a, b):
return a + b
class B:
def foo():
return 5
def run(x, y):
x.foo() # <- No arguments. `x` is probably an instance of `B`, not `A`.
y.foo(5, 6) # <- Two arguments. `y` is probably an instance of `A`, not `B`.
- Advantage - Can be stored pretty simply (direct metadata about each function definition and call).
- Disadvantage - Will not rule out very many things, as many methods have the same signature.
- Question - Should type information about parameters and arguments be taken into account?
When listing the definitions, compare structural type information about the method's receiver to information about the class containing the definition.
Example:
class Person():
def talk():
return t
def get_age():
return a
class Robot():
def talk():
return c
def get_serial_number():
return d
def run(x):
a = x.get_serial_number()
b = x.talk() # <- The receiver `x` also has a `get_serial_number` method, so
# x is probably an instance of `Robot`.
- Advantage - I think structural type information is available to narrow things down in a high percentage of cases.
- Question - How do we store and propagate this structural type information?
In some cases, you can locally find the name of a variable's type:
Example:
def run():
a = Robot()
# ...
b = a
# ...
b.talk() # <- `b` was assigned from `a`, which was assigned from a constructor call to `Robot`.
- Advantage - Sometimes, this would allow us to narrow things down to one implementation
- Question - Often, the dataflow will be much more indirect, and span multiple files. How far do we track it?