Annotates an AST with additional source information like file name.
| 162 | |
| 163 | |
| 164 | class OriginResolver(gast.NodeVisitor): |
| 165 | """Annotates an AST with additional source information like file name.""" |
| 166 | |
| 167 | def __init__(self, root_node, source_lines, comments_map, |
| 168 | context_lineno, context_col_offset, |
| 169 | filepath): |
| 170 | self._source_lines = source_lines |
| 171 | self._comments_map = comments_map |
| 172 | |
| 173 | if (hasattr(root_node, 'decorator_list') and root_node.decorator_list and |
| 174 | hasattr(root_node.decorator_list[0], 'lineno')): |
| 175 | # Typical case: functions. The line number of the first decorator |
| 176 | # is more accurate than the line number of the function itself in |
| 177 | # 3.8+. In earier versions they coincide. |
| 178 | self._lineno_offset = context_lineno - root_node.decorator_list[0].lineno |
| 179 | else: |
| 180 | # Fall back to the line number of the root node. |
| 181 | self._lineno_offset = context_lineno - root_node.lineno |
| 182 | |
| 183 | self._col_offset = context_col_offset - root_node.col_offset |
| 184 | |
| 185 | self._filepath = filepath |
| 186 | |
| 187 | self._function_stack = [] |
| 188 | |
| 189 | def _absolute_lineno(self, node): |
| 190 | return node.lineno + self._lineno_offset |
| 191 | |
| 192 | def _absolute_col_offset(self, node): |
| 193 | return node.col_offset + self._col_offset |
| 194 | |
| 195 | def _attach_origin_info(self, node): |
| 196 | if self._function_stack: |
| 197 | function_name = self._function_stack[-1].name |
| 198 | else: |
| 199 | function_name = None |
| 200 | |
| 201 | source_code_line = self._source_lines[node.lineno - 1] |
| 202 | comment = self._comments_map.get(node.lineno) |
| 203 | |
| 204 | loc = Location(self._filepath, self._absolute_lineno(node), |
| 205 | self._absolute_col_offset(node)) |
| 206 | origin = OriginInfo(loc, function_name, source_code_line, comment) |
| 207 | anno.setanno(node, 'lineno', node.lineno) |
| 208 | anno.setanno(node, anno.Basic.ORIGIN, origin) |
| 209 | |
| 210 | def visit(self, node): |
| 211 | entered_function = False |
| 212 | if isinstance(node, gast.FunctionDef): |
| 213 | entered_function = True |
| 214 | self._function_stack.append(_Function(node.name)) |
| 215 | |
| 216 | if hasattr(node, 'lineno'): |
| 217 | self._attach_origin_info(node) |
| 218 | self.generic_visit(node) |
| 219 | |
| 220 | if entered_function: |
| 221 | self._function_stack.pop() |