Rename variables to allow redefinition of variables. For example, consider this code: x = 0 f(x) x = "a" g(x) It will be transformed like this: x' = 0 f(x') x = "a" g(x) There will be two independent variables (x' and x) that will ha
| 38 | |
| 39 | |
| 40 | class VariableRenameVisitor(TraverserVisitor): |
| 41 | """Rename variables to allow redefinition of variables. |
| 42 | |
| 43 | For example, consider this code: |
| 44 | |
| 45 | x = 0 |
| 46 | f(x) |
| 47 | |
| 48 | x = "a" |
| 49 | g(x) |
| 50 | |
| 51 | It will be transformed like this: |
| 52 | |
| 53 | x' = 0 |
| 54 | f(x') |
| 55 | |
| 56 | x = "a" |
| 57 | g(x) |
| 58 | |
| 59 | There will be two independent variables (x' and x) that will have separate |
| 60 | inferred types. The publicly exposed variant will get the non-suffixed name. |
| 61 | This is the last definition at module top level and the first definition |
| 62 | (argument) within a function. |
| 63 | |
| 64 | Renaming only happens for assignments within the same block. Renaming is |
| 65 | performed before semantic analysis, immediately after parsing. |
| 66 | |
| 67 | The implementation performs a rudimentary static analysis. The analysis is |
| 68 | overly conservative to keep things simple. |
| 69 | """ |
| 70 | |
| 71 | def __init__(self) -> None: |
| 72 | # Counter for labeling new blocks |
| 73 | self.block_id = 0 |
| 74 | # Number of surrounding try statements that disallow variable redefinition |
| 75 | self.disallow_redef_depth = 0 |
| 76 | # Number of surrounding loop statements |
| 77 | self.loop_depth = 0 |
| 78 | # Map block id to loop depth. |
| 79 | self.block_loop_depth: dict[int, int] = {} |
| 80 | # Stack of block ids being processed. |
| 81 | self.blocks: list[int] = [] |
| 82 | # List of scopes; each scope maps short (unqualified) name to block id. |
| 83 | self.var_blocks: list[dict[str, int]] = [] |
| 84 | |
| 85 | # References to variables that we may need to rename. List of |
| 86 | # scopes; each scope is a mapping from name to list of collections |
| 87 | # of names that refer to the same logical variable. |
| 88 | self.refs: list[dict[str, list[list[NameExpr]]]] = [] |
| 89 | # Number of reads of the most recent definition of a variable (per scope) |
| 90 | self.num_reads: list[dict[str, int]] = [] |
| 91 | # Kinds of nested scopes (FILE, FUNCTION or CLASS) |
| 92 | self.scope_kinds: list[int] = [] |
| 93 | |
| 94 | def visit_mypy_file(self, file_node: MypyFile) -> None: |
| 95 | """Rename variables within a file. |
| 96 | |
| 97 | This is the main entry point to this class. |
no outgoing calls
no test coverage detected
searching dependent graphs…