diff --git a/bitbake/lib/bb/codeparser.py b/bitbake/lib/bb/codeparser.py index 0f3d646cc4..77156136f8 100644 --- a/bitbake/lib/bb/codeparser.py +++ b/bitbake/lib/bb/codeparser.py @@ -155,40 +155,6 @@ class PythonParser(): expands = ("d.expand", "bb.data.expand", "data.expand") execfuncs = ("bb.build.exec_func", "bb.build.exec_task") - @classmethod - def _compare_name(cls, strparts, node): - """Given a sequence of strings representing a python name, - where the last component is the actual Name and the prior - elements are Attribute nodes, determine if the supplied node - matches. - """ - - if not strparts: - return True - - current, rest = strparts[0], strparts[1:] - if isinstance(node, ast.Attribute): - if current == node.attr: - return cls._compare_name(rest, node.value) - elif isinstance(node, ast.Name): - if current == node.id: - return True - return False - - @classmethod - def compare_name(cls, value, node): - """Convenience function for the _compare_node method, which - can accept a string (which is split by '.' for you), or an - iterable of strings, in which case it checks to see if any of - them match, similar to isinstance. - """ - - if isinstance(value, basestring): - return cls._compare_name(tuple(reversed(value.split("."))), - node) - else: - return any(cls.compare_name(item, node) for item in value) - @classmethod def warn(cls, func, arg): """Warn about calls of bitbake APIs which pass a non-literal @@ -206,39 +172,41 @@ class PythonParser(): "not a literal", funcstr, argstr) def visit_Call(self, node): - if self.compare_name(self.getvars, node.func): + name = self.called_node_name(node.func) + if name in self.getvars: if isinstance(node.args[0], ast.Str): self.var_references.add(node.args[0].s) else: self.warn(node.func, node.args[0]) - elif self.compare_name(self.expands, node.func): + elif name in self.expands: if isinstance(node.args[0], ast.Str): self.warn(node.func, node.args[0]) self.var_expands.add(node.args[0].s) elif isinstance(node.args[0], ast.Call) and \ - self.compare_name(self.getvars, node.args[0].func): + self.called_node_name(node.args[0].func) in self.getvars: pass else: self.warn(node.func, node.args[0]) - elif self.compare_name(self.execfuncs, node.func): + elif name in self.execfuncs: if isinstance(node.args[0], ast.Str): self.var_execs.add(node.args[0].s) else: self.warn(node.func, node.args[0]) - elif isinstance(node.func, ast.Name): - self.execs.add(node.func.id) - elif isinstance(node.func, ast.Attribute): - # We must have a qualified name. Therefore we need - # to walk the chain of 'Attribute' nodes to determine - # the qualification. - attr_node = node.func.value - identifier = node.func.attr - while isinstance(attr_node, ast.Attribute): - identifier = attr_node.attr + "." + identifier - attr_node = attr_node.value - if isinstance(attr_node, ast.Name): - identifier = attr_node.id + "." + identifier - self.execs.add(identifier) + elif name and isinstance(node.func, (ast.Name, ast.Attribute)): + self.execs.add(name) + + def called_node_name(self, node): + """Given a called node, return its original string form""" + components = [] + while node: + if isinstance(node, ast.Attribute): + components.append(node.attr) + node = node.value + elif isinstance(node, ast.Name): + components.append(node.id) + return '.'.join(reversed(components)) + else: + break def __init__(self): self.var_references = set()