Lichen

inspector.py

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