diff --git a/lib/typeprof/core/service.rb b/lib/typeprof/core/service.rb index 11b9e068..a79ca1c0 100644 --- a/lib/typeprof/core/service.rb +++ b/lib/typeprof/core/service.rb @@ -203,11 +203,20 @@ def type_definitions(path, pos) if node.ret ty_defs = [] node.ret.types.map do |ty, _source| - if ty.is_a?(Type::Instance) - ty.mod.module_decls.each do |mdecl| - # TODO + mod = case ty + when Type::Instance, Type::Singleton + ty.mod + else + base = ty.base_type(@genv) + base.mod if base.is_a?(Type::Instance) + end + + if mod + mod.module_decls.each do |mdecl| + decl_path = mdecl.lenv.path + ty_defs << [decl_path, mdecl.code_range] if decl_path end - ty.mod.module_defs.each do |mdef_node| + mod.module_defs.each do |mdef_node| ty_defs << [mdef_node.lenv.path, mdef_node.code_range] end end diff --git a/test/fixtures/type_definition/sig/test.rbs b/test/fixtures/type_definition/sig/test.rbs new file mode 100644 index 00000000..c9dbbe44 --- /dev/null +++ b/test/fixtures/type_definition/sig/test.rbs @@ -0,0 +1,2 @@ +class Foo +end diff --git a/test/fixtures/type_definition/test.rb b/test/fixtures/type_definition/test.rb new file mode 100644 index 00000000..3f7fb90e --- /dev/null +++ b/test/fixtures/type_definition/test.rb @@ -0,0 +1,5 @@ +class Foo +end + +foo = Foo.new +foo diff --git a/test/fixtures/type_definition/typeprof.conf.json b/test/fixtures/type_definition/typeprof.conf.json new file mode 100644 index 00000000..96fc8809 --- /dev/null +++ b/test/fixtures/type_definition/typeprof.conf.json @@ -0,0 +1,5 @@ +{ + "typeprof_version": "experimental", + "analysis_unit_dirs": ["."], + "sig_dirs": ["sig"] +} diff --git a/test/lsp/lsp_test.rb b/test/lsp/lsp_test.rb index 782fc1ba..5ef58ec7 100644 --- a/test/lsp/lsp_test.rb +++ b/test/lsp/lsp_test.rb @@ -285,6 +285,78 @@ def test(x) end end - # TODO: add a test for definition (for crossing files) + def test_type_definition_for_class_constant + init("type_definition") + + notify( + "textDocument/didOpen", + textDocument: { uri: @folder + "test.rb", version: 0, text: <<-END }, +class Foo +end + +foo = Foo.new +foo + END + ) + + expect_notification("typeprof.enableToggleButton") {|json| } + expect_request("workspace/codeLens/refresh") {|json| } + + id = request( + "textDocument/typeDefinition", + textDocument: { uri: @folder + "test.rb" }, + position: { line: 3, character: 6 }, + ) + + expect_response(id) do |json| + assert_equal(2, json.size) + + rbs_result = json.find { |r| r[:uri].end_with?(".rbs") } + rb_result = json.find { |r| r[:uri].end_with?(".rb") } + + assert_not_nil(rbs_result, "RBS definition should be found") + assert_not_nil(rb_result, "Ruby definition should be found") + + assert(rbs_result[:uri].end_with?("sig/test.rbs")) + assert(rb_result[:uri].end_with?("test.rb")) + end + end + + def test_type_definition_for_local_variable + init("type_definition") + + notify( + "textDocument/didOpen", + textDocument: { uri: @folder + "test.rb", version: 0, text: <<-END }, +class Foo +end + +foo = Foo.new +foo + END + ) + + expect_notification("typeprof.enableToggleButton") {|json| } + expect_request("workspace/codeLens/refresh") {|json| } + + id = request( + "textDocument/typeDefinition", + textDocument: { uri: @folder + "test.rb" }, + position: { line: 4, character: 0 }, + ) + + expect_response(id) do |json| + assert_equal(2, json.size) + + rbs_result = json.find { |r| r[:uri].end_with?(".rbs") } + rb_result = json.find { |r| r[:uri].end_with?(".rb") } + + assert_not_nil(rbs_result, "RBS definition should be found") + assert_not_nil(rb_result, "Ruby definition should be found") + + assert(rbs_result[:uri].end_with?("sig/test.rbs")) + assert(rb_result[:uri].end_with?("test.rb")) + end + end end end