From 03e890d98d9a836bf777d4e71bae1af8fd801e2a Mon Sep 17 00:00:00 2001 From: Steve Cohen Date: Fri, 12 Apr 2024 17:30:29 -0700 Subject: [PATCH] Revert "For module definitions, use the `Indexer` version instead of `ElixirSense` (#658)" This reverts commit 1e00d8e5de0326062c8283a142043d7d83bae620. --- .../code_intelligence/definition.ex | 51 +----- .../fixtures/navigations/lib/my_definition.ex | 2 - .../code_intelligence/definition_test.exs | 156 +++--------------- .../provider/handlers/go_to_definition.ex | 2 +- .../handlers/go_to_definition_test.exs | 7 +- 5 files changed, 36 insertions(+), 182 deletions(-) diff --git a/apps/remote_control/lib/lexical/remote_control/code_intelligence/definition.ex b/apps/remote_control/lib/lexical/remote_control/code_intelligence/definition.ex index cae6d7717..70b2e7d70 100644 --- a/apps/remote_control/lib/lexical/remote_control/code_intelligence/definition.ex +++ b/apps/remote_control/lib/lexical/remote_control/code_intelligence/definition.ex @@ -1,52 +1,17 @@ defmodule Lexical.RemoteControl.CodeIntelligence.Definition do alias Future.Code, as: Code alias Lexical.Ast - alias Lexical.Ast.Analysis alias Lexical.Document alias Lexical.Document.Location alias Lexical.Document.Position - alias Lexical.Formats alias Lexical.RemoteControl.CodeIntelligence.Entity - alias Lexical.RemoteControl.Search.Store alias Lexical.Text - @spec definition(Document.t(), Position.t()) :: {:ok, [Location.t()]} | {:error, String.t()} def definition(%Document{} = document, %Position{} = position) do - with {:ok, _, analysis} <- Document.Store.fetch(document.uri, :analysis), - {:ok, entity, _range} <- Entity.resolve(analysis, position) do - fetch_definition(entity, analysis, position) - end - end - - defp fetch_definition({type, entity}, %Analysis{} = _analysis, %Position{} = _position) - when type in [:struct, :module] do - module = Formats.module(entity) - - locations = - for entry <- Store.exact(module, type: type, subtype: :definition), - result = to_location(entry), - match?({:ok, _}, result) do - {:ok, location} = result - location - end - - case locations do - [] -> - {:error, "No definition found for #{inspect(module)}"} - - [location] -> - {:ok, location} - - _ -> - {:ok, locations} - end - end - - defp fetch_definition(_, %Analysis{} = analysis, %Position{} = position) do - analysis.document + document |> Document.to_string() |> ElixirSense.definition(position.line, position.character) - |> parse_location(analysis.document) + |> parse_location(document) end defp parse_location(%ElixirSense.Location{} = location, document) do @@ -107,16 +72,4 @@ defmodule Lexical.RemoteControl.CodeIntelligence.Definition do Entity.to_range(document, pos, pos) end end - - defp to_location(entry) do - uri = Document.Path.ensure_uri(entry.path) - - case Document.Store.open_temporary(uri) do - {:ok, document} -> - {:ok, Location.new(entry.range, document)} - - _ -> - :error - end - end end diff --git a/apps/remote_control/test/fixtures/navigations/lib/my_definition.ex b/apps/remote_control/test/fixtures/navigations/lib/my_definition.ex index 28d9d4e54..651982512 100644 --- a/apps/remote_control/test/fixtures/navigations/lib/my_definition.ex +++ b/apps/remote_control/test/fixtures/navigations/lib/my_definition.ex @@ -1,8 +1,6 @@ defmodule MyDefinition do @type result :: String.t() - defstruct [:field, another_field: nil] - defmacro __using__(_opts) do quote do import MyDefinition diff --git a/apps/remote_control/test/lexical/remote_control/code_intelligence/definition_test.exs b/apps/remote_control/test/lexical/remote_control/code_intelligence/definition_test.exs index 46d992256..67743823f 100644 --- a/apps/remote_control/test/lexical/remote_control/code_intelligence/definition_test.exs +++ b/apps/remote_control/test/lexical/remote_control/code_intelligence/definition_test.exs @@ -2,15 +2,13 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do use ExUnit.Case, async: true alias Lexical.Document + alias Lexical.Document.Location alias Lexical.RemoteControl alias Lexical.RemoteControl.ProjectNodeSupervisor - alias Lexical.RemoteControl.Search - alias Lexical.RemoteControl.Search.Store.Backends import Lexical.RemoteControl.Api.Messages import Lexical.Test.CodeSigil import Lexical.Test.CursorSupport - import Lexical.Test.EventualAssertions import Lexical.Test.Fixtures import Lexical.Test.RangeSupport @@ -22,12 +20,6 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do |> file_path(Path.join("lib", "my_definition.ex")) |> Document.Path.ensure_uri() - {:ok, _document} = Document.Store.open_temporary(uri) - - on_exit(fn -> - :ok = Document.Store.close(uri) - end) - %{uri: uri} end @@ -46,6 +38,8 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do end setup_all do + start_supervised!(Lexical.Document.Store) + project = project(:navigations) {:ok, _} = start_supervised({ProjectNodeSupervisor, project}) {:ok, _, _} = RemoteControl.start_link(project) @@ -54,26 +48,6 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do RemoteControl.Api.schedule_compile(project, true) assert_receive project_compiled(), 5000 - # ETS - Backends.Ets.destroy_all(project) - RemoteControl.set_project(project) - - start_supervised!({Document.Store, derive: [analysis: &Lexical.Ast.analyze/1]}) - - start_supervised!(RemoteControl.Dispatch) - start_supervised!(Backends.Ets) - - start_supervised!( - {Search.Store, [project, fn _ -> {:ok, []} end, fn _, _ -> {:ok, [], []} end, Backends.Ets]} - ) - - Search.Store.enable() - assert_eventually Search.Store.loaded?(), 1500 - - on_exit(fn -> - Backends.Ets.destroy_all(project) - end) - %{project: project} end @@ -84,8 +58,6 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do on_exit(fn -> :ok = Document.Store.close(uri) end) - - %{subject_uri: uri} end describe "definition/2 when making remote call by alias" do @@ -102,9 +74,7 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do end ] - assert {:ok, ^referenced_uri, definition_line} = - definition(project, subject_module, referenced_uri) - + assert {:ok, ^referenced_uri, definition_line} = definition(project, subject_module) assert definition_line == ~S[ def «greet»(name) do] end @@ -119,29 +89,10 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do end ] - assert {:ok, ^referenced_uri, definition_line} = - definition(project, subject_module, referenced_uri) - + assert {:ok, ^referenced_uri, definition_line} = definition(project, subject_module) assert definition_line == ~S[defmodule «MyDefinition» do] end - test "find the definition of a struct", %{project: project, uri: referenced_uri} do - subject_module = ~q[ - defmodule UsesRemoteStruct do - alias MyDefinition - - def uses_struct() do - %|MyDefinition{} - end - end - ] - - assert {:ok, ^referenced_uri, definition_line} = - definition(project, subject_module, referenced_uri) - - assert definition_line == " «defstruct [:field, another_field: nil]»" - end - test "find the macro definition", %{project: project, uri: referenced_uri} do subject_module = ~q[ defmodule UsesRemoteFunction do @@ -153,16 +104,11 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do end ] - assert {:ok, ^referenced_uri, definition_line} = - definition(project, subject_module, referenced_uri) - + assert {:ok, ^referenced_uri, definition_line} = definition(project, subject_module) assert definition_line == ~S[ defmacro «print_hello» do] end - test "find the right arity function definition", %{ - project: project, - uri: referenced_uri - } do + test "find the right arity function definition", %{project: project} do subject_module = ~q[ defmodule UsesRemoteFunction do alias MultiArity @@ -173,7 +119,7 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do end ] - {:ok, referenced_uri, definition_line} = definition(project, subject_module, referenced_uri) + {:ok, referenced_uri, definition_line} = definition(project, subject_module) assert definition_line == ~S[ def «sum»(a, b, c) do] assert referenced_uri =~ "navigations/lib/multi_arity.ex" @@ -194,9 +140,7 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do end ] - assert {:ok, ^referenced_uri, definition_line} = - definition(project, subject_module, referenced_uri) - + assert {:ok, ^referenced_uri, definition_line} = definition(project, subject_module) assert definition_line == ~S[ def «greet»(name) do] end @@ -212,9 +156,7 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do end ] - assert {:ok, ^referenced_uri, definition_line} = - definition(project, subject_module, referenced_uri) - + assert {:ok, ^referenced_uri, definition_line} = definition(project, subject_module) assert definition_line == ~S[ defmacro «print_hello» do] end end @@ -233,9 +175,7 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do end ] - assert {:ok, ^referenced_uri, definition_line} = - definition(project, subject_module, referenced_uri) - + assert {:ok, ^referenced_uri, definition_line} = definition(project, subject_module) assert definition_line == ~S[ def «greet»(name) do] end @@ -260,38 +200,13 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do end ] - assert {:ok, ^referenced_uri, definition_line} = - definition(project, subject_module, referenced_uri) - + assert {:ok, ^referenced_uri, definition_line} = definition(project, subject_module) assert definition_line == ~S[ def «hello_func_in_using» do] end end describe "definition/2 when making local call" do - test "find multiple locations when the module is defined in multiple places", %{ - project: project, - subject_uri: subject_uri - } do - subject_module = ~q[ - defmodule MyModule do # line 1 - end - - defmodule MyModule do # line 4 - end - - defmodule UsesMyModule do - |MyModule - end - ] - - {:ok, [{_, definition_line1}, {_, definition_line4}]} = - definition(project, subject_module, subject_uri) - - assert definition_line1 == ~S[defmodule «MyModule» do # line 1] - assert definition_line4 == ~S[defmodule «MyModule» do # line 4] - end - - test "find the function definition", %{project: project, subject_uri: subject_uri} do + test "find the function definition", %{project: project} do subject_module = ~q[ defmodule UsesOwnFunction do def greet do @@ -303,15 +218,14 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do end ] - {:ok, referenced_uri, definition_line} = definition(project, subject_module, subject_uri) + {:ok, referenced_uri, definition_line} = definition(project, subject_module) assert definition_line == ~S[ def «greet» do] assert referenced_uri =~ "navigations/lib/my_module.ex" end test "find the function definition when the function has `when` clause", %{ - project: project, - subject_uri: subject_uri + project: project } do subject_module = ~q[ defmodule UsesOwnFunction do @@ -324,13 +238,13 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do end ] - {:ok, referenced_uri, definition_line} = definition(project, subject_module, subject_uri) + {:ok, referenced_uri, definition_line} = definition(project, subject_module) assert definition_line == ~S[ def «greet»(name) when is_binary(name) do] assert referenced_uri =~ "navigations/lib/my_module.ex" end - test "find the attribute", %{project: project, subject_uri: subject_uri} do + test "find the attribute", %{project: project} do subject_module = ~q[ defmodule UsesAttribute do @b 2 @@ -341,13 +255,13 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do end ] - {:ok, referenced_uri, definition_line} = definition(project, subject_module, subject_uri) + {:ok, referenced_uri, definition_line} = definition(project, subject_module) assert definition_line =~ ~S[«@b» 2] assert referenced_uri =~ "navigations/lib/my_module.ex" end - test "find the variable", %{project: project, subject_uri: subject_uri} do + test "find the variable", %{project: project} do subject_module = ~q[ defmodule UsesVariable do def use_variable do @@ -360,7 +274,7 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do end ] - {:ok, referenced_uri, definition_line} = definition(project, subject_module, subject_uri) + {:ok, referenced_uri, definition_line} = definition(project, subject_module) assert definition_line =~ ~S[«a» = 1] assert referenced_uri =~ "navigations/lib/my_module.ex" @@ -373,51 +287,35 @@ defmodule Lexical.RemoteControl.CodeIntelligence.DefinitionTest do """ @tag :skip test "find the definition when calling a Elixir std module function", - %{project: project, subject_uri: subject_uri} do + %{project: project} do subject_module = ~q[ String.to_intege|r("1") ] - {:ok, uri, definition_line} = definition(project, subject_module, subject_uri) + {:ok, uri, definition_line} = definition(project, subject_module) assert uri =~ "lib/elixir/lib/string.ex" assert definition_line =~ ~S[ def «to_integer»(string) when is_binary(string) do] end - test "find the definition when calling a erlang module", %{ - project: project, - subject_uri: subject_uri - } do + test "find the definition when calling a erlang module", %{project: project} do subject_module = ~q[ :erlang.binary_to_ato|m("1") ] - {:ok, uri, definition_line} = definition(project, subject_module, subject_uri) + {:ok, uri, definition_line} = definition(project, subject_module) assert uri =~ "/src/erlang.erl" assert definition_line =~ ~S[«binary_to_atom»(Binary)] end end - defp definition(project, code, referenced_uri) do + defp definition(project, code) do with {position, code} <- pop_cursor(code), {:ok, document} <- subject_module(project, code), - :ok <- index(referenced_uri), - {:ok, location} <- + {:ok, %Location{} = location} <- RemoteControl.Api.definition(project, document, position) do - if is_list(location) do - {:ok, Enum.map(location, &{&1.document.uri, decorate(&1.document, &1.range)})} - else - {:ok, location.document.uri, decorate(location.document, location.range)} - end - end - end - - defp index(referenced_uri) do - with {:ok, document} <- Document.Store.fetch(referenced_uri), - {:ok, entries} <- - Search.Indexer.Source.index(document.path, Document.to_string(document)) do - Search.Store.replace(entries) + {:ok, location.document.uri, decorate(location.document, location.range)} end end end diff --git a/apps/server/lib/lexical/server/provider/handlers/go_to_definition.ex b/apps/server/lib/lexical/server/provider/handlers/go_to_definition.ex index ac2ad201c..dfe9e0d4e 100644 --- a/apps/server/lib/lexical/server/provider/handlers/go_to_definition.ex +++ b/apps/server/lib/lexical/server/provider/handlers/go_to_definition.ex @@ -12,7 +12,7 @@ defmodule Lexical.Server.Provider.Handlers.GoToDefinition do {:error, reason} -> Logger.error("GoToDefinition failed: #{inspect(reason)}") - {:reply, Responses.GoToDefinition.error(request.id, :request_failed, inspect(reason))} + {:error, Responses.GoToDefinition.error(request.id, :request_failed, inspect(reason))} end end end diff --git a/apps/server/test/lexical/server/provider/handlers/go_to_definition_test.exs b/apps/server/test/lexical/server/provider/handlers/go_to_definition_test.exs index 5d1c38450..f9d5ec113 100644 --- a/apps/server/test/lexical/server/provider/handlers/go_to_definition_test.exs +++ b/apps/server/test/lexical/server/provider/handlers/go_to_definition_test.exs @@ -15,7 +15,7 @@ defmodule Lexical.Server.Provider.Handlers.GoToDefinitionTest do use ExUnit.Case, async: false setup_all do - start_supervised!(Server.Application.document_store_child_spec()) + start_supervised(Document.Store) project = project(:navigations) {:ok, _} = start_supervised({DynamicSupervisor, Server.Project.Supervisor.options()}) @@ -61,6 +61,11 @@ defmodule Lexical.Server.Provider.Handlers.GoToDefinitionTest do {:ok, request} = build_request(uses_file_path, 4, 17) {:reply, %{result: %Location{} = location}} = handle(request, project) + + assert location.range.start.line == 15 + assert location.range.start.character == 7 + assert location.range.end.line == 15 + assert location.range.end.character == 12 assert Location.uri(location) == referenced_uri end end