Skip to content

Commit

Permalink
Optimize unused includes detection by avoiding unnecessary work (#1322)
Browse files Browse the repository at this point in the history
While identifying unused includes, the current implementation performs
a go-to-definition operation for all POIs within a document, even if
all the .hrl candidates have already been excluded.

This change stops the iteration as soon as no candidates are present.

The whole detection algorithm could probably be revisited (it would be
good to check if this problem has been tackled in literature), but for
now this optimization will lower the execution time for "unused
includes" diagnostics and reduce the stress on the language server,
especially for big modules.

As an example, this optimization reduces the computing time for
"unused includes" diagnostics for the `els_parser.erl` module from ~1s
to ~200ms.
  • Loading branch information
robertoaloi authored Jun 9, 2022
1 parent 32ced53 commit 6f51ea1
Showing 1 changed file with 22 additions and 19 deletions.
41 changes: 22 additions & 19 deletions apps/els_lsp/src/els_unused_includes_diagnostics.erl
Original file line number Diff line number Diff line change
Expand Up @@ -86,28 +86,31 @@ find_unused_includes(#{uri := Uri} = Document) ->
els_config:get(exclude_unused_includes)
),
IncludedUris = IncludedUris1 -- ExcludeUnusedIncludes,
Fun = fun(POI, Acc) ->
update_unused(Graph, Uri, POI, Acc)
end,
UnusedIncludes = lists:foldl(Fun, IncludedUris, POIs),
UnusedIncludes = update_unused(IncludedUris, Graph, Uri, POIs),
digraph:delete(Graph),
UnusedIncludes.

-spec update_unused(digraph:graph(), uri(), els_poi:poi(), [uri()]) -> [uri()].
update_unused(Graph, Uri, POI, Acc) ->
case els_code_navigation:goto_definition(Uri, POI) of
{ok, Uri, _DefinitionPOI} ->
Acc;
{ok, DefinitionUri, _DefinitionPOI} ->
case digraph:get_path(Graph, DefinitionUri, Uri) of
false ->
Acc;
Path ->
Acc -- Path
end;
{error, _Reason} ->
Acc
end.
-spec update_unused([uri()], digraph:graph(), uri(), [els_poi:poi()]) -> [uri()].
update_unused(Acc = [], _Graph, _Uri, _POIs) ->
Acc;
update_unused(Acc, _Graph, _Uri, _POIs = []) ->
Acc;
update_unused(Acc, Graph, Uri, [POI | POIs]) ->
NewAcc =
case els_code_navigation:goto_definition(Uri, POI) of
{ok, DefinitionUri, _DefinitionPOI} when DefinitionUri =:= Uri ->
Acc;
{ok, DefinitionUri, _DefinitionPOI} ->
case digraph:get_path(Graph, DefinitionUri, Uri) of
false ->
Acc;
Path ->
Acc -- Path
end;
{error, _Reason} ->
Acc
end,
update_unused(NewAcc, Graph, Uri, POIs).

-spec expand_includes(els_dt_document:item()) -> digraph:graph().
expand_includes(Document) ->
Expand Down

0 comments on commit 6f51ea1

Please sign in to comment.