Inline Refactoring
Relevant source files
The following files were used as context for generating this wiki page:
Inline Refactoring is a core feature of the Rope library designed to replace a reference—such as a method, local variable, or parameter—with its actual definition. This process effectively reverses refactorings like "Extract Method" or "Extract Variable," simplifying code by removing unnecessary abstractions or intermediate assignments. Sources: rope/refactor/inline.py:64-77, README.rst
The system supports three primary types of inlining: InlineMethod, InlineVariable, and InlineParameter. It handles complex tasks such as resolving name conflicts during inlining, managing imports for the inlined code, and updating all occurrences across the project's Python files. Sources: rope/refactor/inline.py:79-198, ropetest/refactor/inlinetest.py:17-40
Architecture and Components
The inlining system is built around a factory function and a set of specialized refactoring classes. The entry point for the feature is create_inline, which determines the appropriate inlining type based on the Python object found at a specific file offset. Sources: rope/refactor/inline.py:64-85
Core Components Table
| Component | Description | Relevant File |
|---|---|---|
create_inline | Factory function that returns an InlineMethod, InlineVariable, or InlineParameter instance. | rope/refactor/inline.py:64 |
_Inliner | Base class for all inlining refactorings, providing common initialization and resource tracking. | rope/refactor/inline.py:88 |
InlineMethod | Handles replacing function/method calls with the function body, managing parameters and returns. | rope/refactor/inline.py:101 |
InlineVariable | Replaces local variable references with their assigned value or expression. | rope/refactor/inline.py:190 |
InlineParameter | Uses ChangeSignature to inline function parameters into their call sites. | rope/refactor/inline.py:261 |
_DefinitionGenerator | Responsible for generating the body of the function to be inlined, including parameter mapping. | rope/refactor/inline.py:317 |
Refactoring Initialization Flow
The following diagram illustrates how Rope selects the correct inlining strategy when a user requests an inline refactoring at a specific offset.
Sources: rope/refactor/inline.py:64-85
Inline Method Logic
The InlineMethod class manages the complex logic of moving a function body into various call sites. This involves several critical steps:
- Import Management: Moving required imports from the definition module to the target modules. Sources: rope/refactor/inline.py:114-121
- Parameter Mapping: Assigning call site arguments to the local variables of the inlined function body. Sources: rope/refactor/inline.py:365-380
- Conflict Resolution: Renaming local variables within the inlined body if they conflict with variables in the target scope using a unique prefix (e.g.,
__0__). Sources: rope/refactor/inline.py:382-402 - Return Handling: Converting
returnstatements into expressions or assignments depending on whether the call site uses the returned value. Sources: rope/refactor/inline.py:411-432
Function Call Inlining Sequence
This diagram shows the sequence of operations performed when inlining a function call within a target module.
Inline Variable Logic
InlineVariable is designed for local variables that are assigned exactly once. The refactoring replaces all references to the variable with its assigned expression. Sources: rope/refactor/inline.py:202-206
- Pre-conditions: The variable must be assigned only once; otherwise, a
RefactoringErroris raised. Sources: rope/refactor/inline.py:202 - Replacement: The assignment expression is retrieved via
_getvardefand applied to all occurrences found by theoccurrence_finder. Sources: rope/refactor/inline.py:476-492 - Cleanup: If
remove=True, the original assignment line is removed from the source code. Sources: rope/refactor/inline.py:492-501
Variable Inlining Constraints
| Constraint | Logic | Source |
|---|---|---|
| Single Assignment | len(self.pyname.assignments) != 1 triggers error | rope/refactor/inline.py:202-206 |
| Tuple Assignments | Cannot inline if assignment involves levels/tuples | rope/refactor/inline.py:510-511 |
| Local Scope | Default behavior limits search to the defining resource | rope/refactor/inline.py:218-220 |
Data Structures and Utilities
_DefinitionGenerator
This class acts as a template engine for the inlining process. It uses functionutils.DefinitionInfo to read the signature of the function and functionutils.ArgumentMapping to map passed values to parameters. Sources: rope/refactor/inline.py:350-380
Occurrence Handling
Inlining relies heavily on the occurrences module to find references. For methods, it uses a specialized handle _InlineFunctionCallsForModuleHandle to process each call site, determining if the call is part of an expression (requiring return value handling) or a standalone statement. Sources: rope/refactor/inline.py:435-465
# Definition of a header in _DefinitionGenerator
# This snippet shows how parameters are converted to local assignments
for name, value in paramdict.items():
if name != value and value is not None:
header += name + " = " + value.replace("\n", " ") + "\n"
to_be_inlined.append(name)
Sources: rope/refactor/inline.py:375-380
Conflict Resolution and Scope Management
When inlining code into a new scope, Rope prevents variable name collisions. If a variable name in the inlined function body exists in the host_vars (the variables of the destination scope), Rope renames the guest variable.
- Unique Prefixing: Uses a generator
unique_prefix()to create names like__0__varname. Sources: rope/refactor/inline.py:58-62, rope/refactor/inline.py:389 - Recursive Inlining: Once parameters are mapped to call site values in the header, they are themselves inlined into the body using
_inline_variableto further simplify the resulting code. Sources: rope/refactor/inline.py:404-409
Conclusion
Inline Refactoring in Rope is a sophisticated tool that manages Python's scope and dynamic nature to safely collapse abstractions. By integrating with the library's static analysis, import management, and occurrence finding modules, it ensures that code remains syntactically correct and semantically identical after the transformation. Sources: rope/refactor/inline.py:10-25, README.rst