diff options
| -rw-r--r-- | bitbake/lib/bb/codeparser.py | 72 |
1 files changed, 20 insertions, 52 deletions
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 | |||
| @@ -156,40 +156,6 @@ class PythonParser(): | |||
| 156 | execfuncs = ("bb.build.exec_func", "bb.build.exec_task") | 156 | execfuncs = ("bb.build.exec_func", "bb.build.exec_task") |
| 157 | 157 | ||
| 158 | @classmethod | 158 | @classmethod |
| 159 | def _compare_name(cls, strparts, node): | ||
| 160 | """Given a sequence of strings representing a python name, | ||
| 161 | where the last component is the actual Name and the prior | ||
| 162 | elements are Attribute nodes, determine if the supplied node | ||
| 163 | matches. | ||
| 164 | """ | ||
| 165 | |||
| 166 | if not strparts: | ||
| 167 | return True | ||
| 168 | |||
| 169 | current, rest = strparts[0], strparts[1:] | ||
| 170 | if isinstance(node, ast.Attribute): | ||
| 171 | if current == node.attr: | ||
| 172 | return cls._compare_name(rest, node.value) | ||
| 173 | elif isinstance(node, ast.Name): | ||
| 174 | if current == node.id: | ||
| 175 | return True | ||
| 176 | return False | ||
| 177 | |||
| 178 | @classmethod | ||
| 179 | def compare_name(cls, value, node): | ||
| 180 | """Convenience function for the _compare_node method, which | ||
| 181 | can accept a string (which is split by '.' for you), or an | ||
| 182 | iterable of strings, in which case it checks to see if any of | ||
| 183 | them match, similar to isinstance. | ||
| 184 | """ | ||
| 185 | |||
| 186 | if isinstance(value, basestring): | ||
| 187 | return cls._compare_name(tuple(reversed(value.split("."))), | ||
| 188 | node) | ||
| 189 | else: | ||
| 190 | return any(cls.compare_name(item, node) for item in value) | ||
| 191 | |||
| 192 | @classmethod | ||
| 193 | def warn(cls, func, arg): | 159 | def warn(cls, func, arg): |
| 194 | """Warn about calls of bitbake APIs which pass a non-literal | 160 | """Warn about calls of bitbake APIs which pass a non-literal |
| 195 | argument for the variable name, as we're not able to track such | 161 | argument for the variable name, as we're not able to track such |
| @@ -206,39 +172,41 @@ class PythonParser(): | |||
| 206 | "not a literal", funcstr, argstr) | 172 | "not a literal", funcstr, argstr) |
| 207 | 173 | ||
| 208 | def visit_Call(self, node): | 174 | def visit_Call(self, node): |
| 209 | if self.compare_name(self.getvars, node.func): | 175 | name = self.called_node_name(node.func) |
| 176 | if name in self.getvars: | ||
| 210 | if isinstance(node.args[0], ast.Str): | 177 | if isinstance(node.args[0], ast.Str): |
| 211 | self.var_references.add(node.args[0].s) | 178 | self.var_references.add(node.args[0].s) |
| 212 | else: | 179 | else: |
| 213 | self.warn(node.func, node.args[0]) | 180 | self.warn(node.func, node.args[0]) |
| 214 | elif self.compare_name(self.expands, node.func): | 181 | elif name in self.expands: |
| 215 | if isinstance(node.args[0], ast.Str): | 182 | if isinstance(node.args[0], ast.Str): |
| 216 | self.warn(node.func, node.args[0]) | 183 | self.warn(node.func, node.args[0]) |
| 217 | self.var_expands.add(node.args[0].s) | 184 | self.var_expands.add(node.args[0].s) |
| 218 | elif isinstance(node.args[0], ast.Call) and \ | 185 | elif isinstance(node.args[0], ast.Call) and \ |
| 219 | self.compare_name(self.getvars, node.args[0].func): | 186 | self.called_node_name(node.args[0].func) in self.getvars: |
| 220 | pass | 187 | pass |
| 221 | else: | 188 | else: |
| 222 | self.warn(node.func, node.args[0]) | 189 | self.warn(node.func, node.args[0]) |
| 223 | elif self.compare_name(self.execfuncs, node.func): | 190 | elif name in self.execfuncs: |
| 224 | if isinstance(node.args[0], ast.Str): | 191 | if isinstance(node.args[0], ast.Str): |
| 225 | self.var_execs.add(node.args[0].s) | 192 | self.var_execs.add(node.args[0].s) |
| 226 | else: | 193 | else: |
| 227 | self.warn(node.func, node.args[0]) | 194 | self.warn(node.func, node.args[0]) |
| 228 | elif isinstance(node.func, ast.Name): | 195 | elif name and isinstance(node.func, (ast.Name, ast.Attribute)): |
| 229 | self.execs.add(node.func.id) | 196 | self.execs.add(name) |
| 230 | elif isinstance(node.func, ast.Attribute): | 197 | |
| 231 | # We must have a qualified name. Therefore we need | 198 | def called_node_name(self, node): |
| 232 | # to walk the chain of 'Attribute' nodes to determine | 199 | """Given a called node, return its original string form""" |
| 233 | # the qualification. | 200 | components = [] |
| 234 | attr_node = node.func.value | 201 | while node: |
| 235 | identifier = node.func.attr | 202 | if isinstance(node, ast.Attribute): |
| 236 | while isinstance(attr_node, ast.Attribute): | 203 | components.append(node.attr) |
| 237 | identifier = attr_node.attr + "." + identifier | 204 | node = node.value |
| 238 | attr_node = attr_node.value | 205 | elif isinstance(node, ast.Name): |
| 239 | if isinstance(attr_node, ast.Name): | 206 | components.append(node.id) |
| 240 | identifier = attr_node.id + "." + identifier | 207 | return '.'.join(reversed(components)) |
| 241 | self.execs.add(identifier) | 208 | else: |
| 209 | break | ||
| 242 | 210 | ||
| 243 | def __init__(self): | 211 | def __init__(self): |
| 244 | self.var_references = set() | 212 | self.var_references = set() |
