@@ -3,6 +3,7 @@ local M = {}
33local ts = vim .treesitter
44local warn = require (' pytrize.warn' ).warn
55local paths = require (' pytrize.paths' )
6+ local ts_utils = require (' pytrize.ts' )
67
78local function get_fixture_name ()
89 return vim .fn .expand (' <cword>' )
@@ -17,26 +18,6 @@ local function find_python_files(root_dir, name)
1718 return result
1819end
1920
20- local function walk (node , callback )
21- callback (node )
22- for child in node :iter_children () do
23- walk (child , callback )
24- end
25- end
26-
27- local function is_fixture_decorator (node , bufnr )
28- local node_type = node :type ()
29- if node_type == ' attribute' then
30- return ts .get_node_text (node , bufnr ) == ' pytest.fixture'
31- elseif node_type == ' call' then
32- local func = node :field (' function' )[1 ]
33- if func and func :type () == ' attribute' then
34- return ts .get_node_text (func , bufnr ) == ' pytest.fixture'
35- end
36- end
37- return false
38- end
39-
4021local function get_param_name_node (param_node )
4122 local t = param_node :type ()
4223 if t == ' identifier' then
@@ -140,34 +121,16 @@ local find_rename_positions = function(bufnr, old_name)
140121
141122 local positions = {}
142123
143- walk (root , function (node )
144- local node_type = node :type ()
145-
146- -- Case A: Fixture definition
147- if node_type == ' decorated_definition' then
148- local has_fixture_decorator = false
149- for child in node :iter_children () do
150- if child :type () == ' decorator' then
151- for dchild in child :iter_children () do
152- if is_fixture_decorator (dchild , bufnr ) then
153- has_fixture_decorator = true
154- break
155- end
156- end
157- end
158- end
159-
160- if has_fixture_decorator then
161- local func = node :field (' definition' )[1 ]
162- if func and func :type () == ' function_definition' then
163- local name_node = func :field (' name' )[1 ]
164- if name_node and ts .get_node_text (name_node , bufnr ) == old_name then
165- local row , col_start , _ , col_end = name_node :range ()
166- table.insert (positions , { row = row , col_start = col_start , col_end = col_end })
167- end
168- end
169- end
124+ -- Case A: Fixture definitions
125+ for _ , def in ipairs (ts_utils .get_fixture_defs (bufnr )) do
126+ if def .name == old_name then
127+ local row , col_start , _ , col_end = def .name_node :range ()
128+ table.insert (positions , { row = row , col_start = col_start , col_end = col_end })
170129 end
130+ end
131+
132+ ts_utils .walk (root , function (node )
133+ local node_type = node :type ()
171134
172135 -- Case B: Fixture consumer
173136 if node_type == ' function_definition' then
@@ -265,10 +228,25 @@ local function rename(old_name, new_name)
265228 return
266229 end
267230
231+ -- First pass: determine which files to process. Only rename in files where
232+ -- the fixture resolves to the current file (not shadowed by a closer definition).
233+ local files_to_process = {}
234+ for _ , filepath in ipairs (py_files ) do
235+ if filepath == current_file then
236+ table.insert (files_to_process , filepath )
237+ else
238+ local index = ts_utils .build_fixture_index (filepath , root_dir )
239+ local resolved = index [old_name ]
240+ if resolved and resolved .file == current_file then
241+ table.insert (files_to_process , filepath )
242+ end
243+ end
244+ end
245+
268246 local total_replacements = 0
269247 local files_changed = 0
270248
271- for _ , filepath in ipairs (py_files ) do
249+ for _ , filepath in ipairs (files_to_process ) do
272250 local existing_bufnr = vim .fn .bufnr (filepath )
273251 local was_loaded = existing_bufnr ~= - 1 and vim .fn .bufloaded (existing_bufnr ) == 1
274252
330308-- Internal exports for testing
331309M ._find_rename_positions = find_rename_positions
332310M ._apply_renames = apply_renames
311+ M ._rename = rename
333312
334313return M
0 commit comments