@@ -95,9 +95,15 @@ def iter_child_nodes(node, omit=None, _fields_order=_FieldsOrder()):
9595 """
9696 Yield all direct child nodes of *node*, that is, all fields that
9797 are nodes and all items of fields that are lists of nodes.
98+
99+ :param node: AST node to be iterated upon
100+ :param omit: String or tuple of strings denoting the
101+ attributes of the node to be omitted from
102+ further parsing
103+ :param _fields_order: Order of AST node fields
98104 """
99105 for name in _fields_order [node .__class__ ]:
100- if name == omit :
106+ if omit and name in omit :
101107 continue
102108 field = getattr (node , name , None )
103109 if isinstance (field , ast .AST ):
@@ -472,6 +478,17 @@ class Checker(object):
472478 callables which are deferred assignment checks.
473479 """
474480
481+ _ast_node_scope = {
482+ ast .Module : ModuleScope ,
483+ ast .ClassDef : ClassScope ,
484+ ast .FunctionDef : FunctionScope ,
485+ ast .Lambda : FunctionScope ,
486+ ast .ListComp : GeneratorScope ,
487+ ast .SetComp : GeneratorScope ,
488+ ast .GeneratorExp : GeneratorScope ,
489+ ast .DictComp : GeneratorScope ,
490+ }
491+
475492 nodeDepth = 0
476493 offset = None
477494 traceTree = False
@@ -493,7 +510,10 @@ def __init__(self, tree, filename='(none)', builtins=None,
493510 if builtins :
494511 self .builtIns = self .builtIns .union (builtins )
495512 self .withDoctest = withDoctest
496- self .scopeStack = [ModuleScope ()]
513+ try :
514+ self .scopeStack = [Checker ._ast_node_scope [type (tree )]()]
515+ except KeyError :
516+ raise RuntimeError ('No scope implemented for the node %r' % tree )
497517 self .exceptHandlers = [()]
498518 self .root = tree
499519 self .handleChildren (tree )
@@ -643,6 +663,18 @@ def descendantOf(self, node, ancestors, stop):
643663 return True
644664 return False
645665
666+ def _getAncestor (self , node , ancestor_type ):
667+ parent = node
668+ while True :
669+ if parent is self .root :
670+ return None
671+ parent = self .getParent (parent )
672+ if isinstance (parent , ancestor_type ):
673+ return parent
674+
675+ def getScopeNode (self , node ):
676+ return self ._getAncestor (node , tuple (Checker ._ast_node_scope .keys ()))
677+
646678 def differentForks (self , lnode , rnode ):
647679 """True, if lnode and rnode are located on different forks of IF/TRY"""
648680 ancestor = self .getCommonAncestor (lnode , rnode , self .root )
@@ -790,6 +822,8 @@ def handleNodeStore(self, node):
790822 binding = Binding (name , node )
791823 elif name == '__all__' and isinstance (self .scope , ModuleScope ):
792824 binding = ExportBinding (name , node .parent , self .scope )
825+ elif isinstance (getattr (node , 'ctx' , None ), ast .Param ):
826+ binding = Argument (name , self .getScopeNode (node ))
793827 else :
794828 binding = Assignment (name , node )
795829 self .addBinding (node , binding )
@@ -1103,13 +1137,12 @@ def NAME(self, node):
11031137 and isinstance (node .parent , ast .Call )):
11041138 # we are doing locals() call in current scope
11051139 self .scope .usesLocals = True
1106- elif isinstance (node .ctx , (ast .Store , ast .AugStore )):
1140+ elif isinstance (node .ctx , (ast .Store , ast .AugStore , ast . Param )):
11071141 self .handleNodeStore (node )
11081142 elif isinstance (node .ctx , ast .Del ):
11091143 self .handleNodeDelete (node )
11101144 else :
1111- # must be a Param context -- this only happens for names in function
1112- # arguments, but these aren't dispatched through here
1145+ # Unknown context
11131146 raise RuntimeError ("Got impossible expression context: %r" % (node .ctx ,))
11141147
11151148 def CONTINUE (self , node ):
@@ -1225,15 +1258,8 @@ def addArgs(arglist):
12251258 def runFunction ():
12261259
12271260 self .pushScope ()
1228- for name in args :
1229- self .addBinding (node , Argument (name , node ))
1230- if isinstance (node .body , list ):
1231- # case for FunctionDefs
1232- for stmt in node .body :
1233- self .handleNode (stmt , node )
1234- else :
1235- # case for Lambdas
1236- self .handleNode (node .body , node )
1261+
1262+ self .handleChildren (node , omit = 'decorator_list' )
12371263
12381264 def checkUnusedAssignments ():
12391265 """
@@ -1257,6 +1283,18 @@ def checkReturnWithArgumentInsideGenerator():
12571283
12581284 self .deferFunction (runFunction )
12591285
1286+ def ARGUMENTS (self , node ):
1287+ self .handleChildren (node , omit = ('defaults' , 'kw_defaults' ))
1288+ if PY2 :
1289+ scope_node = self .getScopeNode (node )
1290+ if node .vararg :
1291+ self .addBinding (node , Argument (node .vararg , scope_node ))
1292+ if node .kwarg :
1293+ self .addBinding (node , Argument (node .kwarg , scope_node ))
1294+
1295+ def ARG (self , node ):
1296+ self .addBinding (node , Argument (node .arg , self .getScopeNode (node )))
1297+
12601298 def CLASSDEF (self , node ):
12611299 """
12621300 Check names used in a class definition, including its decorators, base
0 commit comments