def loop_body_block(self, body_node): def is_else_body(body_node): return (len(body_node.parent.children) == 3 # parent loop has an 'else' part and body_node == body_node.parent.children[ 2] # the current node is the 'else' part ) def child_is_if(body_node): return (body_node.children[0].type == "loop" and body_node.children[0].get("loopType") == "IF") if not body_node.getChild("block", 0): ok = False # allow "else if" if is_else_body(body_node) and child_is_if(body_node): ok = True else: # check @hints scope_node = scopes.find_enclosing(body_node) if scope_node: at_hints = get_at_hints(scope_node.node) if at_hints and 'lint' in at_hints and 'ignoreNoLoopBlock' in at_hints[ 'lint']: ok = True if not ok: warn("Loop or condition statement without a block as body", self.file_name, body_node)
def get_at_hints(node, at_hints=None): if at_hints is None: at_hints = defaultdict(dict) commentsArray = Comment.parseNode( node) # searches comment "around" this node for commentAttributes in commentsArray: for entry in commentAttributes: # {'arguments': ['a', 'b'], # 'category': u'lint', # 'functor': u'ignoreReferenceField', # 'text': u'<p>ignoreReferenceField(a,b)</p>' # } cat = entry['category'] if cat == 'lint': functor = entry['functor'] if functor not in at_hints[cat]: at_hints[cat][functor] = set() at_hints[cat][functor].update(entry['arguments']) elif cat == "ignore": if cat not in at_hints: at_hints[cat] = set() at_hints[cat].update(entry['arguments']) # include @hints of parent scopes scope = scopes.find_enclosing(node) if scope: if 0: print "debug:", file_name, node, scope.node at_hints = get_at_hints(scope.node, at_hints) return at_hints
def get_at_hints(node, at_hints=None): if at_hints is None: at_hints = defaultdict(dict) commentsArray = Comment.parseNode(node, process_txt=False) # searches comment "around" this node for commentAttributes in commentsArray: for entry in commentAttributes: # {'arguments': ['a', 'b'], # 'category': u'lint', # 'functor': u'ignoreReferenceField', # 'text': u'<p>ignoreReferenceField(a,b)</p>' # } cat = entry['category'] if cat=='lint': functor = entry['functor'] if functor not in at_hints[cat]: at_hints[cat][functor] = set() at_hints[cat][functor].update(entry['arguments']) elif cat=="ignore": if cat not in at_hints: at_hints[cat] = set() at_hints[cat].update(entry['arguments']) # include @hints of parent scopes scope = scopes.find_enclosing(node) if scope: at_hints = get_at_hints(scope.node, at_hints) return at_hints
def loop_body_block(self, body_node): def is_else_body(body_node): return (len(body_node.parent.children)==3 # parent loop has an 'else' part and body_node == body_node.parent.children[2] # the current node is the 'else' part ) def child_is_if(body_node): return (body_node.children[0].type == "loop" and body_node.children[0].get("loopType") == "IF" ) if not body_node.getChild("block",0): ok = False # allow "else if" if is_else_body(body_node) and child_is_if(body_node): ok = True else: # check @hints scope_node = scopes.find_enclosing(body_node) if scope_node: at_hints = get_at_hints(scope_node.node) if at_hints and 'lint' in at_hints and 'ignoreNoLoopBlock' in at_hints['lint']: ok = True if not ok: issue = warn("Loop or condition statement without a block as body", self.file_name, body_node) self.issues.append(issue)
def dependencies_from_ast(self, tree): result = [] if tree.type in ('file', 'function', 'catch'): top_scope = tree.scope else: top_scope = scopes.find_enclosing(tree) # walk through enclosing and all nested scopes for scope in top_scope.scope_iterator(): if scope.is_defer: # e.g. in 'defer' handle locals like 'statics' as dependency with recursion vars_ = dict(scope.globals().items() + [(x, y) for x, y in scope.locals().items() if y.is_param]) else: # only consider global syms vars_ = scope.globals() for name, scopeVar in vars_.items(): # { sym_name: ScopeVar } # create a depsItem for all its uses for var_node in scopeVar.uses: if treeutil.hasAncestor( var_node, tree ): # var_node is not disconnected through optimization #depsItem = self.depsItem_from_node(var_node) #result.append(depsItem) result.append(var_node) return result
def _analyzeClassDepsNode_1(self, node, depsList, inLoadContext, inDefer=False): if node.type in ("file", "function", "catch"): top_scope = node.scope else: top_scope = scopes.find_enclosing(node) # get enclosing scope of node # import pydb; pydb.debugger() for scope in top_scope.scope_iterator(): # walk through this and all nested scopes for global_name, scopeVar in scope.globals().items(): # get the global symbols { sym_name: ScopeVar } for node in scopeVar.uses: # create a depsItem for all its uses depsItem = self.qualify_deps_item(node, scope.is_load_time, scope.is_defer) depsList.append(depsItem) # and qualify them # Augment with feature dependencies introduces with qx.core.Environment.get("...") calls for envCall in variantoptimizer.findVariantNodes(node): className, classAttribute = self.getClassNameFromEnvKey( envCall.getChild("arguments").children[0].get("value", "") ) if className: depsItem = DependencyItem(className, classAttribute, self.id, envCall.get("line", -1)) depsItem.isCall = True # treat as if actual call, to collect recursive deps # .inLoadContext # get 'qx' node of 'qx.core.Environment....' call_operand = envCall.getChild("operand").children[0] qx_idnode = treeutil.findFirstChainChild(call_operand) scope = qx_idnode.scope inLoadContext = scope.is_load_time # get its scope's .is_load_time depsItem.isLoadDep = inLoadContext if inLoadContext: depsItem.needsRecursion = True depsList.append(depsItem) return
def _analyzeClassDepsNode_2(self, node, depsList, inLoadContext, inDefer=False): if node.type in ('file', 'function', 'catch'): top_scope = node.scope else: top_scope = scopes.find_enclosing( node) # get enclosing scope of node for scope in top_scope.scope_iterator( ): # walk through this and all nested scopes for global_name, scopeVar in scope.globals().items( ): # get the global symbols { sym_name: ScopeVar } for var_node in scopeVar.uses: # create a depsItem for all its uses if treeutil.hasAncestor( var_node, node ): # var_node is not disconnected through optimization depsItem = self.qualify_deps_item( var_node, scope.is_load_time, scope.is_defer) # as this also does filtering if depsItem: depsList.append(depsItem) # and qualify them #if depsItem.name == "qx.log.appender.Console": # import pydb; pydb.debugger() # Augment with feature dependencies introduces with qx.core.Environment.get("...") calls for env_operand in variantoptimizer.findVariantNodes(node): call_node = env_operand.parent.parent env_key = call_node.getChild("arguments").children[0].get( "value", "") className, classAttribute = self.getClassNameFromEnvKey(env_key) if className: #print className depsItem = DependencyItem(className, classAttribute, self.id, env_operand.get('line', -1)) depsItem.isCall = True # treat as if actual call, to collect recursive deps # .inLoadContext # get 'qx' node of 'qx.core.Environment....' qx_idnode = treeutil.findFirstChainChild(env_operand) scope = qx_idnode.scope inLoadContext = scope.is_load_time # get its scope's .is_load_time depsItem.isLoadDep = inLoadContext if inLoadContext: depsItem.needsRecursion = True depsList.append(depsItem) return
def dependencies_from_ast(self, tree): result = [] if tree.type in ("file", "function", "catch"): top_scope = tree.scope else: top_scope = scopes.find_enclosing(tree) # walk through enclosing and all nested scopes for scope in top_scope.scope_iterator(): if scope.is_defer: # e.g. in 'defer' handle locals like 'statics' as dependency with recursion vars_ = dict(scope.globals().items() + [(x, y) for x, y in scope.locals().items() if y.is_param]) else: # only consider global syms vars_ = scope.globals() for name, scopeVar in vars_.items(): # { sym_name: ScopeVar } # create a depsItem for all its uses for var_node in scopeVar.uses: if treeutil.hasAncestor(var_node, tree): # var_node is not disconnected through optimization depsItem = self.depsItem_from_node(var_node) result.append(depsItem) return result
def _analyzeClassDepsNode_2(self, node, depsList, inLoadContext, inDefer=False): if node.type in ('file', 'function', 'catch'): top_scope = node.scope else: top_scope = scopes.find_enclosing(node) # get enclosing scope of node for scope in top_scope.scope_iterator(): # walk through this and all nested scopes for global_name, scopeVar in scope.globals().items(): # get the global symbols { sym_name: ScopeVar } for var_node in scopeVar.uses: # create a depsItem for all its uses if treeutil.hasAncestor(var_node, node): # var_node is not disconnected through optimization depsItem = self.qualify_deps_item(var_node, scope.is_load_time, scope.is_defer) # as this also does filtering if depsItem: depsList.append(depsItem) # and qualify them #if depsItem.name == "qx.log.appender.Console": # import pydb; pydb.debugger() # Augment with feature dependencies introduces with qx.core.Environment.get("...") calls for env_operand in variantoptimizer.findVariantNodes(node): call_node = env_operand.parent.parent env_key = call_node.getChild("arguments").children[0].get("value", "") className, classAttribute = self.getClassNameFromEnvKey(env_key) if className: #print className depsItem = DependencyItem(className, classAttribute, self.id, env_operand.get('line', -1)) depsItem.isCall = True # treat as if actual call, to collect recursive deps # .inLoadContext # get 'qx' node of 'qx.core.Environment....' qx_idnode = treeutil.findFirstChainChild(env_operand) scope = qx_idnode.scope inLoadContext = scope.is_load_time # get its scope's .is_load_time depsItem.isLoadDep = inLoadContext if inLoadContext: depsItem.needsRecursion = True depsList.append(depsItem) return