1.1 --- a/branching.py Fri Oct 07 21:36:08 2016 +0200
1.2 +++ b/branching.py Sat Oct 08 00:33:32 2016 +0200
1.3 @@ -77,14 +77,15 @@
1.4 else:
1.5 return [b for b in self.get_all_suppliers(name) if name in b.assignments]
1.6
1.7 - def set_usage(self, name, attrname):
1.8 + def set_usage(self, name, attrname, invocation=False):
1.9
1.10 """
1.11 - Record usage on the given 'name' of the attribute 'attrname'.
1.12 + Record usage on the given 'name' of the attribute 'attrname', noting the
1.13 + invocation of the attribute if 'invocation' is set to a true value.
1.14 """
1.15
1.16 if self.usage.has_key(name):
1.17 - self.usage[name].add(attrname)
1.18 + self.usage[name].add((attrname, invocation))
1.19
1.20 def get_usage(self):
1.21
1.22 @@ -482,11 +483,12 @@
1.23
1.24 return branch
1.25
1.26 - def use_attribute(self, name, attrname):
1.27 + def use_attribute(self, name, attrname, invocation=False):
1.28
1.29 """
1.30 Indicate the use on the given 'name' of an attribute with the given
1.31 - 'attrname'.
1.32 + 'attrname', optionally involving an invocation of the attribute if
1.33 + 'invocation' is set to a true value.
1.34
1.35 Return all branches that support 'name'.
1.36 """
1.37 @@ -497,7 +499,7 @@
1.38
1.39 if branches.has_key(name):
1.40 for branch in branches[name]:
1.41 - branch.set_usage(name, attrname)
1.42 + branch.set_usage(name, attrname, invocation)
1.43 return branches[name]
1.44 else:
1.45 return None
2.1 --- a/deducer.py Fri Oct 07 21:36:08 2016 +0200
2.2 +++ b/deducer.py Sat Oct 08 00:33:32 2016 +0200
2.3 @@ -20,7 +20,7 @@
2.4 """
2.5
2.6 from common import first, get_attrname_from_location, get_attrnames, \
2.7 - get_name_path, init_item, make_key, sorted_output, \
2.8 + get_name_path, init_item, sorted_output, \
2.9 CommonOutput
2.10 from encoders import encode_attrnames, encode_access_location, \
2.11 encode_constrained, encode_location, encode_usage, \
2.12 @@ -699,7 +699,7 @@
2.13 for attrnames in all_attrnames:
2.14 attrname = get_attrnames(attrnames)[-1]
2.15 access_location = (location, None, attrnames, 0)
2.16 - self.add_usage_term(access_location, [attrname])
2.17 + self.add_usage_term(access_location, ((attrname, False),))
2.18
2.19 def add_usage(self, assignments, path):
2.20
2.21 @@ -713,21 +713,19 @@
2.22 for i, usages in enumerate(versions):
2.23 location = (path, name, None, i)
2.24
2.25 - for attrnames in usages:
2.26 - self.add_usage_term(location, attrnames)
2.27 -
2.28 - def add_usage_term(self, location, attrnames):
2.29 + for usage in usages:
2.30 + self.add_usage_term(location, usage)
2.31 +
2.32 + def add_usage_term(self, location, usage):
2.33
2.34 """
2.35 - For 'location' and using 'attrnames' as a description of usage, record
2.36 + For 'location' and using 'usage' as a description of usage, record
2.37 in the usage index a mapping from the usage to 'location', and record in
2.38 the location index a mapping from 'location' to the usage.
2.39 """
2.40
2.41 - key = make_key(attrnames)
2.42 -
2.43 init_item(self.location_index, location, set)
2.44 - self.location_index[location].add(key)
2.45 + self.location_index[location].add(usage)
2.46
2.47 def init_accessors(self):
2.48
2.49 @@ -803,11 +801,9 @@
2.50
2.51 for location in accessor_locations:
2.52 for usage in self.location_index[location]:
2.53 - key = make_key(usage)
2.54 -
2.55 if assignment:
2.56 - init_item(self.assigned_attrs, key, set)
2.57 - self.assigned_attrs[key].add((path, name, attrnames))
2.58 + init_item(self.assigned_attrs, usage, set)
2.59 + self.assigned_attrs[usage].add((path, name, attrnames))
2.60
2.61 def init_aliases(self):
2.62
2.63 @@ -1010,31 +1006,31 @@
2.64 init_item(attr_types, attrname, set)
2.65 attr_types[attrname].add(name)
2.66
2.67 - def get_class_types_for_usage(self, attrnames):
2.68 -
2.69 - "Return names of classes supporting the given 'attrnames'."
2.70 -
2.71 - return self._get_types_for_usage(attrnames, self.attr_class_types, self.importer.all_class_attrs)
2.72 -
2.73 - def get_instance_types_for_usage(self, attrnames):
2.74 + def get_class_types_for_usage(self, usage):
2.75 +
2.76 + "Return names of classes supporting the given 'usage'."
2.77 +
2.78 + return self._get_types_for_usage(usage, self.attr_class_types, self.importer.all_class_attrs)
2.79 +
2.80 + def get_instance_types_for_usage(self, usage):
2.81
2.82 """
2.83 - Return names of classes whose instances support the given 'attrnames'
2.84 + Return names of classes whose instances support the given 'usage'
2.85 (as either class or instance attributes).
2.86 """
2.87
2.88 - return self._get_types_for_usage(attrnames, self.attr_instance_types, self.importer.all_combined_attrs)
2.89 -
2.90 - def get_module_types_for_usage(self, attrnames):
2.91 -
2.92 - "Return names of modules supporting the given 'attrnames'."
2.93 -
2.94 - return self._get_types_for_usage(attrnames, self.attr_module_types, self.importer.all_module_attrs)
2.95 -
2.96 - def _get_types_for_usage(self, attrnames, attr_types, attrs):
2.97 + return self._get_types_for_usage(usage, self.attr_instance_types, self.importer.all_combined_attrs)
2.98 +
2.99 + def get_module_types_for_usage(self, usage):
2.100 +
2.101 + "Return names of modules supporting the given 'usage'."
2.102 +
2.103 + return self._get_types_for_usage(usage, self.attr_module_types, self.importer.all_module_attrs)
2.104 +
2.105 + def _get_types_for_usage(self, usage, attr_types, attrs):
2.106
2.107 """
2.108 - For the given 'attrnames' representing attribute usage, return types
2.109 + For the given 'usage' representing attribute usage, return types
2.110 recorded in the 'attr_types' attribute-to-types mapping that support
2.111 such usage, with the given 'attrs' type-to-attributes mapping used to
2.112 quickly assess whether a type supports all of the stated attributes.
2.113 @@ -1042,9 +1038,13 @@
2.114
2.115 # Where no attributes are used, any type would be acceptable.
2.116
2.117 - if not attrnames:
2.118 + if not usage:
2.119 return attrs.keys()
2.120
2.121 + attrnames = []
2.122 + for attrname, invocation in usage:
2.123 + attrnames.append(attrname)
2.124 +
2.125 types = []
2.126
2.127 # Obtain types supporting the first attribute name...
2.128 @@ -1389,7 +1389,7 @@
2.129
2.130 else:
2.131 self.init_definition_details(location)
2.132 - self.record_types_for_usage(location, [attrname])
2.133 + self.record_types_for_usage(location, [(attrname, False)])
2.134
2.135 constrained = location in self.accessor_constrained and constrained
2.136
2.137 @@ -1418,7 +1418,7 @@
2.138 'attrname' for type deduction.
2.139 """
2.140
2.141 - usage = [attrname]
2.142 + usage = ((attrname, False),)
2.143
2.144 class_types = self.get_class_types_for_usage(usage)
2.145 only_instance_types = set(self.get_instance_types_for_usage(usage)).difference(class_types)
4.1 --- a/inspector.py Fri Oct 07 21:36:08 2016 +0200
4.2 +++ b/inspector.py Sat Oct 08 00:33:32 2016 +0200
4.3 @@ -43,6 +43,7 @@
4.4
4.5 self.in_class = False
4.6 self.in_conditional = False
4.7 + self.in_invocation = False
4.8 self.global_attr_accesses = {}
4.9
4.10 # Usage tracking.
4.11 @@ -363,7 +364,11 @@
4.12
4.13 # Obtain any completed chain and return the reference to it.
4.14
4.15 + in_invocation = self.in_invocation
4.16 + self.in_invocation = False
4.17 name_ref = self.process_attribute_chain(n)
4.18 + self.in_invocation = in_invocation
4.19 +
4.20 if self.have_access_expression(n):
4.21 return name_ref
4.22
4.23 @@ -440,7 +445,7 @@
4.24 # Record attribute usage in the tracker, and record the branch
4.25 # information for the access.
4.26
4.27 - branches = tracker.use_attribute(name, attrname)
4.28 + branches = tracker.use_attribute(name, attrname, self.in_invocation)
4.29
4.30 if not branches:
4.31 raise InspectError("Name %s is accessed using %s before an assignment." % (
4.32 @@ -707,7 +712,10 @@
4.33 try:
4.34 # Process the expression, obtaining any identified reference.
4.35
4.36 + in_invocation = self.in_invocation
4.37 + self.in_invocation = True
4.38 name_ref = self.process_structure_node(n.node)
4.39 + self.in_invocation = in_invocation
4.40
4.41 # Process the arguments.
4.42
5.1 --- a/modules.py Fri Oct 07 21:36:08 2016 +0200
5.2 +++ b/modules.py Sat Oct 08 00:33:32 2016 +0200
5.3 @@ -21,7 +21,7 @@
5.4 """
5.5
5.6 from common import init_item, remove_items, CommonModule
5.7 -from encoders import decode_modifier_term, encode_modifiers, encode_usage
5.8 +from encoders import decode_modifier_term, decode_usage, encode_modifiers, encode_usage
5.9 from referencing import decode_reference, Reference
5.10 from results import ResolvedNameRef
5.11 import sys
5.12 @@ -636,16 +636,8 @@
5.13 if attrnames == "{}":
5.14 all_attrnames = ()
5.15 else:
5.16 - # Decode attribute details for each usage description.
5.17 -
5.18 - all_attrnames = set()
5.19 - for attrname_str in attrnames.split(", "):
5.20 - all_attrnames.add(attrname_str)
5.21 -
5.22 - all_attrnames = list(all_attrnames)
5.23 - all_attrnames.sort()
5.24 -
5.25 - all_usages.add(tuple(all_attrnames))
5.26 + all_attrnames = decode_usage(attrnames)
5.27 + all_usages.add(all_attrnames)
5.28
5.29 d.append(all_usages)
5.30