Skip to content

Commit 5ac0190

Browse files
committed
reuse once loaded PLT
properly clean up PLT when a new one is loaded
1 parent 59040c4 commit 5ac0190

File tree

2 files changed

+37
-23
lines changed

2 files changed

+37
-23
lines changed

apps/language_server/lib/language_server/dialyzer/manifest.ex

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,7 @@ defmodule ElixirLS.LanguageServer.Dialyzer.Manifest do
227227
])
228228
end
229229

230-
defp transfer_plt(active_plt, pid) do
231-
# FIXME: matching against opaque type
230+
def transfer_plt(active_plt, pid) do
232231
plt(
233232
info: info,
234233
types: types,

apps/language_server/lib/language_server/dialyzer_incremental.ex

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ defmodule ElixirLS.LanguageServer.DialyzerIncremental do
1414
:warning_format,
1515
:apps_paths,
1616
:project_dir,
17-
:next_build
17+
:next_build,
18+
:plt
1819
]
1920

2021
Record.defrecordp(:iplt_info, [
@@ -95,11 +96,9 @@ defmodule ElixirLS.LanguageServer.DialyzerIncremental do
9596
end
9697

9798
@impl GenServer
98-
def handle_call({:suggest_contracts, files}, _from, state) do
99+
def handle_call({:suggest_contracts, files}, _from, state = %{plt: plt}) when plt != nil do
99100
specs =
100101
try do
101-
# TODO maybe store plt in state?
102-
plt = :dialyzer_iplt.from_file(elixir_incremental_plt_path())
103102
SuccessTypings.suggest_contracts(plt, files)
104103
catch
105104
:throw = kind, {:dialyzer_error, message} = payload ->
@@ -145,10 +144,15 @@ defmodule ElixirLS.LanguageServer.DialyzerIncremental do
145144

146145
{opts, warning_modules_to_apps} = build_dialyzer_opts()
147146

147+
if state.plt do
148+
:dialyzer_plt.delete(state.plt)
149+
end
150+
148151
{:ok, pid} =
149152
Task.start_link(fn ->
150-
warnings = do_analyze(opts, warning_modules_to_apps)
151-
send(parent, {:analysis_finished, warnings, build_ref})
153+
{warnings, plt} = do_analyze(opts, warning_modules_to_apps)
154+
Manifest.transfer_plt(plt, parent)
155+
send(parent, {:analysis_finished, warnings, build_ref, plt})
152156
end)
153157

154158
%{
@@ -157,7 +161,8 @@ defmodule ElixirLS.LanguageServer.DialyzerIncremental do
157161
warning_format: warning_format,
158162
apps_paths: apps_paths,
159163
project_dir: project_dir,
160-
analysis_pid: pid
164+
analysis_pid: pid,
165+
plt: nil
161166
}
162167
else
163168
state
@@ -175,7 +180,7 @@ defmodule ElixirLS.LanguageServer.DialyzerIncremental do
175180

176181
@impl GenServer
177182
def handle_info(
178-
{:analysis_finished, warnings_map, build_ref},
183+
{:analysis_finished, warnings_map, build_ref, plt},
179184
state
180185
) do
181186
diagnostics =
@@ -188,14 +193,21 @@ defmodule ElixirLS.LanguageServer.DialyzerIncremental do
188193
)
189194

190195
Server.dialyzer_finished(state.parent, diagnostics, build_ref)
191-
state = %{state | analysis_pid: nil}
196+
state = %{state | analysis_pid: nil, plt: plt}
192197

193198
case state.next_build do
194199
nil -> {:noreply, state}
195200
msg -> handle_cast(msg, %{state | next_build: nil})
196201
end
197202
end
198203

204+
def handle_info(
205+
{:"ETS-TRANSFER", _, _, _},
206+
state
207+
) do
208+
{:noreply, state}
209+
end
210+
199211
defp build_dialyzer_opts() do
200212
# assume that all required apps has been loaded during build
201213
# notable exception is erts which is not loaded by default but we load it manually during startup
@@ -326,7 +338,7 @@ defmodule ElixirLS.LanguageServer.DialyzerIncremental do
326338
# warnings returned by dialyzer public api are stripped to https://www.erlang.org/doc/man/dialyzer#type-dial_warning
327339
# file paths are app relative but we need to know which umbrella app they come from
328340
# we load PLT info directly and read raw warnings
329-
{us, {_dialyzer_plt, plt_info}} =
341+
{us, {dialyzer_plt, plt_info}} =
330342
:timer.tc(fn ->
331343
:dialyzer_iplt.plt_and_info_from_file(elixir_incremental_plt_path())
332344
end)
@@ -335,17 +347,20 @@ defmodule ElixirLS.LanguageServer.DialyzerIncremental do
335347

336348
iplt_info(warning_map: warning_map) = plt_info
337349
# filter by modules from project app/umbrella apps
338-
warning_map
339-
|> Map.take(Map.keys(warning_modules_to_apps))
340-
|> Enum.group_by(
341-
fn {module, _warnings} ->
342-
Map.fetch!(warning_modules_to_apps, module)
343-
end,
344-
fn {module, warnings} ->
345-
# raw warnings may be duplicated
346-
{module, Enum.uniq(warnings)}
347-
end
348-
)
350+
warnings =
351+
warning_map
352+
|> Map.take(Map.keys(warning_modules_to_apps))
353+
|> Enum.group_by(
354+
fn {module, _warnings} ->
355+
Map.fetch!(warning_modules_to_apps, module)
356+
end,
357+
fn {module, warnings} ->
358+
# raw warnings may be duplicated
359+
{module, Enum.uniq(warnings)}
360+
end
361+
)
362+
363+
{warnings, dialyzer_plt}
349364
catch
350365
:throw = kind, {:dialyzer_error, message} = payload ->
351366
{_payload, stacktrace} = Exception.blame(kind, payload, __STACKTRACE__)

0 commit comments

Comments
 (0)