Skip to content

Commit b291109

Browse files
authored
find instance variable references with matched scopes (#3377)
* find instance variable references with matched scope * handling top level references and refactoring
1 parent fe1cbbb commit b291109

File tree

3 files changed

+94
-18
lines changed

3 files changed

+94
-18
lines changed

lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,14 @@ class InstanceVariableTarget < Target
3232
#: String
3333
attr_reader :name
3434

35-
#: (String name) -> void
36-
def initialize(name)
35+
#: Array[String]
36+
attr_reader :owner_ancestors
37+
38+
#: (String name, Array[String] owner_ancestors) -> void
39+
def initialize(name, owner_ancestors)
3740
super()
3841
@name = name
42+
@owner_ancestors = owner_ancestors
3943
end
4044
end
4145

@@ -322,7 +326,10 @@ def collect_constant_references(name, location)
322326
def collect_instance_variable_references(name, location, declaration)
323327
return unless @target.is_a?(InstanceVariableTarget) && name == @target.name
324328

325-
@references << Reference.new(name, location, declaration: declaration)
329+
receiver_type = Index.actual_nesting(@stack, nil).join("::")
330+
if @target.owner_ancestors.include?(receiver_type)
331+
@references << Reference.new(name, location, declaration: declaration)
332+
end
326333
end
327334
end
328335
end

lib/ruby_indexer/test/reference_finder_test.rb

Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -216,22 +216,43 @@ def foo
216216
assert_equal(11, refs[2].location.start_line)
217217
end
218218

219-
def test_finds_instance_variable_read_references
220-
refs = find_instance_variable_references("@foo", <<~RUBY)
219+
def test_finds_instance_variable_references
220+
refs = find_instance_variable_references("@name", ["Foo"], <<~RUBY)
221221
class Foo
222-
def foo
223-
@foo
222+
def initialize
223+
@name = "foo"
224+
end
225+
def name
226+
@name
227+
end
228+
def name_capital
229+
@name[0]
230+
end
231+
end
232+
233+
class Bar
234+
def initialize
235+
@name = "foo"
236+
end
237+
def name
238+
@name
224239
end
225240
end
226241
RUBY
227-
assert_equal(1, refs.size)
242+
assert_equal(3, refs.size)
228243

229-
assert_equal("@foo", refs[0].name)
244+
assert_equal("@name", refs[0].name)
230245
assert_equal(3, refs[0].location.start_line)
246+
247+
assert_equal("@name", refs[1].name)
248+
assert_equal(6, refs[1].location.start_line)
249+
250+
assert_equal("@name", refs[2].name)
251+
assert_equal(9, refs[2].location.start_line)
231252
end
232253

233254
def test_finds_instance_variable_write_references
234-
refs = find_instance_variable_references("@foo", <<~RUBY)
255+
refs = find_instance_variable_references("@foo", ["Foo"], <<~RUBY)
235256
class Foo
236257
def write
237258
@foo = 1
@@ -252,26 +273,70 @@ def write
252273
assert_equal(7, refs[4].location.start_line)
253274
end
254275

255-
def test_finds_instance_variable_references_ignore_context
256-
refs = find_instance_variable_references("@name", <<~RUBY)
257-
class Foo
276+
def test_finds_instance_variable_references_in_owner_ancestors
277+
refs = find_instance_variable_references("@name", ["Foo", "Base", "Top", "Parent"], <<~RUBY)
278+
module Base
279+
def change_name(name)
280+
@name = name
281+
end
258282
def name
283+
@name
284+
end
285+
286+
module ::Top
287+
def name
288+
@name
289+
end
290+
end
291+
end
292+
293+
class Parent
294+
def initialize
295+
@name = "parent"
296+
end
297+
def name_capital
298+
@name[0]
299+
end
300+
end
301+
302+
class Foo < Parent
303+
include Base
304+
def initialize
259305
@name = "foo"
260306
end
307+
def name
308+
@name
309+
end
261310
end
311+
262312
class Bar
263313
def name
264314
@name = "bar"
265315
end
266316
end
267317
RUBY
268-
assert_equal(2, refs.size)
318+
assert_equal(7, refs.size)
269319

270320
assert_equal("@name", refs[0].name)
271321
assert_equal(3, refs[0].location.start_line)
272322

273323
assert_equal("@name", refs[1].name)
274-
assert_equal(8, refs[1].location.start_line)
324+
assert_equal(6, refs[1].location.start_line)
325+
326+
assert_equal("@name", refs[2].name)
327+
assert_equal(11, refs[2].location.start_line)
328+
329+
assert_equal("@name", refs[3].name)
330+
assert_equal(18, refs[3].location.start_line)
331+
332+
assert_equal("@name", refs[4].name)
333+
assert_equal(21, refs[4].location.start_line)
334+
335+
assert_equal("@name", refs[5].name)
336+
assert_equal(28, refs[5].location.start_line)
337+
338+
assert_equal("@name", refs[6].name)
339+
assert_equal(31, refs[6].location.start_line)
275340
end
276341

277342
def test_accounts_for_reopened_classes
@@ -310,8 +375,8 @@ def find_method_references(method_name, source)
310375
find_references(target, source)
311376
end
312377

313-
def find_instance_variable_references(instance_variable_name, source)
314-
target = ReferenceFinder::InstanceVariableTarget.new(instance_variable_name)
378+
def find_instance_variable_references(instance_variable_name, owner_ancestors, source)
379+
target = ReferenceFinder::InstanceVariableTarget.new(instance_variable_name, owner_ancestors)
315380
find_references(target, source)
316381
end
317382

lib/ruby_lsp/requests/references.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,11 @@ def create_reference_target(target_node, node_context)
101101
Prism::InstanceVariableReadNode,
102102
Prism::InstanceVariableTargetNode,
103103
Prism::InstanceVariableWriteNode
104-
RubyIndexer::ReferenceFinder::InstanceVariableTarget.new(target_node.name.to_s)
104+
receiver_type = @global_state.type_inferrer.infer_receiver_type(node_context)
105+
return unless receiver_type
106+
107+
ancestors = @global_state.index.linearized_ancestors_of(receiver_type.name)
108+
RubyIndexer::ReferenceFinder::InstanceVariableTarget.new(target_node.name.to_s, ancestors)
105109
when Prism::CallNode, Prism::DefNode
106110
RubyIndexer::ReferenceFinder::MethodTarget.new(target_node.name.to_s)
107111
end

0 commit comments

Comments
 (0)