Lichen

inspector.py

80:589c3a257c01
2016-10-06 Paul Boddie Prevent parts of attribute expressions from being associated with invocations.
     1 #!/usr/bin/env python     2      3 """     4 Inspect and obtain module structure.     5      6 Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013,     7               2014, 2015, 2016 Paul Boddie <paul@boddie.org.uk>     8      9 This program is free software; you can redistribute it and/or modify it under    10 the terms of the GNU General Public License as published by the Free Software    11 Foundation; either version 3 of the License, or (at your option) any later    12 version.    13     14 This program is distributed in the hope that it will be useful, but WITHOUT    15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    16 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more    17 details.    18     19 You should have received a copy of the GNU General Public License along with    20 this program.  If not, see <http://www.gnu.org/licenses/>.    21 """    22     23 from branching import BranchTracker    24 from common import get_argnames, init_item, predefined_constants    25 from modules import BasicModule, CacheWritingModule, InspectionNaming    26 from errors import InspectError    27 from referencing import Reference    28 from resolving import NameResolving    29 from results import AccessRef, InstanceRef, InvocationRef, LiteralSequenceRef, \    30                     LocalNameRef, NameRef, ResolvedNameRef    31 import compiler    32 import sys    33     34 class InspectedModule(BasicModule, CacheWritingModule, NameResolving, InspectionNaming):    35     36     "A module inspector."    37     38     def __init__(self, name, importer):    39     40         "Initialise the module with basic details."    41     42         BasicModule.__init__(self, name, importer)    43     44         self.in_class = False    45         self.in_conditional = False    46         self.in_invocation = False    47         self.global_attr_accesses = {}    48     49         # Usage tracking.    50     51         self.trackers = []    52         self.attr_accessor_branches = {}    53     54     def __repr__(self):    55         return "InspectedModule(%r, %r)" % (self.name, self.importer)    56     57     # Principal methods.    58     59     def parse(self, filename):    60     61         "Parse the file having the given 'filename'."    62     63         self.parse_file(filename)    64     65         # Inspect the module.    66     67         self.start_tracking_in_module()    68     69         # Detect and record imports and globals declared in the module.    70     71         self.assign_general_local("__name__", self.get_constant("str", self.name))    72         self.assign_general_local("__file__", self.get_constant("str", filename))    73         self.process_structure(self.astnode)    74     75         # Set the class of the module after the definition has occurred.    76     77         ref = self.get_builtin("object")    78         self.set_name("__class__", ref)    79     80         # Get module-level attribute usage details.    81     82         self.stop_tracking_in_module()    83     84         # Collect external name references.    85     86         self.collect_names()    87     88     def complete(self):    89     90         "Complete the module inspection."    91     92         # Resolve names not definitively mapped to objects.    93     94         self.resolve()    95     96         # Define the invocation requirements in each namespace.    97     98         self.set_invocation_usage()    99    100         # Propagate to the importer information needed in subsequent activities.   101    102         self.propagate()   103    104     # Accessory methods.   105    106     def collect_names(self):   107    108         "Collect the names used by each scope."   109    110         for path in self.names_used.keys():   111             self.collect_names_for_path(path)   112    113     def collect_names_for_path(self, path):   114    115         """   116         Collect the names used by the given 'path'. These are propagated to the   117         importer in advance of any dependency resolution.   118         """   119    120         names = self.names_used.get(path)   121         if not names:   122             return   123    124         in_function = self.function_locals.has_key(path)   125    126         for name in names:   127             if name in predefined_constants or in_function and name in self.function_locals[path]:   128                 continue   129    130             # Find local definitions (within dynamic namespaces).   131    132             key = "%s.%s" % (path, name)   133             ref = self.get_resolved_object(key)   134             if ref:   135                 self.set_name_reference(key, ref)   136                 continue   137    138             # Find global or known built-in definitions.   139    140             ref = self.get_resolved_global_or_builtin(name)   141             if ref:   142                 self.set_name_reference(key, ref)   143                 continue   144    145             # Find presumed built-in definitions.   146    147             ref = self.get_builtin(name)   148             self.set_name_reference(key, ref)   149    150     def set_name_reference(self, path, ref):   151    152         "Map the given name 'path' to 'ref'."   153    154         self.importer.all_name_references[path] = self.name_references[path] = ref   155    156     def get_resolved_global_or_builtin(self, name):   157    158         "Return the resolved global or built-in object with the given 'name'."   159    160         # In some circumstances, the name is neither global nor recognised by   161         # the importer. It is then assumed to be a general built-in.   162    163         return self.get_global(name) or \   164                self.importer.get_object("__builtins__.%s" % name)   165    166     # Module structure traversal.   167    168     def process_structure_node(self, n):   169    170         "Process the individual node 'n'."   171    172         # Module global detection.   173    174         if isinstance(n, compiler.ast.Global):   175             self.process_global_node(n)   176    177         # Module import declarations.   178    179         elif isinstance(n, compiler.ast.From):   180             self.process_from_node(n)   181    182         elif isinstance(n, compiler.ast.Import):   183             self.process_import_node(n)   184    185         # Nodes using operator module functions.   186    187         elif isinstance(n, compiler.ast.Operator):   188             return self.process_operator_node(n)   189    190         elif isinstance(n, compiler.ast.AugAssign):   191             self.process_augassign_node(n)   192    193         elif isinstance(n, compiler.ast.Compare):   194             return self.process_compare_node(n)   195    196         elif isinstance(n, compiler.ast.Slice):   197             return self.process_slice_node(n)   198    199         elif isinstance(n, compiler.ast.Sliceobj):   200             return self.process_sliceobj_node(n)   201    202         elif isinstance(n, compiler.ast.Subscript):   203             return self.process_subscript_node(n)   204    205         # Namespaces within modules.   206    207         elif isinstance(n, compiler.ast.Class):   208             self.process_class_node(n)   209    210         elif isinstance(n, compiler.ast.Function):   211             self.process_function_node(n, n.name)   212    213         elif isinstance(n, compiler.ast.Lambda):   214             return self.process_lambda_node(n)   215    216         # Assignments.   217    218         elif isinstance(n, compiler.ast.Assign):   219    220             # Handle each assignment node.   221    222             for node in n.nodes:   223                 self.process_assignment_node(node, n.expr)   224    225         # Assignments within non-Assign nodes.   226    227         elif isinstance(n, compiler.ast.AssName):   228             self.process_assignment_node(n, None)   229    230         elif isinstance(n, compiler.ast.AssAttr):   231             self.process_attribute_access(n)   232    233         # Accesses.   234    235         elif isinstance(n, compiler.ast.Getattr):   236             return self.process_attribute_access(n)   237    238         # Name recording for later testing.   239    240         elif isinstance(n, compiler.ast.Name):   241             return self.process_name_node(n)   242    243         # Conditional statement tracking.   244    245         elif isinstance(n, compiler.ast.For):   246             self.process_for_node(n)   247    248         elif isinstance(n, compiler.ast.While):   249             self.process_while_node(n)   250    251         elif isinstance(n, compiler.ast.If):   252             self.process_if_node(n)   253    254         elif isinstance(n, (compiler.ast.And, compiler.ast.Or)):   255             return self.process_logical_node(n)   256    257         # Exception control-flow tracking.   258    259         elif isinstance(n, compiler.ast.TryExcept):   260             self.process_try_node(n)   261    262         elif isinstance(n, compiler.ast.TryFinally):   263             self.process_try_finally_node(n)   264    265         # Control-flow modification statements.   266    267         elif isinstance(n, compiler.ast.Break):   268             self.trackers[-1].suspend_broken_branch()   269    270         elif isinstance(n, compiler.ast.Continue):   271             self.trackers[-1].suspend_continuing_branch()   272    273         elif isinstance(n, compiler.ast.Raise):   274             self.process_structure(n)   275             self.trackers[-1].abandon_branch()   276    277         elif isinstance(n, compiler.ast.Return):   278             self.process_structure(n)   279             self.trackers[-1].abandon_returning_branch()   280    281         # Invocations.   282    283         elif isinstance(n, compiler.ast.CallFunc):   284             return self.process_invocation_node(n)   285    286         # Constant usage.   287    288         elif isinstance(n, compiler.ast.Const):   289             return self.get_literal_instance(n, n.value.__class__.__name__)   290    291         elif isinstance(n, compiler.ast.Dict):   292             return self.get_literal_instance(n, "dict")   293    294         elif isinstance(n, compiler.ast.List):   295             return self.get_literal_instance(n, "list")   296    297         elif isinstance(n, compiler.ast.Tuple):   298             return self.get_literal_instance(n, "tuple")   299    300         # Unsupported nodes.   301    302         elif isinstance(n, compiler.ast.GenExpr):   303             raise InspectError("Generator expressions are not supported.", self.get_namespace_path(), n)   304    305         elif isinstance(n, compiler.ast.IfExp):   306             raise InspectError("If-else expressions are not supported.", self.get_namespace_path(), n)   307    308         elif isinstance(n, compiler.ast.ListComp):   309             raise InspectError("List comprehensions are not supported.", self.get_namespace_path(), n)   310    311         # All other nodes are processed depth-first.   312    313         else:   314             self.process_structure(n)   315    316         # By default, no expression details are returned.   317    318         return None   319    320     # Specific node handling.   321    322     def process_assignment_node(self, n, expr):   323    324         "Process the individual node 'n' to be assigned the contents of 'expr'."   325    326         # Names and attributes are assigned the entire expression.   327    328         if isinstance(n, compiler.ast.AssName):   329             if n.name == "self":   330                 raise InspectError("Redefinition of self is not allowed.", self.get_namespace_path(), n)   331    332             name_ref = expr and self.process_structure_node(expr)   333    334             # Name assignments populate either function namespaces or the   335             # general namespace hierarchy.   336    337             self.assign_general_local(n.name, name_ref)   338    339             # Record usage of the name.   340    341             self.record_name(n.name)   342    343         elif isinstance(n, compiler.ast.AssAttr):   344             if expr: self.process_structure_node(expr)   345             self.process_attribute_access(n)   346    347         # Lists and tuples are matched against the expression and their   348         # items assigned to expression items.   349    350         elif isinstance(n, (compiler.ast.AssList, compiler.ast.AssTuple)):   351             self.process_assignment_node_items(n, expr)   352    353         # Slices and subscripts are permitted within assignment nodes.   354    355         elif isinstance(n, compiler.ast.Slice):   356             self.process_slice_node(n, expr)   357    358         elif isinstance(n, compiler.ast.Subscript):   359             self.process_subscript_node(n, expr)   360    361     def process_attribute_access(self, n):   362    363         "Process the given attribute access node 'n'."   364    365         # Obtain any completed chain and return the reference to it.   366    367         in_invocation = self.in_invocation   368         self.in_invocation = False   369         name_ref = self.process_attribute_chain(n)   370         self.in_invocation = in_invocation   371    372         if self.have_access_expression(n):   373             return name_ref   374    375         # Where the start of the chain of attributes has been reached, determine   376         # the complete access.   377    378         # Given a non-access node, this chain can be handled in its entirety,   379         # either being name-based and thus an access rooted on a name, or being   380         # based on some other node and thus an anonymous access of some kind.   381    382         path = self.get_namespace_path()   383    384         # Start with the the full attribute chain.   385    386         remaining = self.attrs   387         attrnames = ".".join(remaining)   388    389         # If the accessor cannot be identified, or where attributes   390         # remain in an attribute chain, record the anonymous accesses.   391    392         if not isinstance(name_ref, NameRef): # includes ResolvedNameRef   393    394             assignment = isinstance(n, compiler.ast.AssAttr)   395    396             init_item(self.attr_accesses, path, set)   397             self.attr_accesses[path].add(attrnames)   398    399             self.record_access_details(None, attrnames, assignment)   400             del self.attrs[0]   401             return   402    403         # Name-based accesses will handle the first attribute in a   404         # chain.   405    406         else:   407             attrname = remaining[0]   408    409             # Attribute assignments are used to identify instance attributes.   410    411             if isinstance(n, compiler.ast.AssAttr) and \   412                 self.in_class and self.in_function and n.expr.name == "self":   413    414                 self.set_instance_attr(attrname)   415    416             # Record attribute usage using any name local to this namespace,   417             # if assigned in the namespace, or using an external name   418             # (presently just globals within classes).   419    420             name = self.get_name_for_tracking(name_ref.name, name_ref.final())   421             tracker = self.trackers[-1]   422    423             immediate_access = len(self.attrs) == 1   424             assignment = immediate_access and isinstance(n, compiler.ast.AssAttr)   425    426             del self.attrs[0]   427    428             # Record global-based chains for subsequent resolution.   429    430             is_global = self.in_function and not self.function_locals[path].has_key(name) or \   431                         not self.in_function   432    433             if is_global:   434                 self.record_global_access_details(name, attrnames)   435    436             # Make sure the name is being tracked: global names will not   437             # already be initialised in a branch and must be added   438             # explicitly.   439    440             if not tracker.have_name(name):   441                 tracker.assign_names([name])   442                 if self.in_function:   443                     self.scope_globals[path].add(name)   444    445             # Record attribute usage in the tracker, and record the branch   446             # information for the access.   447    448             branches = tracker.use_attribute(name, attrname)   449    450             if not branches:   451                 print >>sys.stderr, "In %s, name %s is accessed using %s before an assignment." % (   452                     path, name, attrname)   453                 branches = tracker.use_attribute(name, attrname)   454    455             self.record_branches_for_access(branches, name, attrnames)   456             access_number = self.record_access_details(name, attrnames, assignment)   457             return AccessRef(name, attrnames, access_number)   458    459     def process_class_node(self, n):   460    461         "Process the given class node 'n'."   462    463         path = self.get_namespace_path()   464    465         # To avoid notions of class "versions" where the same definition   466         # might be parameterised with different state and be referenced   467         # elsewhere (as base classes, for example), classes in functions or   468         # conditions are forbidden.   469    470         if self.in_function or self.in_conditional:   471             print >>sys.stderr, "In %s, class %s in function or conditional statement ignored." % (   472                 path, n.name)   473             return   474    475         # Resolve base classes.   476    477         bases = []   478    479         for base in n.bases:   480             base_class = self.get_class(base)   481    482             if not base_class:   483                 print >>sys.stderr, "In %s, class %s has unidentifiable base class: %s" % (   484                     path, n.name, base)   485                 return   486             else:   487                 bases.append(base_class)   488    489         # Record bases for the class and retain the class name.   490    491         class_name = self.get_object_path(n.name)   492    493         if not bases and class_name != "__builtins__.core.object":   494             ref = self.get_object("__builtins__.object")   495             bases.append(ref)   496    497         self.importer.classes[class_name] = self.classes[class_name] = bases   498         self.importer.subclasses[class_name] = set()   499         self.scope_globals[class_name] = set()   500    501         # Set the definition before entering the namespace rather than   502         # afterwards because methods may reference it. In normal Python,   503         # a class is not accessible until the definition is complete, but   504         # methods can generally reference it since upon being called the   505         # class will already exist.   506    507         self.set_definition(n.name, "<class>")   508    509         in_class = self.in_class   510         self.in_class = class_name   511         self.set_instance_attr("__class__", Reference("<class>", class_name))   512         self.enter_namespace(n.name)   513         self.set_name("__fn__") # special instantiator attribute   514         self.set_name("__args__") # special instantiator attribute   515         self.assign_general_local("__name__", self.get_constant("str", class_name))   516         self.process_structure_node(n.code)   517         self.exit_namespace()   518         self.in_class = in_class   519    520     def process_from_node(self, n):   521    522         "Process the given node 'n', importing from another module."   523    524         path = self.get_namespace_path()   525    526         module_name, names = self.get_module_name(n)   527         if module_name == self.name:   528             raise InspectError("Cannot import from the current module.", path, n)   529    530         self.queue_module(module_name)   531    532         # Attempt to obtain the referenced objects.   533    534         for name, alias in n.names:   535             if name == "*":   536                 raise InspectError("Only explicitly specified names can be imported from modules.", path, n)   537    538             # Explicit names.   539    540             ref = self.import_name_from_module(name, module_name)   541             value = ResolvedNameRef(alias or name, ref)   542             self.set_general_local(alias or name, value)   543    544     def process_function_node(self, n, name):   545    546         """   547         Process the given function or lambda node 'n' with the given 'name'.   548         """   549    550         is_lambda = isinstance(n, compiler.ast.Lambda)   551    552         # Where a function is declared conditionally, use a separate name for   553         # the definition, and assign the definition to the stated name.   554    555         if (self.in_conditional or self.in_function) and not is_lambda:   556             original_name = name   557             name = self.get_lambda_name()   558         else:   559             original_name = None   560    561         # Initialise argument and local records.   562    563         function_name = self.get_object_path(name)   564         argnames = get_argnames(n.argnames)   565         is_method = self.in_class and not self.in_function   566    567         # Remove explicit "self" from method parameters.   568    569         if is_method and argnames and argnames[0] == "self":   570             del argnames[0]   571    572         # Copy and propagate the parameters.   573    574         self.importer.function_parameters[function_name] = \   575         self.function_parameters[function_name] = argnames[:]   576    577         # Define all arguments/parameters in the local namespace.   578    579         locals = self.function_locals[function_name] = {}   580    581         # Insert "self" into method locals.   582    583         if is_method:   584             argnames.insert(0, "self")   585    586         # Define "self" in terms of the class if in a method.   587         # This does not diminish the need for type-narrowing in the deducer.   588    589         if argnames:   590             if self.in_class and not self.in_function and argnames[0] == "self":   591                 locals[argnames[0]] = Reference("<instance>", self.in_class)   592             else:   593                 locals[argnames[0]] = Reference("<var>")   594    595         for argname in argnames[1:]:   596             locals[argname] = Reference("<var>")   597    598         globals = self.scope_globals[function_name] = set()   599    600         # Process the defaults.   601    602         defaults = self.importer.function_defaults[function_name] = \   603                    self.function_defaults[function_name] = []   604    605         for argname, default in compiler.ast.get_defaults(n):   606             if default:   607    608                 # Obtain any reference for the default.   609    610                 name_ref = self.process_structure_node(default)   611                 defaults.append((argname, name_ref.is_name() and name_ref.reference() or Reference("<var>")))   612    613         # Reset conditional tracking to focus on the function contents.   614    615         in_conditional = self.in_conditional   616         self.in_conditional = False   617    618         in_function = self.in_function   619         self.in_function = function_name   620    621         self.enter_namespace(name)   622    623         # Track attribute usage within the namespace.   624    625         path = self.get_namespace_path()   626    627         self.start_tracking(locals)   628         self.process_structure_node(n.code)   629         self.stop_tracking()   630    631         # Exit to the parent.   632    633         self.exit_namespace()   634    635         # Update flags.   636    637         self.in_function = in_function   638         self.in_conditional = in_conditional   639    640         # Define the function using the appropriate name.   641    642         self.set_definition(name, "<function>")   643    644         # Where a function is set conditionally, assign the name.   645    646         if original_name:   647             self.process_assignment_for_function(original_name, name)   648    649     def process_global_node(self, n):   650    651         """   652         Process the given "global" node 'n'.   653         """   654    655         path = self.get_namespace_path()   656    657         if path != self.name:   658             self.scope_globals[path].update(n.names)   659    660     def process_if_node(self, n):   661    662         """   663         Process the given "if" node 'n'.   664         """   665    666         tracker = self.trackers[-1]   667         tracker.new_branchpoint()   668    669         for test, body in n.tests:   670             self.process_structure_node(test)   671    672             tracker.new_branch()   673    674             in_conditional = self.in_conditional   675             self.in_conditional = True   676             self.process_structure_node(body)   677             self.in_conditional = in_conditional   678    679             tracker.shelve_branch()   680    681         # Maintain a branch for the else clause.   682    683         tracker.new_branch()   684         if n.else_:   685             self.process_structure_node(n.else_)   686         tracker.shelve_branch()   687    688         tracker.merge_branches()   689    690     def process_import_node(self, n):   691    692         "Process the given import node 'n'."   693    694         path = self.get_namespace_path()   695    696         # Load the mentioned module.   697    698         for name, alias in n.names:   699             if name == self.name:   700                 raise InspectError("Cannot import the current module.", path, n)   701    702             self.set_module(alias or name.split(".")[-1], name)   703             self.queue_module(name, True)   704    705     def process_invocation_node(self, n):   706    707         "Process the given invocation node 'n'."   708    709         path = self.get_namespace_path()   710    711         self.allocate_arguments(path, n.args)   712    713         try:   714             # Process the expression, obtaining any identified reference.   715    716             in_invocation = self.in_invocation   717             self.in_invocation = True   718             name_ref = self.process_structure_node(n.node)   719             self.in_invocation = in_invocation   720    721             # Process the arguments.   722    723             for arg in n.args:   724                 self.process_structure_node(arg)   725    726             # Detect class invocations.   727    728             if isinstance(name_ref, ResolvedNameRef) and name_ref.has_kind("<class>"):   729                 return InstanceRef(name_ref.reference().instance_of())   730    731             elif isinstance(name_ref, NameRef):   732                 return InvocationRef(name_ref)   733    734             return None   735    736         finally:   737             self.deallocate_arguments(path, n.args)   738    739     def process_lambda_node(self, n):   740    741         "Process the given lambda node 'n'."   742    743         name = self.get_lambda_name()   744         self.process_function_node(n, name)   745    746         origin = self.get_object_path(name)   747         return ResolvedNameRef(name, Reference("<function>", origin))   748    749     def process_logical_node(self, n):   750    751         "Process the given operator node 'n'."   752    753         self.process_operator_chain(n.nodes, self.process_structure_node)   754    755     def process_name_node(self, n):   756    757         "Process the given name node 'n'."   758    759         path = self.get_namespace_path()   760    761         # Special names.   762    763         if n.name.startswith("$"):   764             value = self.get_special(n.name)   765             if value:   766                 return value   767    768         # Special case for operator functions introduced through code   769         # transformations.   770    771         if n.name.startswith("$op"):   772    773             # Obtain the location of the actual function defined in the operator   774             # package.   775    776             op = n.name[len("$op"):]   777    778             # Attempt to get a reference.   779    780             ref = self.import_name_from_module(op, "operator")   781             self.add_deferred(ref)   782    783             # Record the imported name and provide the resolved name reference.   784    785             value = ResolvedNameRef(n.name, ref)   786             self.set_special(n.name, value)   787             return value   788    789         # Test for self usage, which is only allowed in methods.   790    791         if n.name == "self" and not (self.in_function and self.in_class):   792             raise InspectError("Use of self is only allowed in methods.", path, n)   793    794         # Record usage of the name.   795    796         self.record_name(n.name)   797    798         # Search for unknown names in non-function scopes immediately.   799         # External names in functions are resolved later.   800    801         ref = self.find_name(n.name)   802         if ref:   803             return ResolvedNameRef(n.name, ref)   804    805         # Explicitly-declared global names.   806    807         elif self.in_function and n.name in self.scope_globals[path]:   808             return NameRef(n.name)   809    810         # Examine other names.   811    812         else:   813             tracker = self.trackers[-1]   814    815             # Check local names.   816    817             branches = tracker.tracking_name(n.name)   818    819             # Local name.   820    821             if branches:   822                 self.record_branches_for_access(branches, n.name, None)   823                 access_number = self.record_access_details(n.name, None, False)   824                 return LocalNameRef(n.name, access_number)   825    826             # Possible global or built-in name.   827    828             else:   829                 return NameRef(n.name)   830    831     def process_operator_chain(self, nodes, fn):   832    833         """   834         Process the given chain of 'nodes', applying 'fn' to each node or item.   835         Each node starts a new conditional region, effectively making a deeply-   836         nested collection of if-like statements.   837         """   838    839         tracker = self.trackers[-1]   840    841         for item in nodes:   842             tracker.new_branchpoint()   843             tracker.new_branch()   844             fn(item)   845    846         for item in nodes[:-1]:   847             tracker.shelve_branch()   848             tracker.new_branch()   849             tracker.shelve_branch()   850             tracker.merge_branches()   851    852         tracker.shelve_branch()   853         tracker.merge_branches()   854    855     def process_try_node(self, n):   856    857         """   858         Process the given "try...except" node 'n'.   859         """   860    861         tracker = self.trackers[-1]   862         tracker.new_branchpoint()   863    864         self.process_structure_node(n.body)   865    866         for name, var, handler in n.handlers:   867             if name is not None:   868                 self.process_structure_node(name)   869    870             # Any abandoned branches from the body can now be resumed in a new   871             # branch.   872    873             tracker.resume_abandoned_branches()   874    875             # Establish the local for the handler.   876    877             if var is not None:   878                 self.process_structure_node(var)   879             if handler is not None:   880                 self.process_structure_node(handler)   881    882             tracker.shelve_branch()   883    884         # The else clause maintains the usage from the body but without the   885         # abandoned branches since they would never lead to the else clause   886         # being executed.   887    888         if n.else_:   889             tracker.new_branch()   890             self.process_structure_node(n.else_)   891             tracker.shelve_branch()   892    893         # Without an else clause, a null branch propagates the successful   894         # outcome.   895    896         else:   897             tracker.new_branch()   898             tracker.shelve_branch()   899    900         tracker.merge_branches()   901    902     def process_try_finally_node(self, n):   903    904         """   905         Process the given "try...finally" node 'n'.   906         """   907    908         tracker = self.trackers[-1]   909         self.process_structure_node(n.body)   910    911         # Any abandoned branches from the body can now be resumed.   912    913         branches = tracker.resume_all_abandoned_branches()   914         self.process_structure_node(n.final)   915    916         # At the end of the finally clause, abandoned branches are discarded.   917    918         tracker.restore_active_branches(branches)   919    920     def process_while_node(self, n):   921    922         "Process the given while node 'n'."   923    924         tracker = self.trackers[-1]   925         tracker.new_branchpoint(loop_node=True)   926    927         # Evaluate any test or iterator outside the loop.   928    929         self.process_structure_node(n.test)   930    931         # Propagate attribute usage to branches.   932    933         tracker.new_branch(loop_node=True)   934    935         # Enter the loop.   936    937         in_conditional = self.in_conditional   938         self.in_conditional = True   939         self.process_structure_node(n.body)   940         self.in_conditional = in_conditional   941    942         # Continuing branches are resumed before any test.   943    944         tracker.resume_continuing_branches()   945    946         # Evaluate any continuation test within the body.   947    948         self.process_structure_node(n.test)   949    950         tracker.shelve_branch(loop_node=True)   951    952         # Support the non-looping condition.   953    954         tracker.new_branch()   955         tracker.shelve_branch()   956    957         tracker.merge_branches()   958    959         # Evaluate any else clause outside branches.   960    961         if n.else_:   962             self.process_structure_node(n.else_)   963    964         # Connect broken branches to the code after any loop.   965    966         tracker.resume_broken_branches()   967    968     # Branch tracking methods.   969    970     def start_tracking(self, names):   971    972         """   973         Start tracking attribute usage for names in the current namespace,   974         immediately registering the given 'names'.   975         """   976    977         path = self.get_namespace_path()   978         parent = self.trackers[-1]   979         tracker = BranchTracker()   980         self.trackers.append(tracker)   981    982         # Record the given names established as new branches.   983    984         tracker.assign_names(names)   985    986     def assign_name(self, name, name_ref):   987    988         "Assign to 'name' the given 'name_ref' in the current namespace."   989    990         name = self.get_name_for_tracking(name)   991         self.trackers[-1].assign_names([name], [name_ref])   992    993     def stop_tracking(self):   994    995         """   996         Stop tracking attribute usage, recording computed usage for the current   997         namespace.   998         """   999   1000         path = self.get_namespace_path()  1001         tracker = self.trackers.pop()  1002         self.record_assignments_for_access(tracker)  1003   1004         self.attr_usage[path] = tracker.get_all_usage()  1005         self.name_initialisers[path] = tracker.get_all_values()  1006   1007     def start_tracking_in_module(self):  1008   1009         "Start tracking attribute usage in the module."  1010   1011         tracker = BranchTracker()  1012         self.trackers.append(tracker)  1013   1014     def stop_tracking_in_module(self):  1015   1016         "Stop tracking attribute usage in the module."  1017   1018         tracker = self.trackers[0]  1019         self.record_assignments_for_access(tracker)  1020         self.attr_usage[self.name] = tracker.get_all_usage()  1021         self.name_initialisers[self.name] = tracker.get_all_values()  1022   1023     def record_assignments_for_access(self, tracker):  1024   1025         """  1026         For the current path, use the given 'tracker' to record assignment  1027         version information for attribute accesses.  1028         """  1029   1030         path = self.get_path_for_access()  1031   1032         if not self.attr_accessor_branches.has_key(path):  1033             return  1034   1035         init_item(self.attr_accessors, path, dict)  1036         attr_accessors = self.attr_accessors[path]  1037   1038         # Obtain the branches applying during each access.  1039   1040         for access, all_branches in self.attr_accessor_branches[path].items():  1041             name, attrnames = access  1042             init_item(attr_accessors, access, list)  1043   1044             # Obtain the assignments applying to each branch.  1045   1046             for branches in all_branches:  1047                 positions = tracker.get_assignment_positions_for_branches(name, branches)  1048   1049                 # Detect missing name information.  1050   1051                 if None in positions:  1052                     globals = self.global_attr_accesses.get(path)  1053                     accesses = globals and globals.get(name)  1054                     if not accesses:  1055                         print >>sys.stderr, "In %s, %s may not be defined when used." % (  1056                             self.get_namespace_path(), name)  1057                     positions.remove(None)  1058   1059                 attr_accessors[access].append(positions)  1060   1061     def record_branches_for_access(self, branches, name, attrnames):  1062   1063         """  1064         Record the given 'branches' for an access involving the given 'name' and  1065         'attrnames'.  1066         """  1067   1068         access = name, attrnames  1069         path = self.get_path_for_access()  1070   1071         init_item(self.attr_accessor_branches, path, dict)  1072         attr_accessor_branches = self.attr_accessor_branches[path]  1073   1074         init_item(attr_accessor_branches, access, list)  1075         attr_accessor_branches[access].append(branches)  1076   1077     def record_access_details(self, name, attrnames, assignment):  1078   1079         """  1080         For the given 'name' and 'attrnames', record an access indicating  1081         whether 'assignment' is occurring.  1082   1083         These details correspond to accesses otherwise recorded by the attribute  1084         accessor and attribute access dictionaries.  1085         """  1086   1087         access = name, attrnames  1088         path = self.get_path_for_access()  1089   1090         init_item(self.attr_access_modifiers, path, dict)  1091         init_item(self.attr_access_modifiers[path], access, list)  1092   1093         access_number = len(self.attr_access_modifiers[path][access])  1094         self.attr_access_modifiers[path][access].append(assignment and "A" or self.in_invocation and "I" or "_")  1095         return access_number  1096   1097     def record_global_access_details(self, name, attrnames):  1098   1099         """  1100         Record details of a global access via the given 'name' involving the  1101         indicated 'attrnames'.  1102         """  1103   1104         path = self.get_namespace_path()  1105   1106         init_item(self.global_attr_accesses, path, dict)  1107         init_item(self.global_attr_accesses[path], name, set)  1108         self.global_attr_accesses[path][name].add(attrnames)  1109   1110     # Namespace modification.  1111   1112     def record_name(self, name):  1113   1114         "Record the use of 'name' in a namespace."  1115   1116         path = self.get_namespace_path()  1117         init_item(self.names_used, path, set)  1118         self.names_used[path].add(name)  1119   1120     def set_module(self, name, module_name):  1121   1122         """  1123         Set a module in the current namespace using the given 'name' associated  1124         with the corresponding 'module_name'.  1125         """  1126   1127         if name:  1128             self.set_general_local(name, Reference("<module>", module_name))  1129   1130     def set_definition(self, name, kind):  1131   1132         """  1133         Set the definition having the given 'name' and 'kind'.  1134   1135         Definitions are set in the static namespace hierarchy, but they can also  1136         be recorded for function locals.  1137         """  1138   1139         if self.is_global(name):  1140             print >>sys.stderr, "In %s, %s is defined as being global." % (  1141                 self.get_namespace_path(), name)  1142   1143         path = self.get_object_path(name)  1144         self.set_object(path, kind)  1145   1146         ref = self.get_object(path)  1147         if ref.get_kind() == "<var>":  1148             print >>sys.stderr, "In %s, %s is defined more than once." % (  1149                 self.get_namespace_path(), name)  1150   1151         if not self.is_global(name) and self.in_function:  1152             self.set_function_local(name, ref)  1153   1154     def set_function_local(self, name, ref=None):  1155   1156         "Set the local with the given 'name' and optional 'ref'."  1157   1158         locals = self.function_locals[self.get_namespace_path()]  1159         multiple = not ref or locals.has_key(name) and locals[name] != ref  1160         locals[name] = multiple and Reference("<var>") or ref  1161   1162     def assign_general_local(self, name, name_ref):  1163   1164         """  1165         Set for 'name' the given 'name_ref', recording the name for attribute  1166         usage tracking.  1167         """  1168   1169         self.set_general_local(name, name_ref)  1170         self.assign_name(name, name_ref)  1171   1172     def set_general_local(self, name, value=None):  1173   1174         """  1175         Set the 'name' with optional 'value' in any kind of local namespace,  1176         where the 'value' should be a reference if specified.  1177         """  1178   1179         init_value = self.get_initialising_value(value)  1180   1181         # Module global names.  1182   1183         if self.is_global(name):  1184             path = self.get_global_path(name)  1185             self.set_object(path, init_value)  1186   1187         # Function local names.  1188   1189         elif self.in_function:  1190             path = self.get_object_path(name)  1191             self.set_function_local(name, init_value)  1192   1193         # Other namespaces (classes).  1194   1195         else:  1196             path = self.get_object_path(name)  1197             self.set_name(name, init_value)  1198   1199     def set_name(self, name, ref=None):  1200   1201         "Attach the 'name' with optional 'ref' to the current namespace."  1202   1203         self.set_object(self.get_object_path(name), ref)  1204   1205     def set_instance_attr(self, name, ref=None):  1206   1207         """  1208         Add an instance attribute of the given 'name' to the current class,  1209         using the optional 'ref'.  1210         """  1211   1212         init_item(self.instance_attrs, self.in_class, set)  1213         self.instance_attrs[self.in_class].add(name)  1214   1215         if ref:  1216             init_item(self.instance_attr_constants, self.in_class, dict)  1217             self.instance_attr_constants[self.in_class][name] = ref  1218   1219     def get_initialising_value(self, value):  1220   1221         "Return a suitable initialiser reference for 'value'."  1222   1223         # Includes LiteralSequenceRef, ResolvedNameRef...  1224   1225         if isinstance(value, (NameRef, AccessRef, InstanceRef)):  1226             return value.reference()  1227   1228         # In general, invocations do not produce known results. However, the  1229         # name initialisers are resolved once a module has been inspected.  1230   1231         elif isinstance(value, InvocationRef):  1232             return value.reference()  1233   1234         else:  1235             return value  1236   1237     # Static, program-relative naming.  1238   1239     def find_name(self, name):  1240   1241         """  1242         Return the qualified name for the given 'name' used in the current  1243         non-function namespace.  1244         """  1245   1246         path = self.get_namespace_path()  1247         ref = None  1248   1249         if not self.in_function and name not in predefined_constants:  1250             if self.in_class:  1251                 ref = self.get_object(self.get_object_path(name))  1252             if not ref:  1253                 ref = self.get_global_or_builtin(name)  1254   1255         return ref  1256   1257     def get_class(self, node):  1258   1259         """  1260         Use the given 'node' to obtain the identity of a class. Return a  1261         reference for the class. Unresolved dependencies are permitted and must  1262         be resolved later.  1263         """  1264   1265         ref = self._get_class(node)  1266         return ref.has_kind(["<class>", "<depends>"]) and ref or None  1267   1268     def _get_class(self, node):  1269   1270         """  1271         Use the given 'node' to find a class definition. Return a reference to  1272         the class.  1273         """  1274   1275         if isinstance(node, compiler.ast.Getattr):  1276   1277             # Obtain the identity of the access target.  1278   1279             ref = self._get_class(node.expr)  1280   1281             # Where the target is a class or module, obtain the identity of the  1282             # attribute.  1283   1284             if ref.has_kind(["<function>", "<var>"]):  1285                 return None  1286             else:  1287                 attrname = "%s.%s" % (ref.get_origin(), node.attrname)  1288                 return self.get_object(attrname)  1289   1290         # Names can be module-level or built-in.  1291   1292         elif isinstance(node, compiler.ast.Name):  1293   1294             # Record usage of the name and attempt to identify it.  1295   1296             self.record_name(node.name)  1297             return self.find_name(node.name)  1298         else:  1299             return None  1300   1301     def get_constant(self, name, value):  1302   1303         "Return a constant reference for the given type 'name' and 'value'."  1304   1305         ref = self.get_builtin_class(name)  1306         return self.get_constant_reference(ref, value)  1307   1308     def get_literal_instance(self, n, name):  1309   1310         "For node 'n', return a reference to an instance of 'name'."  1311   1312         # Get a reference to the built-in class.  1313   1314         ref = self.get_builtin_class(name)  1315   1316         # Obtain the details of the literal itself.  1317         # An alias to the type is generated for sequences.  1318   1319         if name in ("dict", "list", "tuple"):  1320             self.set_special_literal(name, ref)  1321             return self.process_literal_sequence_node(n, name, ref, LiteralSequenceRef)  1322   1323         # Constant values are independently recorded.  1324   1325         else:  1326             return self.get_constant_reference(ref, n.value)  1327   1328     # Special names.  1329   1330     def get_special(self, name):  1331   1332         "Return any stored value for the given special 'name'."  1333   1334         return self.special.get(name)  1335   1336     def set_special(self, name, value):  1337   1338         """  1339         Set a special 'name' that merely tracks the use of an implicit object  1340         'value'.  1341         """  1342   1343         self.special[name] = value  1344   1345     def set_special_literal(self, name, ref):  1346   1347         """  1348         Set a special name for the literal type 'name' having type 'ref'. Such  1349         special names provide a way of referring to literal object types.  1350         """  1351   1352         literal_name = "$L%s" % name  1353         value = ResolvedNameRef(literal_name, ref)  1354         self.set_special(literal_name, value)  1355   1356     # Functions and invocations.  1357   1358     def set_invocation_usage(self):  1359   1360         """  1361         Discard the current invocation storage figures, retaining the maximum  1362         values.  1363         """  1364   1365         for path, (current, maximum) in self.function_targets.items():  1366             self.importer.function_targets[path] = self.function_targets[path] = maximum  1367   1368         for path, (current, maximum) in self.function_arguments.items():  1369             self.importer.function_arguments[path] = self.function_arguments[path] = maximum  1370   1371     def allocate_arguments(self, path, args):  1372   1373         """  1374         Allocate temporary argument storage using current and maximum  1375         requirements for the given 'path' and 'args'.  1376         """  1377   1378         init_item(self.function_targets, path, lambda: [0, 0])  1379         t = self.function_targets[path]  1380         t[0] += 1  1381         t[1] = max(t[0], t[1])  1382   1383         init_item(self.function_arguments, path, lambda: [0, 0])  1384         t = self.function_arguments[path]  1385         t[0] += len(args) + 1  1386         t[1] = max(t[0], t[1])  1387   1388     def deallocate_arguments(self, path, args):  1389   1390         "Deallocate temporary argument storage for the given 'path' and 'args'."  1391   1392         self.function_targets[path][0] -= 1  1393         self.function_arguments[path][0] -= len(args) + 1  1394   1395 # vim: tabstop=4 expandtab shiftwidth=4