root / logilab.pylintinstaller / logilab / astng / lookup.py

Revision 202:d67e86292521, 7.9 kB (checked in by tziade@…, 9 months ago)

added logilab.pylintinstaller

Line 
1# This program is free software; you can redistribute it and/or modify it under
2# the terms of the GNU General Public License as published by the Free Software
3# Foundation; either version 2 of the License, or (at your option) any later
4# version.
5#
6# This program is distributed in the hope that it will be useful, but WITHOUT
7# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
9#
10# You should have received a copy of the GNU General Public License along with
11# this program; if not, write to the Free Software Foundation, Inc.,
12# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
13"""name lookup methods, available on Name ans scoped (Module, Class,
14Function...) nodes:
15
16* .lookup(name)
17* .ilookup(name)
18
19Be careful, lookup is kinda internal and return a tuple (scope, [stmts]), while
20ilookup return an iterator on infered values
21
22:author:    Sylvain Thenault
23:copyright: 2003-2007 LOGILAB S.A. (Paris, FRANCE)
24:contact:   http://www.logilab.fr/ -- mailto:python-projects@logilab.org
25:copyright: 2003-2007 Sylvain Thenault
26:contact:   mailto:thenault@gmail.com
27"""
28
29from __future__ import generators
30
31__docformat__ = "restructuredtext en"
32
33import __builtin__
34
35from logilab.astng.utils import are_exclusive
36from logilab.astng import nodes, MANAGER, _infer_stmts, copy_context
37
38
39def lookup(self, name):
40    """lookup a variable name
41
42    return the scoope node and the list of assignments associated to the given
43    name according to the scope where it has been found (locals, globals or
44    builtin)
45
46    The lookup is starting from self's scope. If self is not a frame itself and
47    the name is found in the inner frame locals, statements will be filtered
48    to remove ignorable statements according to self's location
49    """
50    #assert ID_RGX.match(name), '%r is not a valid identifier' % name
51    return self.scope().scope_lookup(self, name)
52
53def scope_lookup(self, node, name, offset=0):
54    try:
55        stmts = node._filter_stmts(self.locals[name], self, offset)
56    except KeyError:
57        stmts = ()
58    if stmts:
59        return self, stmts
60    if self.parent:
61        # nested scope: if parent scope is a function, that's fine
62        # else jump to the module
63        pscope = self.parent.scope()
64        if not isinstance(pscope, nodes.Function):
65            pscope = pscope.root()
66        return pscope.scope_lookup(node, name)
67    return builtin_lookup(name)
68
69def class_scope_lookup(self, node, name, offset=0):
70    if node in self.bases:
71        #print 'frame swaping'
72        frame = self.parent.frame()
73        # line offset to avoid that class A(A) resolve the ancestor to
74        # the defined class
75        offset = -1
76    else:
77        frame = self
78    return scope_lookup(frame, node, name, offset)
79
80def function_scope_lookup(self, node, name, offset=0):
81    if node in self.defaults:
82        frame = self.parent.frame()
83        # line offset to avoid that def func(f=func) resolve the default
84        # value to the defined function
85        offset = -1
86    else:
87        # check this is not used in function decorators
88        frame = self
89    return scope_lookup(frame, node, name, offset)
90   
91def builtin_lookup(name):
92    """lookup a name into the builtin module
93    return the list of matching statements and the astng for the builtin
94    module
95    """
96    builtinastng = MANAGER.astng_from_module(__builtin__)
97    try:
98        stmts = builtinastng.locals[name]
99    except KeyError:
100        stmts = ()
101    return builtinastng, stmts
102
103def ilookup(self, name, context=None):
104    """infered lookup
105   
106    return an iterator on infered values of the statements returned by
107    the lookup method
108    """
109    frame, stmts = self.lookup(name)
110    context = copy_context(context)
111    context.lookupname = name
112    return _infer_stmts(stmts, context, frame)
113
114
115def _filter_stmts(self, stmts, frame, offset):
116    """filter statements:
117
118    If self is not a frame itself and the name is found in the inner
119    frame locals, statements will be filtered to remove ignorable
120    statements according to self's location
121    """
122    # if offset == -1, my actual frame is not the inner frame but its parent
123    #
124    # class A(B): pass
125    #
126    # we need this to resolve B correctly
127    if offset == -1:
128        myframe = self.frame().parent.frame()
129    else:
130        myframe = self.frame()
131    if not myframe is frame or self is frame:
132        return stmts
133    #print self.name, frame.name
134    mystmt = self.statement()
135    # line filtering if we are in the same frame
136    if myframe is frame:
137        mylineno = mystmt.source_line() + offset
138    else:
139        # disabling lineno filtering
140        print 'disabling lineno filtering'
141        mylineno = 0
142    _stmts = []
143    _stmt_parents = []
144    #print '-'*60
145    #print 'filtering', stmts, mylineno
146    for node in stmts:
147        stmt = node.statement()
148        # line filtering is on and we have reached our location, break
149        if mylineno > 0 and stmt.source_line() > mylineno:
150            #print 'break', mylineno, stmt.source_line()
151            break
152        if isinstance(node, Class) and self in node.bases:
153            #print 'breaking on', self, node.bases           
154            break
155        try:
156            ass_type = node.ass_type()
157            if ass_type is mystmt:
158                if not isinstance(ass_type, (ListCompFor,  GenExprFor)):
159                    #print 'break now2', self, ass_type
160                    break
161                if isinstance(self, (Const, Name)):
162                    _stmts = [self]
163                    #print 'break now', ass_type, self, node
164                    break
165        except AttributeError:
166            ass_type = None
167        # a loop assigment is hidding previous assigment
168        if isinstance(ass_type, (For, ListCompFor,  GenExprFor)) and \
169               ass_type.parent_of(self):
170            _stmts = [node]
171            _stmt_parents = [stmt.parent]
172            continue
173        try:
174            pindex = _stmt_parents.index(stmt.parent)
175        except ValueError:
176            pass
177        else:
178            try:
179                if ass_type and _stmts[pindex].ass_type().parent_of(ass_type):
180                    # print 'skipping', node, node.source_line()
181                    continue
182            except AttributeError:
183                pass # name from Import, Function, Class...
184            if not are_exclusive(self, node):
185                ###print 'PARENT', stmt.parent
186                #print 'removing', _stmts[pindex]
187                del _stmt_parents[pindex]
188                del _stmts[pindex]
189        if isinstance(node, AssName):
190            if stmt.parent is mystmt.parent:
191                #print 'assign clear'
192                _stmts = []
193                _stmt_parents = []
194            if node.flags == 'OP_DELETE':
195                #print 'delete clear'
196                _stmts = []
197                _stmt_parents = []
198                continue
199               
200        if not are_exclusive(self, node):
201            #print 'append', node, node.source_line()
202            _stmts.append(node)
203            _stmt_parents.append(stmt.parent)
204    #print '->', _stmts
205    stmts = _stmts
206    return stmts
207
208
209def _decorate(astmodule):
210    """add this module functionalities to necessary nodes"""
211    for klass in (astmodule.Name, astmodule.Module, astmodule.Class,
212                  astmodule.Function, astmodule.Lambda):
213        klass.ilookup = ilookup
214        klass.lookup = lookup
215        klass._filter_stmts = _filter_stmts
216    astmodule.Class.scope_lookup = class_scope_lookup
217    astmodule.Function.scope_lookup = function_scope_lookup
218    astmodule.Lambda.scope_lookup = function_scope_lookup
219    astmodule.Module.scope_lookup = scope_lookup
220    astmodule.GenExpr.scope_lookup = scope_lookup
221    for name in ('Class', 'Function', 'Lambda',
222                 'For', 'ListCompFor', 'GenExprFor',
223                 'AssName', 'Name', 'Const'):
224        globals()[name] = getattr(astmodule, name)
Note: See TracBrowser for help on using the browser.