1.1 --- a/common.py Sun Feb 19 17:56:06 2017 +0100
1.2 +++ b/common.py Mon Feb 20 00:35:08 2017 +0100
1.3 @@ -741,14 +741,17 @@
1.4
1.5 return isinstance(node.expr, compiler.ast.Getattr)
1.6
1.7 - def get_name_for_tracking(self, name, ref=None):
1.8 + def get_name_for_tracking(self, name, name_ref=None):
1.9
1.10 """
1.11 Return the name to be used for attribute usage observations involving
1.12 - the given 'name' in the current namespace. If 'ref' is indicated and
1.13 - the name is being used outside a function, return the origin information
1.14 - from 'ref'; otherwise, return a path computed using the current
1.15 - namespace and the given name.
1.16 + the given 'name' in the current namespace.
1.17 +
1.18 + If the name is being used outside a function, and if 'name_ref' is
1.19 + given, a path featuring the name in the global namespace is returned
1.20 + where 'name_ref' indicates a global, or a static reference is used if
1.21 + 'name_ref' provides such a reference. Otherwise, a path computed using
1.22 + the current namespace and the given name is returned.
1.23
1.24 The intention of this method is to provide a suitably-qualified name
1.25 that can be tracked across namespaces. Where globals are being
1.26 @@ -766,15 +769,15 @@
1.27 if self.in_function:
1.28 return name
1.29
1.30 - # For static namespaces, use the given qualified name.
1.31 + # For static references, use the reference origin.
1.32
1.33 - elif ref and ref.static():
1.34 - return ref.get_origin()
1.35 + elif name_ref and name_ref.final():
1.36 + return name_ref.final()
1.37
1.38 - # For non-static objects in static namespaces, use any alias.
1.39 + # For global names outside functions, use a global name.
1.40
1.41 - elif ref and ref.get_name():
1.42 - return ref.get_name()
1.43 + elif name_ref and name_ref.is_global_name():
1.44 + return self.get_global_path(name)
1.45
1.46 # Otherwise, establish a name in the current namespace.
1.47
2.1 --- a/inspector.py Sun Feb 19 17:56:06 2017 +0100
2.2 +++ b/inspector.py Mon Feb 20 00:35:08 2017 +0100
2.3 @@ -412,7 +412,7 @@
2.4 # if assigned in the namespace, or using an external name
2.5 # (presently just globals within classes).
2.6
2.7 - name = self.get_name_for_tracking(name_ref.name, name_ref.reference())
2.8 + name = self.get_name_for_tracking(name_ref.name, name_ref)
2.9 tracker = self.trackers[-1]
2.10
2.11 immediate_access = len(self.attrs) == 1
2.12 @@ -420,10 +420,7 @@
2.13
2.14 # Record global-based chains for subsequent resolution.
2.15
2.16 - is_global = self.in_function and not self.function_locals[path].has_key(name) or \
2.17 - not self.in_function
2.18 -
2.19 - if is_global:
2.20 + if name_ref.is_global_name():
2.21 self.record_global_access_details(name, attrnames)
2.22
2.23 # Make sure the name is being tracked: global names will not
2.24 @@ -873,12 +870,12 @@
2.25
2.26 ref = self.find_name(n.name)
2.27 if ref:
2.28 - return ResolvedNameRef(n.name, ref)
2.29 + return ResolvedNameRef(n.name, ref, is_global=True)
2.30
2.31 # Explicitly-declared global names.
2.32
2.33 elif self.in_function and n.name in self.scope_globals[path]:
2.34 - return NameRef(n.name)
2.35 + return NameRef(n.name, is_global=True)
2.36
2.37 # Examine other names.
2.38
2.39 @@ -899,7 +896,7 @@
2.40 # Possible global or built-in name.
2.41
2.42 else:
2.43 - return NameRef(n.name)
2.44 + return NameRef(n.name, is_global=True)
2.45
2.46 def process_operator_chain(self, nodes, fn):
2.47
3.1 --- a/results.py Sun Feb 19 17:56:06 2017 +0100
3.2 +++ b/results.py Mon Feb 20 00:35:08 2017 +0100
3.3 @@ -30,6 +30,9 @@
3.4 def is_name(self):
3.5 return False
3.6
3.7 + def is_global_name(self):
3.8 + return False
3.9 +
3.10 def reference(self):
3.11 return None
3.12
3.13 @@ -90,25 +93,29 @@
3.14
3.15 "A reference to a name."
3.16
3.17 - def __init__(self, name, expr=None):
3.18 + def __init__(self, name, expr=None, is_global=False):
3.19 self.name = name
3.20 self.expr = expr
3.21 + self.is_global = is_global
3.22
3.23 def is_name(self):
3.24 return True
3.25
3.26 + def is_global_name(self):
3.27 + return self.is_global
3.28 +
3.29 def final(self):
3.30 return None
3.31
3.32 def __repr__(self):
3.33 - return "NameRef(%r, %r)" % (self.name, self.expr)
3.34 + return "NameRef(%r, %r, %r)" % (self.name, self.expr, self.is_global)
3.35
3.36 class LocalNameRef(NameRef):
3.37
3.38 "A reference to a local name."
3.39
3.40 def __init__(self, name, number):
3.41 - NameRef.__init__(self, name)
3.42 + NameRef.__init__(self, name, is_global=False)
3.43 self.number = number
3.44
3.45 def __repr__(self):
3.46 @@ -149,12 +156,12 @@
3.47
3.48 "A resolved name-based reference."
3.49
3.50 - def __init__(self, name, ref, expr=None):
3.51 - NameRef.__init__(self, name, expr)
3.52 + def __init__(self, name, ref, expr=None, is_global=False):
3.53 + NameRef.__init__(self, name, expr, is_global)
3.54 ResolvedRef.__init__(self, ref)
3.55
3.56 def __repr__(self):
3.57 - return "ResolvedNameRef(%r, %r, %r)" % (self.name, self.ref, self.expr)
3.58 + return "ResolvedNameRef(%r, %r, %r, %r)" % (self.name, self.ref, self.expr, self.is_global)
3.59
3.60 class ConstantValueRef(ResolvedNameRef):
3.61
4.1 --- a/translator.py Sun Feb 19 17:56:06 2017 +0100
4.2 +++ b/translator.py Mon Feb 20 00:35:08 2017 +0100
4.3 @@ -91,8 +91,8 @@
4.4
4.5 "A reference to a name in the translation."
4.6
4.7 - def __init__(self, name, ref, expr=None, parameter=None, location=None):
4.8 - results.ResolvedNameRef.__init__(self, name, ref, expr)
4.9 + def __init__(self, name, ref, expr=None, is_global=False, parameter=None, location=None):
4.10 + results.ResolvedNameRef.__init__(self, name, ref, expr, is_global)
4.11 self.parameter = parameter
4.12 self.location = location
4.13
4.14 @@ -726,7 +726,7 @@
4.15 # the complete access.
4.16
4.17 name_ref = attr_expr and attr_expr.is_name() and attr_expr
4.18 - name = name_ref and self.get_name_for_tracking(name_ref.name, name_ref and name_ref.reference()) or None
4.19 + name = name_ref and self.get_name_for_tracking(name_ref.name, name_ref) or None
4.20
4.21 location = self.get_access_location(name, self.attrs)
4.22 refs = self.get_referenced_attributes(location)
4.23 @@ -1490,8 +1490,23 @@
4.24 # Determine any assigned globals.
4.25
4.26 globals = self.importer.get_module(self.name).scope_globals.get(path)
4.27 +
4.28 + # Explicitly declared globals.
4.29 +
4.30 if globals and n.name in globals:
4.31 objpath = self.get_global_path(n.name)
4.32 + is_global = True
4.33 +
4.34 + # Implicitly referenced globals in functions.
4.35 +
4.36 + elif self.in_function:
4.37 + is_global = n.name not in self.importer.function_locals[path]
4.38 +
4.39 + # Implicitly referenced globals elsewhere.
4.40 +
4.41 + else:
4.42 + namespace = self.importer.identify(path)
4.43 + is_global = not self.importer.get_attributes(namespace, n.name)
4.44
4.45 # Get the static identity of the name.
4.46
4.47 @@ -1520,7 +1535,7 @@
4.48 # static namespace members. The reference should be configured to return
4.49 # such names.
4.50
4.51 - return TrResolvedNameRef(n.name, ref, expr=expr, parameter=parameter, location=location)
4.52 + return TrResolvedNameRef(n.name, ref, expr=expr, is_global=is_global, parameter=parameter, location=location)
4.53
4.54 def process_not_node(self, n):
4.55