Lichen

inspector.py

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