1.1 --- a/common.py Wed Oct 19 16:37:01 2016 +0200
1.2 +++ b/common.py Wed Oct 19 21:05:24 2016 +0200
1.3 @@ -559,7 +559,7 @@
1.4 # Break attribute chains where non-access nodes are found.
1.5
1.6 if not self.have_access_expression(n):
1.7 - self.attrs = []
1.8 + self.reset_attribute_chain()
1.9
1.10 # Descend into the expression, extending backwards any existing chain,
1.11 # or building another for the expression.
1.12 @@ -568,7 +568,8 @@
1.13
1.14 # Restore chain information applying to this node.
1.15
1.16 - self.attrs = attrs
1.17 + if not self.have_access_expression(n):
1.18 + self.restore_attribute_chain(attrs)
1.19
1.20 # Return immediately if the expression was another access and thus a
1.21 # continuation backwards along the chain. The above processing will
1.22 @@ -579,6 +580,18 @@
1.23
1.24 return name_ref
1.25
1.26 + def reset_attribute_chain(self):
1.27 +
1.28 + "Reset the attribute chain for a subexpression of an attribute access."
1.29 +
1.30 + self.attrs = []
1.31 +
1.32 + def restore_attribute_chain(self, attrs):
1.33 +
1.34 + "Restore the attribute chain for an attribute access."
1.35 +
1.36 + self.attrs = attrs
1.37 +
1.38 def have_access_expression(self, node):
1.39
1.40 "Return whether the expression associated with 'node' is Getattr."
2.1 --- a/inspector.py Wed Oct 19 16:37:01 2016 +0200
2.2 +++ b/inspector.py Wed Oct 19 21:05:24 2016 +0200
2.3 @@ -21,7 +21,7 @@
2.4 """
2.5
2.6 from branching import BranchTracker
2.7 -from common import get_argnames, init_item, predefined_constants
2.8 +from common import CommonModule, get_argnames, init_item, predefined_constants
2.9 from modules import BasicModule, CacheWritingModule, InspectionNaming
2.10 from errors import InspectError
2.11 from referencing import Reference
2.12 @@ -45,6 +45,14 @@
2.13 self.in_class = False
2.14 self.in_conditional = False
2.15 self.in_invocation = False
2.16 +
2.17 + # Attribute chain state management.
2.18 +
2.19 + self.chain_assignment = []
2.20 + self.chain_invocation = []
2.21 +
2.22 + # Accesses to global attributes.
2.23 +
2.24 self.global_attr_accesses = {}
2.25
2.26 # Usage tracking.
2.27 @@ -367,20 +375,10 @@
2.28
2.29 "Process the given attribute access node 'n'."
2.30
2.31 - # Parts of the attribute chain are neither invoked nor assigned.
2.32 -
2.33 - in_invocation = self.in_invocation
2.34 - self.in_invocation = False
2.35 - in_assignment = self.in_assignment
2.36 - self.in_assignment = False
2.37 -
2.38 # Obtain any completed chain and return the reference to it.
2.39
2.40 name_ref = self.process_attribute_chain(n)
2.41
2.42 - self.in_invocation = in_invocation
2.43 - self.in_assignment = in_assignment
2.44 -
2.45 if self.have_access_expression(n):
2.46 return name_ref
2.47
2.48 @@ -455,15 +453,14 @@
2.49 # Record attribute usage in the tracker, and record the branch
2.50 # information for the access.
2.51
2.52 - branches = tracker.use_attribute(name, attrname, self.in_invocation,
2.53 - self.in_assignment and immediate_access)
2.54 + branches = tracker.use_attribute(name, attrname, self.in_invocation, assignment)
2.55
2.56 if not branches:
2.57 raise InspectError("Name %s is accessed using %s before an assignment." % (
2.58 name, attrname), path, n)
2.59
2.60 self.record_branches_for_access(branches, name, attrnames)
2.61 - access_number = self.record_access_details(name, attrnames, assignment)
2.62 + access_number = self.record_access_details(name, attrnames, self.in_assignment)
2.63
2.64 del self.attrs[0]
2.65 return AccessRef(name, attrnames, access_number)
2.66 @@ -992,6 +989,26 @@
2.67
2.68 tracker.resume_broken_branches()
2.69
2.70 + # Attribute chain handling.
2.71 +
2.72 + def reset_attribute_chain(self):
2.73 +
2.74 + "Reset the attribute chain for a subexpression of an attribute access."
2.75 +
2.76 + CommonModule.reset_attribute_chain(self)
2.77 + self.chain_assignment.append(self.in_assignment)
2.78 + self.chain_invocation.append(self.in_invocation)
2.79 + self.in_assignment = False
2.80 + self.in_invocation = False
2.81 +
2.82 + def restore_attribute_chain(self, attrs):
2.83 +
2.84 + "Restore the attribute chain for an attribute access."
2.85 +
2.86 + CommonModule.restore_attribute_chain(self, attrs)
2.87 + self.in_assignment = self.chain_assignment.pop()
2.88 + self.in_invocation = self.chain_invocation.pop()
2.89 +
2.90 # Branch tracking methods.
2.91
2.92 def start_tracking(self, names):