@@ -297,6 +297,14 @@ defmodule ElixirLS.LanguageServer.Build do
297
297
end
298
298
299
299
defp purge_app ( app ) do
300
+ Logger . debug ( "Stopping #{ app } " )
301
+
302
+ case Application . stop ( app ) do
303
+ :ok -> :ok
304
+ { :error , { :not_started , _ } } -> :ok
305
+ { :error , error } -> Logger . warning ( "Application.stop failed for #{ app } : #{ inspect ( error ) } " )
306
+ end
307
+
300
308
modules =
301
309
case :application . get_key ( app , :modules ) do
302
310
{ :ok , modules } -> modules
@@ -310,31 +318,11 @@ defmodule ElixirLS.LanguageServer.Build do
310
318
311
319
Logger . debug ( "Unloading #{ app } " )
312
320
313
- case Application . stop ( app ) do
314
- :ok -> :ok
315
- { :error , :not_started } -> :ok
316
- { :error , error } -> Logger . warning ( "Application.stop failed for #{ app } : #{ inspect ( error ) } " )
317
- end
318
-
319
- lib_dir = :code . lib_dir ( app )
320
-
321
321
case Application . unload ( app ) do
322
322
:ok -> :ok
323
+ { :error , { :not_loaded , _ } } -> :ok
323
324
{ :error , error } -> Logger . warning ( "Application.unload failed for #{ app } : #{ inspect ( error ) } " )
324
325
end
325
-
326
- if is_list ( lib_dir ) do
327
- case :code . del_path ( :filename . join ( lib_dir , ~c" ebin" ) ) do
328
- true ->
329
- :ok
330
-
331
- false ->
332
- :ok
333
-
334
- { :error , reason } ->
335
- Logger . warning ( "Unable to clean code path for #{ app } : #{ inspect ( reason ) } " )
336
- end
337
- end
338
326
end
339
327
340
328
defp get_deps_by_app ( deps ) , do: get_deps_by_app ( deps , % { } )
@@ -396,16 +384,46 @@ defmodule ElixirLS.LanguageServer.Build do
396
384
cached_deps_by_app = get_deps_by_app ( cached_deps )
397
385
removed_apps = Map . keys ( cached_deps_by_app ) -- Map . keys ( current_deps_by_app )
398
386
399
- removed_deps = cached_deps_by_app |> Map . take ( removed_apps )
387
+ removed_deps =
388
+ cached_deps_by_app
389
+ |> Map . take ( removed_apps )
390
+ |> Enum . flat_map ( & elem ( & 1 , 1 ) )
391
+ |> Enum . uniq ( )
400
392
401
- for { _app , deps } <- removed_deps ,
402
- dep <- deps do
393
+ # purge removed dependencies
394
+ for dep <- removed_deps do
403
395
purge_dep ( dep )
404
396
end
405
397
398
+ # purge current dependencies in invalid state
406
399
for dep <- current_deps do
407
400
maybe_purge_dep ( dep )
408
401
end
402
+
403
+ mix_project_apps =
404
+ if Mix.Project . umbrella? ( ) do
405
+ Mix.Project . apps_paths ( ) |> Enum . map ( & elem ( & 1 , 0 ) )
406
+ else
407
+ # in umbrella Mix.Project.apps_paths() returns nil
408
+ # get app from config instead
409
+ [ Mix.Project . config ( ) [ :app ] ]
410
+ end
411
+
412
+ mix_project_apps_deps =
413
+ current_deps_by_app
414
+ |> Map . take ( mix_project_apps )
415
+ |> Enum . flat_map ( & elem ( & 1 , 1 ) )
416
+ |> Enum . uniq ( )
417
+
418
+ # purge mix project apps
419
+ # elixir compiler loads apps only on initial compilation
420
+ # on subsequent ones it does not update application controller state
421
+ # if we don't purge the apps we end up with invalid state
422
+ # e.g. :application.get_key(app, :modules) returns outdated module list
423
+ # see https://github.com/elixir-lang/elixir/issues/13001
424
+ for dep <- mix_project_apps_deps do
425
+ purge_dep ( dep )
426
+ end
409
427
end
410
428
411
429
defp fetch_deps ( current_deps ) do
@@ -462,7 +480,6 @@ defmodule ElixirLS.LanguageServer.Build do
462
480
options =
463
481
if Version . match? ( System . version ( ) , ">= 1.14.0" ) do
464
482
Keyword . merge ( options ,
465
- # we are running the server with consolidated protocols
466
483
# this disables warnings `X has already been consolidated`
467
484
# when running `compile` task
468
485
ignore_already_consolidated: true
0 commit comments