diff -r 3224f20d8eb0 -r 76f2b46437a6 Plugins/CheckerPlugins/SyntaxChecker/pyflakes/checker.py --- a/Plugins/CheckerPlugins/SyntaxChecker/pyflakes/checker.py Tue Oct 20 19:14:55 2015 +0200 +++ b/Plugins/CheckerPlugins/SyntaxChecker/pyflakes/checker.py Tue Oct 20 19:19:12 2015 +0200 @@ -455,6 +455,10 @@ elif isinstance(existing, Importation) and value.redefines(existing): existing.redefined.append(node) + if value.name in self.scope: + # then assume the rebound name is used as a global or within a loop + value.used = self.scope[value.name].used + self.scope[value.name] = value def getNodeHandler(self, node_class): @@ -478,7 +482,7 @@ return scopes = [scope for scope in self.scopeStack[:-1] - if isinstance(scope, (FunctionScope, ModuleScope))] + if isinstance(scope, (FunctionScope, ModuleScope, GeneratorScope))] if isinstance(self.scope, GeneratorScope) and scopes[-1] != self.scopeStack[-2]: scopes.append(self.scopeStack[-2]) @@ -533,14 +537,30 @@ binding = ExportBinding(name, node.parent, self.scope) else: binding = Assignment(name, node) - if name in self.scope: - binding.used = self.scope[name].used self.addBinding(node, binding) def handleNodeDelete(self, node): + + def on_conditional_branch(): + """ + Return `True` if node is part of a conditional body. + """ + current = getattr(node, 'parent', None) + while current: + if isinstance(current, (ast.If, ast.While, ast.IfExp)): + return True + current = getattr(current, 'parent', None) + return False + name = getNodeName(node) if not name: return + + if on_conditional_branch(): + # We can not predict if this conditional branch is going to + # be executed. + return + if isinstance(self.scope, FunctionScope) and name in self.scope.globals: self.scope.globals.remove(name) else: @@ -638,8 +658,8 @@ # "stmt" type nodes DELETE = PRINT = FOR = ASYNCFOR = WHILE = IF = WITH = WITHITEM = \ - ASYNCWITH = RAISE = TRYFINALLY = ASSERT = EXEC = EXPR = \ - ASSIGN = handleChildren + ASYNCWITH = ASYNCWITHITEM = RAISE = TRYFINALLY = ASSERT = EXEC = \ + EXPR = ASSIGN = handleChildren CONTINUE = BREAK = PASS = ignore @@ -662,14 +682,38 @@ EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = ignore # additional node types - LISTCOMP = COMPREHENSION = KEYWORD = handleChildren + COMPREHENSION = KEYWORD = handleChildren def GLOBAL(self, node): """ Keep track of globals declarations. """ - if isinstance(self.scope, FunctionScope): - self.scope.globals.update(node.names) + # In doctests, the global scope is an anonymous function at index 1. + global_scope_index = 0#1 if self.withDoctest else 0 + global_scope = self.scopeStack[global_scope_index] + + # Ignore 'global' statement in global scope. + if self.scope is not global_scope: + + # One 'global' statement can bind multiple (comma-delimited) names. + for node_name in node.names: + node_value = Assignment(node_name, node) + + # Remove UndefinedName messages already reported for this name. + self.messages = [ + m for m in self.messages if not + isinstance(m, messages.UndefinedName) and not + m.message_args[0] == node_name] + + # Bind name to global scope if it doesn't exist already. + global_scope.setdefault(node_name, node_value) + + # Bind name to non-global scopes, but as already "used". + node_value.used = (global_scope, node) + for scope in self.scopeStack[global_scope_index + 1:]: + scope[node_name] = node_value + if isinstance(scope, FunctionScope): + scope.globals.add(node_name) NONLOCAL = GLOBAL @@ -678,6 +722,8 @@ self.handleChildren(node) self.popScope() + LISTCOMP = handleChildren if PY2 else GENERATOREXP + DICTCOMP = SETCOMP = GENERATOREXP def NAME(self, node): @@ -701,6 +747,10 @@ raise RuntimeError("Got impossible expression context: %r" % (node.ctx,)) def RETURN(self, node): + if isinstance(self.scope, ClassScope): + self.report(messages.ReturnOutsideFunction, node) + return + if ( node.value and hasattr(self.scope, 'returnValue') and @@ -713,7 +763,7 @@ self.scope.isGenerator = True self.handleNode(node.value, node) - YIELDFROM = YIELD + AWAIT = YIELDFROM = YIELD def FUNCTIONDEF(self, node): for deco in node.decorator_list: