(lineno: int, node: ast.AST)
| 144 | |
| 145 | |
| 146 | def get_statement_startend2(lineno: int, node: ast.AST) -> Tuple[int, Optional[int]]: |
| 147 | # Flatten all statements and except handlers into one lineno-list. |
| 148 | # AST's line numbers start indexing at 1. |
| 149 | values: List[int] = [] |
| 150 | for x in ast.walk(node): |
| 151 | if isinstance(x, (ast.stmt, ast.ExceptHandler)): |
| 152 | # Before Python 3.8, the lineno of a decorated class or function pointed at the decorator. |
| 153 | # Since Python 3.8, the lineno points to the class/def, so need to include the decorators. |
| 154 | if isinstance(x, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)): |
| 155 | for d in x.decorator_list: |
| 156 | values.append(d.lineno - 1) |
| 157 | values.append(x.lineno - 1) |
| 158 | for name in ("finalbody", "orelse"): |
| 159 | val: Optional[List[ast.stmt]] = getattr(x, name, None) |
| 160 | if val: |
| 161 | # Treat the finally/orelse part as its own statement. |
| 162 | values.append(val[0].lineno - 1 - 1) |
| 163 | values.sort() |
| 164 | insert_index = bisect_right(values, lineno) |
| 165 | start = values[insert_index - 1] |
| 166 | if insert_index >= len(values): |
| 167 | end = None |
| 168 | else: |
| 169 | end = values[insert_index] |
| 170 | return start, end |
| 171 | |
| 172 | |
| 173 | def getstatementrange_ast( |
no test coverage detected