1.1 --- a/deducer.py Sat Oct 08 00:34:34 2016 +0200
1.2 +++ b/deducer.py Sat Oct 08 00:43:13 2016 +0200
1.3 @@ -20,8 +20,8 @@
1.4 """
1.5
1.6 from common import first, get_attrname_from_location, get_attrnames, \
1.7 - get_name_path, init_item, sorted_output, \
1.8 - CommonOutput
1.9 + get_invoked_attributes, get_name_path, init_item, \
1.10 + sorted_output, CommonOutput
1.11 from encoders import encode_attrnames, encode_access_location, \
1.12 encode_constrained, encode_location, encode_usage, \
1.13 get_kinds, test_for_kinds, test_for_type
1.14 @@ -1394,7 +1394,9 @@
1.15 constrained,
1.16 constrained_specific) = self.get_target_types(accessor_location, usage)
1.17
1.18 - self.record_reference_types(accessor_location, class_types, instance_types, module_types, constrained, constrained_specific)
1.19 + invocations = get_invoked_attributes(usage)
1.20 +
1.21 + self.record_reference_types(accessor_location, class_types, instance_types, module_types, constrained, constrained_specific, invocations)
1.22
1.23 def record_types_for_attribute(self, access_location, attrname):
1.24
1.25 @@ -1543,7 +1545,7 @@
1.26 return None
1.27
1.28 def record_reference_types(self, location, class_types, instance_types,
1.29 - module_types, constrained, constrained_specific=False):
1.30 + module_types, constrained, constrained_specific=False, invocations=None):
1.31
1.32 """
1.33 Associate attribute provider types with the given 'location', consisting
1.34 @@ -1572,12 +1574,18 @@
1.35 # Instance-only and module types support only their own kinds as
1.36 # accessors.
1.37
1.38 + path, name, version, attrnames = location
1.39 +
1.40 + if invocations:
1.41 + class_only_types = self.filter_for_invocations(class_types, invocations)
1.42 + else:
1.43 + class_only_types = class_types
1.44 +
1.45 # However, the nature of accessors can be further determined.
1.46 # Any self variable may only refer to an instance.
1.47
1.48 - path, name, version, attrnames = location
1.49 if name != "self" or not self.in_method(path):
1.50 - self.accessor_class_types[location].update(class_types)
1.51 + self.accessor_class_types[location].update(class_only_types)
1.52
1.53 if not constrained_specific:
1.54 self.accessor_instance_types[location].update(class_types)
1.55 @@ -1590,6 +1598,30 @@
1.56 if constrained:
1.57 self.accessor_constrained.add(location)
1.58
1.59 + def filter_for_invocations(self, class_types, attrnames):
1.60 +
1.61 + """
1.62 + From the given 'class_types', identify methods for the given
1.63 + 'attrnames' that are being invoked, returning a filtered collection of
1.64 + class types.
1.65 + """
1.66 +
1.67 + to_filter = set()
1.68 +
1.69 + for class_type in class_types:
1.70 + for attrname in attrnames:
1.71 + ref = self.importer.get_class_attribute(class_type, attrname)
1.72 + parent_class = ref and ref.parent()
1.73 +
1.74 + if ref and ref.has_kind("<function>") and (
1.75 + parent_class == class_type or
1.76 + class_type in self.descendants[parent_class]):
1.77 +
1.78 + to_filter.add(class_type)
1.79 + break
1.80 +
1.81 + return set(class_types).difference(to_filter)
1.82 +
1.83 def identify_reference_attributes(self, location, attrname, class_types, instance_types, module_types, constrained):
1.84
1.85 """