Skip to content

Commit 22ee2da

Browse files
authored
Cherry pick upstream changes (#19)
* Handle out-of-spec diagnostic positions without crashing * Show warning when launching with an Elixir version <= 1.7 * Fixes a bug in dependency loading in Elixir 1.9 and fixes bug causing builds to fail permanently after an invalid dep specification Mix.Dep.loaded/1 was removed in Elixir 1.9. This was also a problem in the mix_task_archive_deps dependency we use in the release task, so I've updated a fork of that repo and am sending a PR upstream. Also, checking cached deps to look for changed deps can fail, so we now rescue those failures. Fixes #155 * Bumped required Elixir version (for both use and development) to 1.7.0 because of Mix.Dep.load_on_environment/1 requirement * Change Dialyzer's `analyze` message to be a GenServer notification instead of request and grab build lock while stale-checking beams Up till now, the reason that the `analyze` is triggered with a GenServer `call` instead of `cast` is just so that a build doesn't happen concurrently (since the build can delete beam files while the Dialyzer server tries to stale-check them). There are other places where the global state changes caused by builds are a problem too, and we added a global "build lock" that processes can grab to avoid this sort of thing. I'm turning "analyze" into a GenServer cast, which allows the main language server to continue servicing requests. The Dialyzer server will grab the build lock while it stale-checks the beam files so it only blocks builds, not the main language server. This also makes it more robust because an exception or exit during analyze won't kill the main language server and the supervisor can restart the Dialyzer server. * Update elixir version to still be valid
1 parent b5aa32c commit 22ee2da

File tree

10 files changed

+55
-47
lines changed

10 files changed

+55
-47
lines changed

.tool-versions

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
elixir 1.6.6-otp-20
2-
erlang 20.2.4
1+
elixir 1.7.4-otp-21
2+
erlang 21.2.4

README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ The Elixir Language Server provides a server that runs in the background, provid
77
- Debugger support (requires Erlang >= OTP 19)
88
- Automatic, incremental Dialyzer analysis (requires Erlang OTP 20)
99
- Automatic inline suggestion of @specs based on Dialyzer's inferred success typings
10-
- Inline reporting of build warnings and errors (requires Elixir >= 1.6)
10+
- Inline reporting of build warnings and errors
1111
- Documentation lookup on hover
1212
- Go-to-definition
1313
- Code completion
14-
- Code formatter (requries Elixir >= 1.6)
14+
- Code formatter
1515
- Find references to functions and modules (Thanks to @mattbaker)
1616
- Quick symbol lookup in file (Thanks to @mattbaker)
1717

@@ -21,8 +21,7 @@ The Elixir Language Server provides a server that runs in the background, provid
2121

2222
Elixir:
2323

24-
- 1.6.0 minimum
25-
- \>= 1.6.6 recommended
24+
- 1.7.0 minimum
2625

2726
Erlang:
2827

apps/debugger/mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ defmodule ElixirLS.Debugger.Mixfile do
99
config_path: "config/config.exs",
1010
deps_path: "../../deps",
1111
lockfile: "../../mix.lock",
12-
elixir: ">= 1.6.5",
12+
elixir: ">= 1.7.0",
1313
build_embedded: false,
1414
start_permanent: true,
1515
build_per_environment: false,

apps/elixir_ls_utils/mix.exs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ defmodule ElixirLS.Utils.Mixfile do
1010
deps_path: "../../deps",
1111
elixirc_paths: ["lib", "test/support"],
1212
lockfile: "../../mix.lock",
13-
elixir: ">= 1.6.5",
13+
elixir: ">= 1.7.0",
1414
build_embedded: false,
1515
start_permanent: false,
1616
build_per_environment: false,
@@ -41,6 +41,6 @@ defmodule ElixirLS.Utils.Mixfile do
4141
#
4242
# Type "mix help deps" for more examples and options
4343
defp deps do
44-
[{:jason, "~> 1.0"}, {:mix_task_archive_deps, "~> 0.4.0"}]
44+
[{:jason, "~> 1.0"}, {:mix_task_archive_deps, github: "JakeBecker/mix_task_archive_deps"}]
4545
end
4646
end

apps/language_server/lib/language_server/build.ex

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ defmodule ElixirLS.LanguageServer.Build do
1313
:timer.tc(fn ->
1414
IO.puts("Compiling with Mix env #{Mix.env()}")
1515

16-
prev_deps = Mix.Dep.loaded([])
17-
clear_deps_cache()
16+
prev_deps = cached_deps()
17+
Mix.Dep.clear_cached()
1818

1919
case reload_project() do
2020
{:ok, mixfile_diagnostics} ->
21-
if fetch_deps? and Mix.Dep.loaded([]) != prev_deps, do: fetch_deps()
21+
if fetch_deps? and Mix.Dep.load_on_environment([]) != prev_deps,
22+
do: fetch_deps()
23+
2224
{status, diagnostics} = compile()
2325
Server.build_finished(parent, {status, mixfile_diagnostics ++ diagnostics})
2426

@@ -171,13 +173,18 @@ defmodule ElixirLS.LanguageServer.Build do
171173
end
172174
end
173175

174-
defp clear_deps_cache do
175-
Mix.ProjectStack.write_cache({:cached_deps, Mix.env(), Mix.Project.get()}, nil)
176+
defp cached_deps do
177+
try do
178+
Mix.Dep.cached()
179+
rescue
180+
_ ->
181+
[]
182+
end
176183
end
177184

178185
defp fetch_deps do
179186
missing_deps =
180-
Mix.Dep.loaded([])
187+
Mix.Dep.load_on_environment([])
181188
|> Enum.filter(fn %Mix.Dep{status: status} ->
182189
case status do
183190
{:unavailable, _} -> true
@@ -227,11 +234,11 @@ defmodule ElixirLS.LanguageServer.Build do
227234
}
228235
end
229236

230-
defp range(nil, nil) do
237+
defp range(_, nil) do
231238
%{"start" => %{"line" => 0, "character" => 0}, "end" => %{"line" => 0, "character" => 0}}
232239
end
233240

234-
defp range(nil, source_file) do
241+
defp range(_, source_file) do
235242
SourceFile.full_range(source_file)
236243
end
237244
end

apps/language_server/lib/language_server/dialyzer.ex

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ defmodule ElixirLS.LanguageServer.Dialyzer do
6464
end
6565

6666
def analyze(parent \\ self(), build_ref, warn_opts) do
67-
GenServer.call({:global, {parent, __MODULE__}}, {:analyze, build_ref, warn_opts}, :infinity)
67+
GenServer.cast({:global, {parent, __MODULE__}}, {:analyze, build_ref, warn_opts})
6868
end
6969

7070
def analysis_finished(server, status, active_plt, mod_deps, md5, warnings, timestamp, build_ref) do
@@ -144,35 +144,37 @@ defmodule ElixirLS.LanguageServer.Dialyzer do
144144
{:reply, :ok, state}
145145
end
146146

147-
def handle_call({:analyze, build_ref, warn_opts}, _from, state) do
147+
def handle_call({:suggest_contracts, files}, _from, %{plt: plt} = state) do
148+
specs = if is_nil(plt), do: [], else: SuccessTypings.suggest_contracts(plt, files)
149+
{:reply, specs, state}
150+
end
151+
152+
def handle_cast({:analyze, build_ref, warn_opts}, state) do
148153
state =
149-
if Mix.Project.get() do
150-
JsonRpc.log_message(:info, "[ElixirLS Dialyzer] Checking for stale beam files")
151-
new_timestamp = adjusted_timestamp()
154+
ElixirLS.LanguageServer.Build.with_build_lock(fn ->
155+
if Mix.Project.get() do
156+
JsonRpc.log_message(:info, "[ElixirLS Dialyzer] Checking for stale beam files")
157+
new_timestamp = adjusted_timestamp()
152158

153-
{removed_files, file_changes} =
154-
update_stale(state.md5, state.removed_files, state.file_changes, state.timestamp)
159+
{removed_files, file_changes} =
160+
update_stale(state.md5, state.removed_files, state.file_changes, state.timestamp)
155161

156-
state = %{
157-
state
158-
| warn_opts: warn_opts,
159-
timestamp: new_timestamp,
160-
removed_files: removed_files,
161-
file_changes: file_changes,
162-
build_ref: build_ref
163-
}
164-
165-
trigger_analyze(state)
166-
else
167-
state
168-
end
162+
state = %{
163+
state
164+
| warn_opts: warn_opts,
165+
timestamp: new_timestamp,
166+
removed_files: removed_files,
167+
file_changes: file_changes,
168+
build_ref: build_ref
169+
}
169170

170-
{:reply, :ok, state}
171-
end
171+
trigger_analyze(state)
172+
else
173+
state
174+
end
175+
end)
172176

173-
def handle_call({:suggest_contracts, files}, _from, %{plt: plt} = state) do
174-
specs = if is_nil(plt), do: [], else: SuccessTypings.suggest_contracts(plt, files)
175-
{:reply, specs, state}
177+
{:noreply, state}
176178
end
177179

178180
def handle_info({:"ETS-TRANSFER", _, _, _}, state) do

apps/language_server/lib/language_server/server.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -552,10 +552,10 @@ defmodule ElixirLS.LanguageServer.Server do
552552
end
553553

554554
defp show_version_warnings do
555-
unless Version.match?(System.version(), ">= 1.6.0") do
555+
unless Version.match?(System.version(), ">= 1.7.0") do
556556
JsonRpc.show_message(
557557
:warning,
558-
"Elixir versions below 1.6 are not supported. (Currently v#{System.version()})"
558+
"Elixir versions below 1.7 are not supported. (Currently v#{System.version()})"
559559
)
560560
end
561561

apps/language_server/mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ defmodule ElixirLS.LanguageServer.Mixfile do
55
[
66
app: :language_server,
77
version: "0.2.24",
8-
elixir: ">= 1.6.5",
8+
elixir: ">= 1.7.0",
99
build_path: "../../_build",
1010
config_path: "config/config.exs",
1111
deps_path: "../../deps",

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ defmodule ElixirLS.Mixfile do
88
start_permanent: Mix.env() == :prod,
99
build_per_environment: false,
1010
deps: deps(),
11-
elixir: ">= 1.6.0-dev"
11+
elixir: ">= 1.7.0"
1212
]
1313
end
1414

mix.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"logger_file_backend": {:hex, :logger_file_backend, "0.0.9", "5c2f7d4a28431e695cdf94d191523dbafe609321a67bb654254897f546c393db", [:mix], []},
2020
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], []},
2121
"mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], []},
22-
"mix_task_archive_deps": {:hex, :mix_task_archive_deps, "0.4.0", "95cf15d1b04e10c6319e16a82b88109db2e8164f63e733c1742dfaf8ed9cace5", [:mix], [], "hexpm"},
22+
"mix_task_archive_deps": {:git, "https://github.com/JakeBecker/mix_task_archive_deps.git", "0f71e526e53c96626df80b03d595c58d616f363f", []},
2323
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
2424
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], []},
2525
}

0 commit comments

Comments
 (0)