1.1 --- a/deducer.py Thu Mar 16 18:13:34 2017 +0100
1.2 +++ b/deducer.py Sun Mar 19 00:56:43 2017 +0100
1.3 @@ -62,10 +62,18 @@
1.4
1.5 self.access_index = {}
1.6
1.7 + # Map definition locations to affected accesses.
1.8 +
1.9 + self.access_index_rev = {}
1.10 +
1.11 # Map aliases to accesses that define them.
1.12
1.13 self.alias_index = {}
1.14
1.15 + # Map accesses to aliases whose initial values are influenced by them.
1.16 +
1.17 + self.alias_index_rev = {}
1.18 +
1.19 # Map constant accesses to redefined accesses.
1.20
1.21 self.const_accesses = {}
1.22 @@ -372,7 +380,8 @@
1.23 if referenced_attrs:
1.24 attrname = get_attrname_from_location(location)
1.25
1.26 - all_accessed_attrs = self.reference_all_attrs[location]
1.27 + all_accessed_attrs = list(set(self.reference_all_attrs[location]))
1.28 + all_accessed_attrs.sort()
1.29
1.30 for attrtype, attrs in self.get_referenced_attrs(location):
1.31 print >>f_attrs, encode_access_location(location), encode_constrained(constrained), attrtype, sorted_output(attrs)
1.32 @@ -520,9 +529,10 @@
1.33 self.accessor_all_general_types[location] = all_general_types = \
1.34 combine_types(general_class_types, general_instance_types, general_module_types)
1.35
1.36 - # Record guard information.
1.37 -
1.38 - if not constrained:
1.39 + # Record guard information but only for accessors employed by
1.40 + # accesses. There are no attribute accesses to guard, otherwise.
1.41 +
1.42 + if not constrained and self.access_index_rev.get(location):
1.43
1.44 # Record specific type guard details.
1.45
1.46 @@ -862,6 +872,13 @@
1.47 location = (path, name, None, version)
1.48 locations.append(location)
1.49
1.50 + # Map accessors to affected accesses.
1.51 +
1.52 + l = init_item(self.access_index_rev, location, set)
1.53 + l.add(access_location)
1.54 +
1.55 + # Map accesses to supplying accessors.
1.56 +
1.57 self.access_index[access_location] = locations
1.58
1.59 def get_accessors_for_access(self, access_location):
1.60 @@ -955,22 +972,21 @@
1.61
1.62 for (path, name), all_aliases in self.importer.all_aliased_names.items():
1.63
1.64 - # For each version of the name, obtain the access location.
1.65 -
1.66 - for version, (original_path, original_name, attrnames, access_number) in all_aliases.items():
1.67 - accessor_location = (path, name, None, version)
1.68 - access_location = (original_path, original_name, attrnames, access_number)
1.69 - init_item(self.alias_index, accessor_location, list)
1.70 - self.alias_index[accessor_location].append(access_location)
1.71 + # For each version of the name, obtain the access locations.
1.72 +
1.73 + for version, aliases in all_aliases.items():
1.74 + for (original_path, original_name, attrnames, access_number) in aliases:
1.75 + accessor_location = (path, name, None, version)
1.76 + access_location = (original_path, original_name, attrnames, access_number)
1.77 + init_item(self.alias_index, accessor_location, list)
1.78 + self.alias_index[accessor_location].append(access_location)
1.79
1.80 # Get aliases in terms of non-aliases and accesses.
1.81
1.82 for accessor_location, access_locations in self.alias_index.items():
1.83 self.update_aliases(accessor_location, access_locations)
1.84
1.85 - # Get accesses affected by aliases.
1.86 -
1.87 - self.alias_index_rev = {}
1.88 + # Get a mapping from accesses to affected aliases.
1.89
1.90 for accessor_location, access_locations in self.alias_index.items():
1.91 for access_location in access_locations:
1.92 @@ -996,10 +1012,16 @@
1.93 for access_location in access_locations:
1.94 (path, original_name, attrnames, access_number) = access_location
1.95
1.96 + # Locations may have been recorded for return values, but they may
1.97 + # not correspond to actual accesses.
1.98 +
1.99 + if not self.access_index.has_key(access_location):
1.100 + updated_locations.add(access_location)
1.101 +
1.102 # Where an alias refers to a name access, obtain the original name
1.103 # version details.
1.104
1.105 - if attrnames is None:
1.106 + elif attrnames is None:
1.107
1.108 # For each name version, attempt to determine any accesses that
1.109 # initialise the name.
1.110 @@ -1250,10 +1272,8 @@
1.111
1.112 # Specific name-based attribute accesses.
1.113
1.114 - alias_accesses = set()
1.115 -
1.116 for access_location, accessor_locations in self.access_index.items():
1.117 - self.record_types_for_access(access_location, accessor_locations, alias_accesses)
1.118 + self.record_types_for_access(access_location, accessor_locations)
1.119
1.120 # Anonymous references with attribute chains.
1.121
1.122 @@ -1373,6 +1393,23 @@
1.123 if self.record_types_for_alias(location):
1.124 updated_aliases.add(location)
1.125
1.126 + # Define accesses employing aliases.
1.127 +
1.128 + alias_accesses = set()
1.129 + affected_aliases = set()
1.130 +
1.131 + for alias in updated_aliases:
1.132 +
1.133 + # Access affected by the alias.
1.134 +
1.135 + if self.access_index_rev.has_key(alias):
1.136 + alias_accesses.update(self.access_index_rev[alias])
1.137 +
1.138 + # Another alias affected by the alias.
1.139 +
1.140 + elif self.alias_index_rev.has_key(alias):
1.141 + affected_aliases.update(self.alias_index_rev[alias])
1.142 +
1.143 # Update accesses employing aliases.
1.144
1.145 updated_accesses = set()
1.146 @@ -1381,9 +1418,7 @@
1.147 if self.record_types_for_access(access_location, self.access_index[access_location]):
1.148 updated_accesses.add(access_location)
1.149
1.150 - # Update aliases for updated accesses.
1.151 -
1.152 - affected_aliases = set()
1.153 + # Determine which aliases are affected by the updated accesses.
1.154
1.155 for access_location in updated_accesses:
1.156 if self.alias_index_rev.has_key(access_location):
1.157 @@ -1433,10 +1468,10 @@
1.158 # Detect any initialised name for the location.
1.159
1.160 if name:
1.161 - ref = self.get_initialised_name(location)
1.162 - if ref:
1.163 + refs = self.get_initialised_name(location)
1.164 + if refs:
1.165 (class_types, only_instance_types, module_types,
1.166 - _function_types, _var_types) = separate_types([ref])
1.167 + _function_types, _var_types) = separate_types(refs)
1.168 return class_types, only_instance_types, module_types, True, have_assignments
1.169
1.170 # Retrieve the recorded types for the usage.
1.171 @@ -1541,7 +1576,7 @@
1.172
1.173 self.referenced_attrs[location] = {}
1.174
1.175 - def record_types_for_access(self, access_location, accessor_locations, alias_accesses=None):
1.176 + def record_types_for_access(self, access_location, accessor_locations):
1.177
1.178 """
1.179 Define types for the 'access_location' associated with the given
1.180 @@ -1568,11 +1603,6 @@
1.181
1.182 for location in accessor_locations:
1.183
1.184 - # Remember accesses employing aliases.
1.185 -
1.186 - if alias_accesses is not None and self.alias_index.has_key(location):
1.187 - alias_accesses.add(access_location)
1.188 -
1.189 # Use the type information deduced for names from above.
1.190
1.191 if self.accessor_class_types.has_key(location):
1.192 @@ -1676,6 +1706,8 @@
1.193 new_accessor_instance_types = set()
1.194 new_accessor_module_types = set()
1.195
1.196 + refs = set()
1.197 +
1.198 for access_location in self.alias_index[accessor_location]:
1.199 location, name, attrnames, access_number = access_location
1.200 invocation = self.reference_invocations.get(access_location)
1.201 @@ -1742,52 +1774,67 @@
1.202 new_accessor_instance_types.update(instance_types)
1.203 new_accessor_module_types.update(module_types)
1.204
1.205 + refs.update(accessor_attrs)
1.206 +
1.207 # Alias references a name, not an access.
1.208
1.209 else:
1.210 - # Attempt to refine the types using initialised names.
1.211 -
1.212 - attr = self.get_initialised_name(access_location)
1.213 - if attr:
1.214 - attrs = [attr]
1.215 + # Attempt to refine the types using initialised names or
1.216 + # accessors.
1.217 +
1.218 + attrs = self.get_initialised_name(access_location)
1.219 +
1.220 + if attrs:
1.221 provider_attrs = self.convert_invocation_providers(attrs, invocation)
1.222 -
1.223 - (class_types, instance_types, module_types, function_types,
1.224 - var_types) = separate_types(provider_attrs)
1.225 -
1.226 - class_types = set(provider_class_types).intersection(class_types)
1.227 - instance_types = set(provider_instance_types).intersection(instance_types)
1.228 - module_types = set(provider_module_types).intersection(module_types)
1.229 -
1.230 - new_provider_class_types.update(class_types)
1.231 - new_provider_instance_types.update(instance_types)
1.232 - new_provider_module_types.update(module_types)
1.233 -
1.234 accessor_attrs = self.convert_invocations(attrs, invocation)
1.235 -
1.236 - (class_types, instance_types, module_types, function_types,
1.237 - var_types) = separate_types(accessor_attrs)
1.238 -
1.239 - class_types = set(accessor_class_types).intersection(class_types)
1.240 - instance_types = set(accessor_instance_types).intersection(instance_types)
1.241 - module_types = set(accessor_module_types).intersection(module_types)
1.242 -
1.243 - new_accessor_class_types.update(class_types)
1.244 - new_accessor_instance_types.update(instance_types)
1.245 - new_accessor_module_types.update(module_types)
1.246 + else:
1.247 + provider_attrs = self.get_provider_references(access_location)
1.248 + attrs = accessor_attrs = self.get_accessor_references(access_location)
1.249
1.250 # Where no further information is found, do not attempt to
1.251 # refine the defined accessor types.
1.252
1.253 - else:
1.254 + if not attrs:
1.255 return False
1.256
1.257 + (class_types, instance_types, module_types, function_types,
1.258 + var_types) = separate_types(provider_attrs)
1.259 +
1.260 + class_types = set(provider_class_types).intersection(class_types)
1.261 + instance_types = set(provider_instance_types).intersection(instance_types)
1.262 + module_types = set(provider_module_types).intersection(module_types)
1.263 +
1.264 + new_provider_class_types.update(class_types)
1.265 + new_provider_instance_types.update(instance_types)
1.266 + new_provider_module_types.update(module_types)
1.267 +
1.268 + (class_types, instance_types, module_types, function_types,
1.269 + var_types) = separate_types(accessor_attrs)
1.270 +
1.271 + class_types = set(accessor_class_types).intersection(class_types)
1.272 + instance_types = set(accessor_instance_types).intersection(instance_types)
1.273 + module_types = set(accessor_module_types).intersection(module_types)
1.274 +
1.275 + new_accessor_class_types.update(class_types)
1.276 + new_accessor_instance_types.update(instance_types)
1.277 + new_accessor_module_types.update(module_types)
1.278 +
1.279 + refs.update(accessor_attrs)
1.280 +
1.281 + # Update the alias relationships for invocations.
1.282 +
1.283 + self.update_alias_accesses(access_location, attrs)
1.284 +
1.285 # Record refined type details for the alias as an accessor.
1.286
1.287 self.init_definition_details(accessor_location)
1.288 self.update_provider_types(accessor_location, new_provider_class_types, new_provider_instance_types, new_provider_module_types)
1.289 self.update_accessor_types(accessor_location, new_accessor_class_types, new_accessor_instance_types, new_accessor_module_types)
1.290
1.291 + # Record reference details for the alias separately from accessors.
1.292 +
1.293 + self.referenced_objects[accessor_location] = refs
1.294 +
1.295 return new_accessor_class_types != accessor_class_types or \
1.296 new_accessor_instance_types != accessor_instance_types or \
1.297 new_accessor_module_types != accessor_module_types
1.298 @@ -1797,16 +1844,9 @@
1.299 # return value information.
1.300
1.301 else:
1.302 - old_refs = self.referenced_objects.get(accessor_location)
1.303 refs = set()
1.304
1.305 for access_location in self.alias_index[accessor_location]:
1.306 -
1.307 - # Obtain any redefined constant access location.
1.308 -
1.309 - if self.const_accesses.has_key(access_location):
1.310 - access_location = self.const_accesses[access_location]
1.311 -
1.312 location, name, attrnames, access_number = access_location
1.313 invocation = self.reference_invocations.get(access_location)
1.314
1.315 @@ -1827,8 +1867,14 @@
1.316 # Obtain references and attribute types for the access.
1.317
1.318 attrs = self.get_references_for_access(access_location)
1.319 - attrs = self.convert_invocations(attrs, invocation)
1.320 - refs.update(attrs)
1.321 +
1.322 + # Where no further information is found, do not attempt to
1.323 + # refine the defined accessor types.
1.324 +
1.325 + if not attrs:
1.326 + return False
1.327 +
1.328 + refs.update(self.convert_invocations(attrs, invocation))
1.329
1.330 # Alias references a name, not an access.
1.331
1.332 @@ -1836,25 +1882,83 @@
1.333
1.334 # Obtain initialiser information.
1.335
1.336 - attr = self.get_initialised_name(access_location)
1.337 - if attr:
1.338 - refs.update(self.convert_invocations([attr], invocation))
1.339 -
1.340 - # Obtain provider information.
1.341 -
1.342 - elif self.provider_class_types.has_key(access_location):
1.343 - class_types = self.provider_class_types[access_location]
1.344 - instance_types = self.provider_instance_types[access_location]
1.345 - module_types = self.provider_module_types[access_location]
1.346 -
1.347 - types = combine_types(class_types, instance_types, module_types)
1.348 - refs.update(self.convert_invocation_providers(types, invocation))
1.349 + attrs = self.get_initialised_name(access_location)
1.350 +
1.351 + if attrs:
1.352 + provider_attrs = self.convert_invocation_providers(attrs, invocation)
1.353 + accessor_attrs = self.convert_invocations(attrs, invocation)
1.354 + else:
1.355 + provider_attrs = self.get_provider_references(access_location)
1.356 + attrs = accessor_attrs = self.get_accessor_references(access_location)
1.357 +
1.358 + # Where no further information is found, do not attempt to
1.359 + # refine the defined accessor types.
1.360 +
1.361 + if not attrs:
1.362 + return False
1.363 +
1.364 + refs.update(self.convert_invocations(attrs, invocation))
1.365 +
1.366 + # Update the alias relationships for invocations.
1.367 +
1.368 + self.update_alias_accesses(access_location, attrs)
1.369 +
1.370 + # Record refined type details for the alias as an accessor.
1.371 +
1.372 + (class_types, instance_types, module_types, function_types,
1.373 + var_types) = separate_types(refs)
1.374 +
1.375 + # Where non-accessor types are found, do not attempt to refine
1.376 + # the defined accessor types.
1.377 +
1.378 + if not function_types and not var_types:
1.379 + self.init_definition_details(accessor_location)
1.380 + self.update_provider_types(accessor_location, class_types + instance_types, class_types + instance_types, module_types)
1.381 + self.update_accessor_types(accessor_location, class_types, instance_types, module_types)
1.382
1.383 # Record reference details for the alias separately from accessors.
1.384
1.385 self.referenced_objects[accessor_location] = refs
1.386
1.387 - return old_refs != refs
1.388 + return True
1.389 +
1.390 + def update_alias_accesses(self, access_location, refs):
1.391 +
1.392 + """
1.393 + Record 'access_location' as a location affected by the return values of
1.394 + 'refs' if an invocation is involved.
1.395 + """
1.396 +
1.397 + if not self.reference_invocations.has_key(access_location):
1.398 + return
1.399 +
1.400 + for ref in refs:
1.401 +
1.402 + # Initialising accesses originate from the return values.
1.403 +
1.404 + key = (ref.get_origin(), "$return")
1.405 + self._update_alias_accesses(access_location, key, self.importer.all_initialised_names)
1.406 + self._update_alias_accesses(access_location, key, self.importer.all_aliased_names)
1.407 +
1.408 + def _update_alias_accesses(self, access_location, key, names):
1.409 +
1.410 + """
1.411 + Make each return value provide information to the given
1.412 + 'access_location', using 'key' to reference the return value and 'names'
1.413 + as the collection of definitions.
1.414 + """
1.415 +
1.416 + versions = names.get(key)
1.417 + if not versions:
1.418 + return
1.419 +
1.420 + for version in versions.keys():
1.421 + location = key + (None, version)
1.422 + l = init_item(self.alias_index_rev, location, set)
1.423 + l.add(access_location)
1.424 +
1.425 + l = init_item(self.alias_index, access_location, set)
1.426 + l.add(location)
1.427
1.428 def get_references_for_access(self, access_location):
1.429
1.430 @@ -1878,11 +1982,20 @@
1.431 providers = set()
1.432
1.433 for ref in refs:
1.434 - ref = self.convert_invocation_provider(ref)
1.435 + invocation_providers = self.convert_accessors_to_providers(self.convert_invocation_provider(ref))
1.436 + providers.update(invocation_providers)
1.437 +
1.438 + return self.references_or_var(providers)
1.439 +
1.440 + def convert_accessors_to_providers(self, refs):
1.441 +
1.442 + "Convert accessor 'refs' to provider references."
1.443 +
1.444 + providers = set()
1.445 + for ref in refs:
1.446 if ref.has_kind("<instance>"):
1.447 providers.add(Reference("<class>", ref.get_origin()))
1.448 providers.add(ref)
1.449 -
1.450 return providers
1.451
1.452 def convert_invocation_provider(self, ref):
1.453 @@ -1891,11 +2004,11 @@
1.454
1.455 if ref:
1.456 if ref.has_kind("<class>"):
1.457 - return ref
1.458 + return [ref]
1.459 elif ref.has_kind("<function>"):
1.460 return self.convert_function_invocation(ref)
1.461
1.462 - return Reference("<var>")
1.463 + return [Reference("<var>")]
1.464
1.465 def convert_invocations(self, refs, invocation):
1.466
1.467 @@ -1904,7 +2017,15 @@
1.468 value.
1.469 """
1.470
1.471 - return invocation and map(self.convert_invocation, refs) or refs
1.472 + if not invocation:
1.473 + return refs
1.474 +
1.475 + invocation_refs = set()
1.476 +
1.477 + for ref in refs:
1.478 + invocation_refs.update(self.convert_invocation(ref))
1.479 +
1.480 + return self.references_or_var(invocation_refs)
1.481
1.482 def convert_invocation(self, ref):
1.483
1.484 @@ -1912,23 +2033,32 @@
1.485
1.486 if ref:
1.487 if ref.has_kind("<class>"):
1.488 - return ref.instance_of()
1.489 + return [ref.instance_of()]
1.490 elif ref.has_kind("<function>"):
1.491 return self.convert_function_invocation(ref)
1.492
1.493 - return Reference("<var>")
1.494 + return [Reference("<var>")]
1.495
1.496 def convert_function_invocation(self, ref):
1.497
1.498 "Convert the function 'ref' to its return value reference."
1.499
1.500 - initialised_names = self.importer.all_initialised_names.get((ref.get_origin(), "$return"))
1.501 - if initialised_names:
1.502 - refs = set(initialised_names.values())
1.503 - if len(refs) == 1:
1.504 - return first(refs)
1.505 -
1.506 - return Reference("<var>")
1.507 + initialisers = self.importer.all_initialised_names.get((ref.get_origin(), "$return"))
1.508 + aliases = self.importer.all_aliased_names.get((ref.get_origin(), "$return"))
1.509 +
1.510 + if initialisers and not aliases:
1.511 + return set(initialisers.values())
1.512 +
1.513 + return [Reference("<var>")]
1.514 +
1.515 + def references_or_var(self, refs):
1.516 +
1.517 + var = Reference("<var>")
1.518 +
1.519 + if var in refs:
1.520 + return set([var])
1.521 + else:
1.522 + return refs
1.523
1.524 def get_initialised_name(self, access_location):
1.525
1.526 @@ -1941,9 +2071,39 @@
1.527
1.528 # Use initialiser information, if available.
1.529
1.530 - refs = self.importer.all_initialised_names.get((path, name))
1.531 - if refs and refs.has_key(version):
1.532 - return refs[version]
1.533 + initialisers = self.importer.all_initialised_names.get((path, name))
1.534 + if initialisers and initialisers.has_key(version):
1.535 + return [initialisers[version]]
1.536 + else:
1.537 + return None
1.538 +
1.539 + def get_accessor_references(self, access_location):
1.540 +
1.541 + """
1.542 + Return references corresponding to accessor details at the given
1.543 + 'access_location'.
1.544 + """
1.545 +
1.546 + if self.accessor_class_types.has_key(access_location):
1.547 + class_types = self.accessor_class_types[access_location]
1.548 + instance_types = self.accessor_instance_types[access_location]
1.549 + module_types = self.accessor_module_types[access_location]
1.550 + return combine_types(class_types, instance_types, module_types)
1.551 + else:
1.552 + return None
1.553 +
1.554 + def get_provider_references(self, access_location):
1.555 +
1.556 + """
1.557 + Return references corresponding to provider details at the given
1.558 + 'access_location'.
1.559 + """
1.560 +
1.561 + if self.provider_class_types.has_key(access_location):
1.562 + class_types = self.provider_class_types[access_location]
1.563 + instance_types = self.provider_instance_types[access_location]
1.564 + module_types = self.provider_module_types[access_location]
1.565 + return combine_types(class_types, instance_types, module_types)
1.566 else:
1.567 return None
1.568
4.1 --- a/modules.py Thu Mar 16 18:13:34 2017 +0100
4.2 +++ b/modules.py Sun Mar 19 00:56:43 2017 +0100
4.3 @@ -71,10 +71,6 @@
4.4
4.5 self.exception_namespaces = set()
4.6
4.7 - # Return value details.
4.8 -
4.9 - self.return_values = {}
4.10 -
4.11 # Attribute usage at module and function levels.
4.12
4.13 self.attr_usage = {}
4.14 @@ -102,6 +98,10 @@
4.15 self.initialised_names = {}
4.16 self.aliased_names = {}
4.17
4.18 + # Return values for functions in this module.
4.19 +
4.20 + self.return_values = {}
4.21 +
4.22 def __repr__(self):
4.23 return "BasicModule(%r, %r)" % (self.name, self.importer)
4.24
4.25 @@ -496,7 +496,9 @@
4.26 init_item(self.aliased_names, (path, name), dict)
4.27 if number == "{}": number = None
4.28 else: number = int(number)
4.29 - self.aliased_names[(path, name)][int(version)] = (original_path, original_name, attrnames != "{}" and attrnames or None, number)
4.30 + d = self.aliased_names[(path, name)]
4.31 + init_item(d, int(version), list)
4.32 + d[int(version)].append((original_path, original_name, attrnames != "{}" and attrnames or None, number))
4.33 line = f.readline().rstrip()
4.34
4.35 def _get_function_parameters(self, f):
4.36 @@ -763,9 +765,10 @@
4.37 for (path, name), aliases in assignments:
4.38 versions = aliases.items()
4.39 versions.sort()
4.40 - for version, alias in versions:
4.41 - original_path, original_name, attrnames, number = alias
4.42 - print >>f, path, name, version, original_path, original_name, attrnames or "{}", number is None and "{}" or number
4.43 + for version, version_aliases in versions:
4.44 + for alias in version_aliases:
4.45 + original_path, original_name, attrnames, number = alias
4.46 + print >>f, path, name, version, original_path, original_name, attrnames or "{}", number is None and "{}" or number
4.47
4.48 print >>f
4.49 print >>f, "function parameters:"
5.1 --- a/resolving.py Thu Mar 16 18:13:34 2017 +0100
5.2 +++ b/resolving.py Sun Mar 19 00:56:43 2017 +0100
5.3 @@ -244,11 +244,11 @@
5.4 aliased_names = {}
5.5
5.6 for i, name_ref in enumerate(values):
5.7 - initialised_ref, aliased_name = self.resolve_reference(path, name_ref)
5.8 + initialised_ref, _aliased_names = self.resolve_reference(path, name_ref)
5.9 if initialised_ref:
5.10 initialised_names[i] = initialised_ref
5.11 - if aliased_name:
5.12 - aliased_names[i] = aliased_name
5.13 + if _aliased_names:
5.14 + aliased_names[i] = _aliased_names
5.15
5.16 if initialised_names:
5.17 self.initialised_names[(path, name)] = initialised_names
5.18 @@ -269,11 +269,11 @@
5.19 aliased_names = {}
5.20
5.21 for i, name_ref in enumerate(values):
5.22 - initialised_ref, aliased_name = self.resolve_reference(path, name_ref)
5.23 + initialised_ref, _aliased_names = self.resolve_reference(path, name_ref)
5.24 if initialised_ref:
5.25 initialised_names[i] = initialised_ref
5.26 - if aliased_name:
5.27 - aliased_names[i] = aliased_name
5.28 + if _aliased_names:
5.29 + aliased_names[i] = _aliased_names
5.30
5.31 if initialised_names:
5.32 self.initialised_names[(path, "$return")] = initialised_names
5.33 @@ -290,7 +290,7 @@
5.34 const_accesses = self.const_accesses.get(path)
5.35
5.36 initialised_ref = None
5.37 - aliased_name = None
5.38 + aliased_names = None
5.39 no_reference = None, None
5.40
5.41 # Unwrap invocations.
5.42 @@ -336,9 +336,9 @@
5.43 # alongside original name, attribute and access
5.44 # number details.
5.45
5.46 - aliased_name = path, name_ref.original_name, name_ref.attrnames, name_ref.number
5.47 + aliased_names = [(path, name_ref.original_name, name_ref.attrnames, name_ref.number)]
5.48
5.49 - return None, aliased_name
5.50 + return None, aliased_names
5.51
5.52 # Attempt to resolve a plain name reference.
5.53
5.54 @@ -355,9 +355,9 @@
5.55 # alongside original name, attribute and access
5.56 # number details.
5.57
5.58 - aliased_name = path, name_ref.name, None, name_ref.number
5.59 + aliased_names = [(path, name_ref.name, None, name_ref.number)]
5.60
5.61 - return None, aliased_name
5.62 + return None, aliased_names
5.63
5.64 ref = self.get_resolved_object(ref.get_origin())
5.65 if not ref:
5.66 @@ -382,13 +382,32 @@
5.67
5.68 # Convert class invocations to instances.
5.69
5.70 - if ref and invocation or ref.has_kind("<invoke>"):
5.71 - ref = self.convert_invocation(ref)
5.72 + if ref and (invocation or ref.has_kind("<invoke>")):
5.73 + target_ref = ref
5.74 + ref = self.convert_invocation(target_ref)
5.75 +
5.76 + if not ref or ref.has_kind("<var>"):
5.77 + aliased_names = self.get_aliases_for_target(target_ref.get_origin())
5.78 + else:
5.79 + initialised_ref = ref
5.80
5.81 - if ref and not ref.has_kind("<var>"):
5.82 + elif ref and not ref.has_kind("<var>"):
5.83 initialised_ref = ref
5.84 +
5.85 + return initialised_ref, aliased_names
5.86
5.87 - return initialised_ref, aliased_name
5.88 + def get_aliases_for_target(self, path):
5.89 +
5.90 + "Return a list of return value locations for the given 'path'."
5.91 +
5.92 + return_values = self.importer.all_return_values.get(path)
5.93 + locations = []
5.94 +
5.95 + if return_values:
5.96 + for version in range(0, len(return_values)):
5.97 + locations.append((path, "$return", None, version))
5.98 +
5.99 + return locations
5.100
5.101 def resolve_literals(self):
5.102