1.1 --- a/deducer.py Sun Mar 12 21:41:50 2017 +0100
1.2 +++ b/deducer.py Mon Mar 13 01:53:43 2017 +0100
1.3 @@ -903,9 +903,11 @@
1.4 access_location = (path, None, attrname_str, 0)
1.5
1.6 # Plain name accesses do not employ attributes and are
1.7 - # ignored.
1.8 + # ignored. Whether they are invoked is of interest, however.
1.9
1.10 if not attrname_str:
1.11 + if invocation:
1.12 + self.reference_invocations[access_location] = invocation
1.13 continue
1.14
1.15 attrnames = get_attrnames(attrname_str)
1.16 @@ -1518,6 +1520,9 @@
1.17 if not attrname:
1.18 return
1.19
1.20 + invocation = access_location in self.reference_invocations
1.21 + assignment = access_location in self.reference_assignments
1.22 +
1.23 # Collect all suggested types for the accessors. Accesses may
1.24 # require accessors from of a subset of the complete set of types.
1.25
1.26 @@ -1547,7 +1552,7 @@
1.27
1.28 else:
1.29 self.init_definition_details(location)
1.30 - self.record_types_for_usage(location, [(attrname, False, False)])
1.31 + self.record_types_for_usage(location, [(attrname, invocation, assignment)])
1.32
1.33 constrained = location in self.accessor_constrained and constrained
1.34
1.35 @@ -1618,11 +1623,19 @@
1.36 provider_instance_types = self.provider_instance_types[accessor_location]
1.37 provider_module_types = self.provider_module_types[accessor_location]
1.38
1.39 + accessor_class_types = self.accessor_class_types[accessor_location]
1.40 + accessor_instance_types = self.accessor_instance_types[accessor_location]
1.41 + accessor_module_types = self.accessor_module_types[accessor_location]
1.42 +
1.43 # Find details for any corresponding access.
1.44
1.45 - all_class_types = set()
1.46 - all_instance_types = set()
1.47 - all_module_types = set()
1.48 + new_provider_class_types = set()
1.49 + new_provider_instance_types = set()
1.50 + new_provider_module_types = set()
1.51 +
1.52 + new_accessor_class_types = set()
1.53 + new_accessor_instance_types = set()
1.54 + new_accessor_module_types = set()
1.55
1.56 for access_location in self.alias_index[accessor_location]:
1.57 location, name, attrnames, access_number = access_location
1.58 @@ -1645,10 +1658,20 @@
1.59 # Obtain references and attribute types for the access.
1.60
1.61 attrs = self.get_references_for_access(access_location)
1.62 - attrs = self.convert_invocation_providers(attrs, invocation)
1.63 +
1.64 + # Where no specific attributes are defined, do not attempt
1.65 + # to refine the alias's types.
1.66 +
1.67 + if not attrs:
1.68 + return
1.69 +
1.70 + # Invocations converting class accessors to instances do not
1.71 + # change the nature of class providers.
1.72 +
1.73 + provider_attrs = self.convert_invocation_providers(attrs, invocation)
1.74
1.75 (class_types, instance_types, module_types, function_types,
1.76 - var_types) = separate_types(attrs)
1.77 + var_types) = separate_types(provider_attrs)
1.78
1.79 # Where non-accessor types are found, do not attempt to refine
1.80 # the defined accessor types.
1.81 @@ -1656,13 +1679,30 @@
1.82 if function_types or var_types:
1.83 return
1.84
1.85 - # Invocations converting class accessors to instances do not
1.86 - # change the nature of class providers.
1.87 -
1.88 class_types = set(provider_class_types).intersection(class_types)
1.89 instance_types = set(provider_instance_types).intersection(instance_types)
1.90 module_types = set(provider_module_types).intersection(module_types)
1.91
1.92 + new_provider_class_types.update(class_types)
1.93 + new_provider_instance_types.update(instance_types)
1.94 + new_provider_module_types.update(module_types)
1.95 +
1.96 + # Accessors are updated separately, employing invocation
1.97 + # result details.
1.98 +
1.99 + accessor_attrs = self.convert_invocations(attrs, invocation)
1.100 +
1.101 + (class_types, instance_types, module_types, function_types,
1.102 + var_types) = separate_types(accessor_attrs)
1.103 +
1.104 + class_types = set(accessor_class_types).intersection(class_types)
1.105 + instance_types = set(accessor_instance_types).intersection(instance_types)
1.106 + module_types = set(accessor_module_types).intersection(module_types)
1.107 +
1.108 + new_accessor_class_types.update(class_types)
1.109 + new_accessor_instance_types.update(instance_types)
1.110 + new_accessor_module_types.update(module_types)
1.111 +
1.112 # Alias references a name, not an access.
1.113
1.114 else:
1.115 @@ -1670,10 +1710,32 @@
1.116
1.117 attr = self.get_initialised_name(access_location)
1.118 if attr:
1.119 - attrs = self.convert_invocation_providers([attr], invocation)
1.120 + attrs = [attr]
1.121 + provider_attrs = self.convert_invocation_providers(attrs, invocation)
1.122
1.123 (class_types, instance_types, module_types, function_types,
1.124 - var_types) = separate_types(attrs)
1.125 + var_types) = separate_types(provider_attrs)
1.126 +
1.127 + class_types = set(provider_class_types).intersection(class_types)
1.128 + instance_types = set(provider_instance_types).intersection(instance_types)
1.129 + module_types = set(provider_module_types).intersection(module_types)
1.130 +
1.131 + new_provider_class_types.update(class_types)
1.132 + new_provider_instance_types.update(instance_types)
1.133 + new_provider_module_types.update(module_types)
1.134 +
1.135 + accessor_attrs = self.convert_invocations(attrs, invocation)
1.136 +
1.137 + (class_types, instance_types, module_types, function_types,
1.138 + var_types) = separate_types(accessor_attrs)
1.139 +
1.140 + class_types = set(accessor_class_types).intersection(class_types)
1.141 + instance_types = set(accessor_instance_types).intersection(instance_types)
1.142 + module_types = set(accessor_module_types).intersection(module_types)
1.143 +
1.144 + new_accessor_class_types.update(class_types)
1.145 + new_accessor_instance_types.update(instance_types)
1.146 + new_accessor_module_types.update(module_types)
1.147
1.148 # Where no further information is found, do not attempt to
1.149 # refine the defined accessor types.
1.150 @@ -1681,14 +1743,11 @@
1.151 else:
1.152 return
1.153
1.154 - all_class_types.update(class_types)
1.155 - all_instance_types.update(instance_types)
1.156 - all_module_types.update(module_types)
1.157 -
1.158 # Record refined type details for the alias as an accessor.
1.159
1.160 self.init_definition_details(accessor_location)
1.161 - self.record_reference_types(accessor_location, all_class_types, all_instance_types, all_module_types, False)
1.162 + self.update_provider_types(accessor_location, new_provider_class_types, new_provider_instance_types, new_provider_module_types)
1.163 + self.update_accessor_types(accessor_location, new_accessor_class_types, new_accessor_instance_types, new_accessor_module_types)
1.164
1.165 # Without an access, attempt to identify references for the alias.
1.166 # Invocations convert classes to instances and also attempt to find
1.167 @@ -1719,9 +1778,7 @@
1.168
1.169 # Alias references an attribute access.
1.170
1.171 - attrname = attrnames and attrnames[0]
1.172 -
1.173 - if attrname:
1.174 + if attrnames:
1.175
1.176 # Obtain references and attribute types for the access.
1.177
1.178 @@ -1746,7 +1803,8 @@
1.179 instance_types = self.provider_instance_types[access_location]
1.180 module_types = self.provider_module_types[access_location]
1.181
1.182 - refs.update(combine_types(class_types, instance_types, module_types))
1.183 + types = combine_types(class_types, instance_types, module_types)
1.184 + refs.update(self.convert_invocation_providers(types, invocation))
1.185
1.186 # Record reference details for the alias separately from accessors.
1.187
1.188 @@ -1863,15 +1921,13 @@
1.189
1.190 # Update the type details for the location.
1.191
1.192 - self.provider_class_types[location].update(class_types)
1.193 - self.provider_instance_types[location].update(instance_types)
1.194 - self.provider_module_types[location].update(module_types)
1.195 + self.update_provider_types(location, class_types, instance_types, module_types)
1.196
1.197 # Class types support classes and instances as accessors.
1.198 # Instance-only and module types support only their own kinds as
1.199 # accessors.
1.200
1.201 - path, name, version, attrnames = location
1.202 + path, name, attrnames, version = location
1.203
1.204 if invocations:
1.205 class_only_types = self.filter_for_invocations(class_types, invocations)
1.206 @@ -1895,6 +1951,28 @@
1.207 if constrained:
1.208 self.accessor_constrained.add(location)
1.209
1.210 + def update_provider_types(self, location, class_types, instance_types, module_types):
1.211 +
1.212 + """
1.213 + Update provider types for the given 'location', adding 'class_types',
1.214 + 'instance_types' and 'module_types' to those already stored.
1.215 + """
1.216 +
1.217 + self.provider_class_types[location].update(class_types)
1.218 + self.provider_instance_types[location].update(instance_types)
1.219 + self.provider_module_types[location].update(module_types)
1.220 +
1.221 + def update_accessor_types(self, location, class_types, instance_types, module_types):
1.222 +
1.223 + """
1.224 + Update accessor types for the given 'location', adding 'class_types',
1.225 + 'instance_types' and 'module_types' to those already stored.
1.226 + """
1.227 +
1.228 + self.accessor_class_types[location].update(class_types)
1.229 + self.accessor_instance_types[location].update(instance_types)
1.230 + self.accessor_module_types[location].update(module_types)
1.231 +
1.232 def filter_for_invocations(self, class_types, attrnames):
1.233
1.234 """
2.1 --- a/inspector.py Sun Mar 12 21:41:50 2017 +0100
2.2 +++ b/inspector.py Mon Mar 13 01:53:43 2017 +0100
2.3 @@ -909,7 +909,8 @@
2.4 branches = self.trackers[-1].tracking_name(name)
2.5 if branches:
2.6 self.record_branches_for_access(branches, name, None)
2.7 - return self.record_access_details(name, None, None, None)
2.8 + return self.record_access_details(name, None, self.in_assignment,
2.9 + self.in_invocation)
2.10 return None
2.11
2.12 def process_operator_chain(self, nodes, fn):