Skip to content

Refactor token lookup logic #1183

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ defmodule ElixirLS.LanguageServer.Providers.Declaration.Locator do
alias ElixirLS.LanguageServer.Location
alias ElixirSense.Core.Parser
alias ElixirSense.Core.State.{ModFunInfo, SpecInfo}

require ElixirSense.Core.Introspection, as: Introspection
alias ElixirLS.LanguageServer.Providers.LocatorUtils

@doc """
Finds the declaration (callback or protocol definition) for the function under the cursor.
Expand All @@ -28,26 +29,23 @@ defmodule ElixirLS.LanguageServer.Providers.Declaration.Locator do
Returns either a single `%Location{}` or a list of locations if multiple declarations are found.
"""
def declaration(code, line, column, options \\ []) do
case NormalizedCode.Fragment.surround_context(code, {line, column}) do
:none ->
case LocatorUtils.build(code, line, column, options) do
nil ->
nil

context ->
metadata =
Keyword.get_lazy(options, :metadata, fn ->
Parser.parse_string(code, true, false, {line, column})
end)

env = Metadata.get_cursor_env(metadata, {line, column}, {context.begin, context.end})
find(context, env, metadata)
info ->
find(info)
end
end

@doc false
def find(context, %State.Env{module: module} = env, metadata) do
binding_env = Binding.from_env(env, metadata, context.begin)

type = SurroundContext.to_binding(context.context, module)
def find(%{
context: context,
env: %State.Env{module: module} = env,
metadata: metadata,
binding_env: binding_env,
type: type
}) do

case type do
nil ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,47 +25,29 @@ defmodule ElixirLS.LanguageServer.Providers.Definition.Locator do

alias ElixirLS.LanguageServer.Plugins.Phoenix.Scope
alias ElixirSense.Core.Normalized.Code, as: NormalizedCode
alias ElixirLS.LanguageServer.Providers.LocatorUtils

def definition(code, line, column, options \\ []) do
case NormalizedCode.Fragment.surround_context(code, {line, column}) do
:none ->
case LocatorUtils.build(code, line, column, options) do
nil ->
nil

context ->
metadata =
Keyword.get_lazy(options, :metadata, fn ->
Parser.parse_string(code, true, false, {line, column})
end)

env = Metadata.get_cursor_env(metadata, {line, column}, {context.begin, context.end})

find(
context,
env,
metadata
)
info ->
find(info)
end
end

@doc """
Finds out where a module, function, macro or variable was defined.
"""
@spec find(
any(),
State.Env.t(),
Metadata.t()
) :: %Location{} | nil
def find(
context,
%State.Env{
module: module,
attributes: attributes
} = env,
metadata
) do
binding_env = Binding.from_env(env, metadata, context.begin)

type = SurroundContext.to_binding(context.context, module)
@spec find(LocatorUtils.t()) :: %Location{} | nil
def find(%{
context: context,
env: %State.Env{module: module, attributes: attributes} = env,
metadata: metadata,
binding_env: binding_env,
type: type
}) do

case type do
nil ->
Expand Down
32 changes: 12 additions & 20 deletions apps/language_server/lib/language_server/providers/hover/docs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ defmodule ElixirLS.LanguageServer.Providers.Hover.Docs do
alias ElixirSense.Core.TypeInfo
alias ElixirSense.Core.Parser
alias ElixirSense.Core.Source
alias ElixirLS.LanguageServer.Providers.LocatorUtils

@type markdown :: String.t()

Expand Down Expand Up @@ -71,20 +72,12 @@ defmodule ElixirLS.LanguageServer.Providers.Hover.Docs do
|> Kernel.--([:exception, :message])

def docs(code, line, column, options \\ []) do
case NormalizedCode.Fragment.surround_context(code, {line, column}) do
:none ->
case LocatorUtils.build(code, line, column, options) do
nil ->
nil

%{begin: begin_pos, end: end_pos} = context ->
metadata =
Keyword.get_lazy(options, :metadata, fn ->
Parser.parse_string(code, true, false, {line, column})
end)

env =
Metadata.get_cursor_env(metadata, {line, column}, {begin_pos, end_pos})

case all(context, env, metadata) do
%{context: %{begin: begin_pos, end: end_pos}} = info ->
case all(info) do
[] ->
nil

Expand All @@ -100,16 +93,15 @@ defmodule ElixirLS.LanguageServer.Providers.Hover.Docs do
end
end

defp all(
context,
%State.Env{
defp all(%{
context: context,
env: %State.Env{
module: module
} = env,
metadata
) do
binding_env = Binding.from_env(env, metadata, context.begin)

type = SurroundContext.to_binding(context.context, module)
metadata: metadata,
binding_env: binding_env,
type: type
}) do

case type do
nil ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,48 +19,31 @@ defmodule ElixirLS.LanguageServer.Providers.Implementation.Locator do
alias ElixirLS.LanguageServer.Location
alias ElixirSense.Core.Parser
alias ElixirSense.Core.Normalized.Code, as: NormalizedCode
alias ElixirLS.LanguageServer.Providers.LocatorUtils

require ElixirSense.Core.Introspection, as: Introspection

def implementations(code, line, column, options \\ []) do
case NormalizedCode.Fragment.surround_context(code, {line, column}) do
:none ->
case LocatorUtils.build(code, line, column, options) do
nil ->
[]

context ->
metadata =
Keyword.get_lazy(options, :metadata, fn ->
Parser.parse_string(code, true, false, {line, column})
end)

env = Metadata.get_cursor_env(metadata, {line, column}, {context.begin, context.end})

find(
context,
env,
metadata
)
info ->
find(info)
end
end

@doc """
Finds out where a callback, protocol or delegate was implemented.
"""
@spec find(
any(),
State.Env.t(),
Metadata.t()
) :: [%Location{}]
def find(
context,
%State.Env{
module: module
} = env,
metadata
) do
binding_env = Binding.from_env(env, metadata, context.begin)

type = SurroundContext.to_binding(context.context, module)
@spec find(LocatorUtils.t()) :: [%Location{}]
def find(%{
context: context,
env: %State.Env{module: module} = env,
metadata: metadata,
binding_env: binding_env,
type: type
}) do

case type do
nil ->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
defmodule ElixirLS.LanguageServer.Providers.LocatorUtils do
@moduledoc """
Helper for providers resolving symbols at a given cursor position.
"""

alias ElixirSense.Core.{Binding, Metadata, Parser, SurroundContext}
alias ElixirSense.Core.Normalized.Code, as: NormalizedCode

@type t :: %{
context: map(),
env: Metadata.t(),
metadata: Metadata.t(),
binding_env: any(),
type: any()
}

@spec build(String.t(), pos_integer, pos_integer, keyword()) :: t | nil
def build(code, line, column, options \\ []) do
case NormalizedCode.Fragment.surround_context(code, {line, column}) do
:none ->
nil

context ->
metadata =
Keyword.get_lazy(options, :metadata, fn ->
Parser.parse_string(code, true, false, {line, column})
end)

env = Metadata.get_cursor_env(metadata, {line, column}, {context.begin, context.end})

%{
context: context,
env: env,
metadata: metadata,
binding_env: Binding.from_env(env, metadata, context.begin),
type: SurroundContext.to_binding(context.context, env.module)
}
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -19,37 +19,16 @@ defmodule ElixirLS.LanguageServer.Providers.References.Locator do
alias ElixirSense.Core.SurroundContext
alias ElixirSense.Core.Parser
alias ElixirSense.Core.Source
alias ElixirLS.LanguageServer.Providers.LocatorUtils

def references(code, line, column, trace, options \\ []) do
case NormalizedCode.Fragment.surround_context(code, {line, column}) do
:none ->
case LocatorUtils.build(code, line, column, options) do
nil ->
[]

context ->
metadata =
Keyword.get_lazy(options, :metadata, fn ->
Parser.parse_string(code, true, false, {line, column})
end)

# if context is var try to find env by scope_id
# find scopes that contain this variable

env =
%State.Env{
module: module
} =
Metadata.get_cursor_env(metadata, {line, column}, {context.begin, context.end})

# find last env of current module
attributes = get_attributes(metadata, module)

find(
context,
env,
attributes,
metadata,
trace
)
info ->
attributes = get_attributes(info.metadata, info.env.module)
find(Map.put(info, :attributes, attributes), trace)
|> Enum.uniq()
end
end
Expand All @@ -73,23 +52,21 @@ defmodule ElixirLS.LanguageServer.Providers.References.Locator do
range: range
}

def find(
context,
%State.Env{
def find(%{
context: context,
env: %State.Env{
aliases: aliases,
module: module
} = env,
attributes,
%Metadata{
metadata: %Metadata{
mods_funs_to_positions: mods_funs,
calls: calls,
types: metadata_types
} = metadata,
trace
) do
binding_env = Binding.from_env(env, metadata, context.begin)

type = SurroundContext.to_binding(context.context, module)
binding_env: binding_env,
type: type,
attributes: attributes
}, trace) do

refs_for_mod_fun = fn {mod, function} ->
actual =
Expand Down
Loading