From 3731b6a3f688cb646dfa770e7fcf8181ee3fc891 Mon Sep 17 00:00:00 2001 From: Lukasz Samson Date: Thu, 29 Aug 2024 23:23:41 +0200 Subject: [PATCH] correctly handle var versioning --- lib/elixir_sense/core/compiler.ex | 7 +++--- lib/elixir_sense/core/metadata_builder.ex | 27 ++++++++++------------- lib/elixir_sense/core/state.ex | 17 +++++++++++--- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/lib/elixir_sense/core/compiler.ex b/lib/elixir_sense/core/compiler.ex index 2679b218..e882b487 100644 --- a/lib/elixir_sense/core/compiler.ex +++ b/lib/elixir_sense/core/compiler.ex @@ -1499,8 +1499,6 @@ defmodule ElixirSense.Core.Compiler do |> new_vars_scope |> new_attributes_scope - # TODO magic with ElixirEnv instead of new_vars_scope? - {state, _env} = maybe_add_protocol_behaviour(state, %{env | module: full}) {_result, state, e_env} = expand(block, state, %{env | module: full}) @@ -1535,9 +1533,10 @@ defmodule ElixirSense.Core.Compiler do end) # restore vars from outer scope + # restore version counter state = state |> apply_optional_callbacks(%{env | module: full}) - |> remove_vars_scope(state_orig) + |> remove_vars_scope(state_orig, true) |> remove_attributes_scope |> remove_module @@ -1633,6 +1632,8 @@ defmodule ElixirSense.Core.Compiler do {_e_args, state, env_for_expand} = expand_args(args, %{state | prematch: {%{}, 0, :none}}, %{env_for_expand | context: :match}) + # TODO expand defaults + {e_guard, state, env_for_expand} = __MODULE__.Clauses.guard( guards, diff --git a/lib/elixir_sense/core/metadata_builder.ex b/lib/elixir_sense/core/metadata_builder.ex index 38ddec59..b8d94ee4 100644 --- a/lib/elixir_sense/core/metadata_builder.ex +++ b/lib/elixir_sense/core/metadata_builder.ex @@ -14,24 +14,21 @@ defmodule ElixirSense.Core.MetadataBuilder do """ @spec build(Macro.t(), nil | {pos_integer, pos_integer}) :: State.t() def build(ast, cursor_position \\ nil) do - {_ast, state, _env} = - Compiler.expand( - ast, - %State{ - cursor_position: cursor_position, - prematch: - if Version.match?(System.version(), ">= 1.15.0-dev") do - Code.get_compiler_option(:on_undefined_variable) - else - :warn - end - }, - Compiler.env() - ) + state_orig = %State{ + cursor_position: cursor_position, + prematch: + if Version.match?(System.version(), ">= 1.15.0-dev") do + Code.get_compiler_option(:on_undefined_variable) + else + :warn + end + } + + {_ast, state, _env} =Compiler.expand(ast, state_orig, Compiler.env()) state |> remove_attributes_scope - |> remove_vars_scope(%{vars: {%{}, false}}) + |> remove_vars_scope(state_orig) |> remove_module end diff --git a/lib/elixir_sense/core/state.ex b/lib/elixir_sense/core/state.ex index d9a4811c..a593d33a 100644 --- a/lib/elixir_sense/core/state.ex +++ b/lib/elixir_sense/core/state.ex @@ -810,6 +810,7 @@ defmodule ElixirSense.Core.State do scope_id_count: scope_id, vars_info: [%{} | state.vars_info], # elixir_ex entries + # each def starts versioning from 0 unused: 0, vars: {%{}, false} } @@ -819,9 +820,9 @@ defmodule ElixirSense.Core.State do %__MODULE__{state | attributes: [[] | state.attributes], scope_attributes: [[]]} end - def remove_vars_scope(%__MODULE__{} = state, %{vars: vars}) do + def remove_vars_scope(%__MODULE__{} = state, %{vars: vars, unused: unused}, restore_version_counter \\ false) do state = maybe_move_vars_to_outer_scope(state) - %__MODULE__{ + state = %__MODULE__{ state | scope_ids: tl(state.scope_ids), vars_info: tl(state.vars_info), @@ -829,9 +830,18 @@ defmodule ElixirSense.Core.State do # restore elixir_ex fields vars: vars } + + if restore_version_counter do + # this is used by defmodule as module body does not affect outside versioning + %__MODULE__{ + state + | unused: unused + } + else + state + end end - # TODO should we restore unused? def remove_func_vars_scope(%__MODULE__{} = state, %{vars: vars, unused: unused}) do %__MODULE__{ state @@ -840,6 +850,7 @@ defmodule ElixirSense.Core.State do vars_info_per_scope_id: update_vars_info_per_scope_id(state), # restore elixir_ex fields vars: vars, + # restore versioning unused: unused } end