Track variables marked as global in static analysis. This is needed in an upcoming CL.

PiperOrigin-RevId: 288736389
Change-Id: I2c8854d301adeb45e1ca7422b00c455f60d8f7cc
This commit is contained in:
Dan Moldovan 2020-01-08 11:15:45 -08:00 committed by TensorFlower Gardener
parent 4e8a6a0324
commit 43e41f42dd
2 changed files with 15 additions and 8 deletions

View File

@ -63,20 +63,18 @@ class Scope(object):
bound: Set[qual_names.QN], names that are bound to this scope. See
https://docs.python.org/3/reference/executionmodel.html#binding-of-names
for a precise definition.
free: Set[qual_names.QN], names that are free variables in the context of
this scpe. This property only matches Python's notion of free variables
for isolated scopes. For example, the scope tracking the body of an if
statement will count a variable that it used but not bound as free,
even if it's actually bound elsewhere in the enclosing function.
globals: Set[qual_names.QN], names that are explicitly marked as global in
this scope. Note that this doesn't include free read-only vars bound to
global symbols.
free_vars: Set[qual_names.QN], the free variables in this scope. See
https://docs.python.org/3/reference/executionmodel.html for a precise
definition.
params: WeakValueDictionary[qual_names.QN, ast.Node], function arguments
visible in this scope, mapped to the function node that defines them.
enclosing_scope: Scope, the innermost isolated scope that is a transitive
parent of this scope. May be the scope itself.
referenced: Set[qual_names.QN], the totality of the symbols used by this
scope and its parents.
free_vars: Set[qual_names.QN], the free variables in this scope. See
https://docs.python.org/3/reference/executionmodel.html for a precise
definition.
is_final: bool, whether the scope is frozen or not.
Note - simple statements may never delete and modify a symbol at the same
@ -106,6 +104,7 @@ class Scope(object):
self.deleted = set()
self.bound = set()
self.globals = set()
self.params = weakref.WeakValueDictionary()
@ -174,6 +173,7 @@ class Scope(object):
self.parent.read.update(self.read)
self.parent.modified.update(self.modified)
self.parent.bound.update(self.bound)
self.parent.globals.update(self.globals)
else:
# TODO(mdan): This is not accurate.
self.parent.read.update(self.read - self.bound)
@ -305,6 +305,11 @@ class ActivityAnalyzer(transformer.Base):
self._exit_and_record_scope(node)
return node
def visit_Global(self, node):
for name in node.names:
self.scope.globals.add(qual_names.QN(name))
return node
def visit_Expr(self, node):
return self._process_statement(node)

View File

@ -541,6 +541,8 @@ class ActivityAnalyzerTest(ActivityAnalyzerTestBase):
fn_node = node
body_scope = anno.getanno(fn_node, NodeAnno.BODY_SCOPE)
self.assertScopeIs(body_scope, ('global_b', 'c'), ('global_a',))
self.assertSetEqual(body_scope.globals, set(
(QN('global_a'), QN('global_b'))))
def test_class_definition_basic(self):