@@ -297,6 +297,14 @@ defmodule ElixirLS.LanguageServer.Build do
297297 end
298298
299299 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+
300308 modules =
301309 case :application . get_key ( app , :modules ) do
302310 { :ok , modules } -> modules
@@ -310,31 +318,11 @@ defmodule ElixirLS.LanguageServer.Build do
310318
311319 Logger . debug ( "Unloading #{ app } " )
312320
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-
321321 case Application . unload ( app ) do
322322 :ok -> :ok
323+ { :error , { :not_loaded , _ } } -> :ok
323324 { :error , error } -> Logger . warning ( "Application.unload failed for #{ app } : #{ inspect ( error ) } " )
324325 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
338326 end
339327
340328 defp get_deps_by_app ( deps ) , do: get_deps_by_app ( deps , % { } )
@@ -396,16 +384,46 @@ defmodule ElixirLS.LanguageServer.Build do
396384 cached_deps_by_app = get_deps_by_app ( cached_deps )
397385 removed_apps = Map . keys ( cached_deps_by_app ) -- Map . keys ( current_deps_by_app )
398386
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 ( )
400392
401- for { _app , deps } <- removed_deps ,
402- dep <- deps do
393+ # purge removed dependencies
394+ for dep <- removed_deps do
403395 purge_dep ( dep )
404396 end
405397
398+ # purge current dependencies in invalid state
406399 for dep <- current_deps do
407400 maybe_purge_dep ( dep )
408401 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
409427 end
410428
411429 defp fetch_deps ( current_deps ) do
@@ -462,7 +480,6 @@ defmodule ElixirLS.LanguageServer.Build do
462480 options =
463481 if Version . match? ( System . version ( ) , ">= 1.14.0" ) do
464482 Keyword . merge ( options ,
465- # we are running the server with consolidated protocols
466483 # this disables warnings `X has already been consolidated`
467484 # when running `compile` task
468485 ignore_already_consolidated: true
0 commit comments