(lineno: int, node: ast.AST)
| 151 | |
| 152 | |
| 153 | def get_statement_startend2(lineno: int, node: ast.AST) -> tuple[int, int | None]: |
| 154 | # Flatten all statements and except handlers into one lineno-list. |
| 155 | # AST's line numbers start indexing at 1. |
| 156 | values: list[int] = [] |
| 157 | for x in ast.walk(node): |
| 158 | if isinstance(x, ast.stmt | ast.ExceptHandler): |
| 159 | # The lineno points to the class/def, so need to include the decorators. |
| 160 | if isinstance(x, ast.ClassDef | ast.FunctionDef | ast.AsyncFunctionDef): |
| 161 | for d in x.decorator_list: |
| 162 | values.append(d.lineno - 1) |
| 163 | values.append(x.lineno - 1) |
| 164 | for name in ("finalbody", "orelse"): |
| 165 | val: list[ast.stmt] | None = getattr(x, name, None) |
| 166 | if val: |
| 167 | # Treat the finally/orelse part as its own statement. |
| 168 | values.append(val[0].lineno - 1 - 1) |
| 169 | values.sort() |
| 170 | insert_index = bisect_right(values, lineno) |
| 171 | if insert_index == 0: |
| 172 | return 0, None |
| 173 | start = values[insert_index - 1] |
| 174 | if insert_index >= len(values): |
| 175 | end = None |
| 176 | else: |
| 177 | end = values[insert_index] |
| 178 | return start, end |
| 179 | |
| 180 | |
| 181 | def getstatementrange_ast( |
no test coverage detected