Skip to content

Commit

Permalink
Use both index and naive when looking up scoped references
Browse files Browse the repository at this point in the history
Finding scoped references can be done in two ways:

  * Naive, find all POIs that can reach our POI and matches the id.

  * Indexed, use the index to find all matching POIs, then check if
    they actually reference our POI by using goto_definition.

It varies from case to case which is the fastest, so we race both
functions to get the quickest answer.
  • Loading branch information
plux committed Jan 9, 2024
1 parent 9257f5d commit b44a8b6
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 28 deletions.
27 changes: 26 additions & 1 deletion apps/els_core/src/els_utils.erl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
camel_case/1,
jaro_distance/2,
is_windows/0,
system_tmp_dir/0
system_tmp_dir/0,
race/1
]).

%%==============================================================================
Expand Down Expand Up @@ -272,9 +273,33 @@ system_tmp_dir() ->
"/tmp"
end.

%% @doc Run functions in parallel and return the result of the first function
%% that terminates
-spec race(fun(() -> Result)) -> Result.
race(Funs) ->
Parent = self(),
Ref = make_ref(),
Pids = [spawn(fun() -> Parent ! {Ref, Fun()} end) || Fun <- Funs],
receive
{Ref, Result} ->
%% Ensure no lingering processes
[exit(Pid, kill) || Pid <- Pids],
%% Ensure no lingering messages
ok = flush(Ref),
Result
end.

%%==============================================================================
%% Internal functions
%%==============================================================================
-spec flush(reference()) -> ok.
flush(Ref) ->
receive
{Ref, _} ->
flush(Ref)
after 0 ->
ok
end.

%% Folding over files

Expand Down
2 changes: 1 addition & 1 deletion apps/els_lsp/src/els_dt_references.erl
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ kind_to_category(Kind) when
Kind =:= record_field;
Kind =:= record_def_field
->
record;
record_field;
kind_to_category(Kind) when Kind =:= include ->
include;
kind_to_category(Kind) when Kind =:= include_lib ->
Expand Down
16 changes: 5 additions & 11 deletions apps/els_lsp/src/els_indexing.erl
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ index_references(Id, Uri, POIs, Version) ->
%% Macro
macro,
%% Record
record_expr
record_expr,
record_field
],
[
index_reference(Id, Uri, POI, Version)
Expand All @@ -156,16 +157,9 @@ index_references(Id, Uri, POIs, Version) ->
ok.

-spec index_reference(atom(), uri(), els_poi:poi(), version()) -> ok.
index_reference(_M, Uri, #{kind := Kind, id := Id, range := Range}, Version) when
Kind =:= macro
->
els_dt_references:versioned_insert(Kind, #{
id => Id,
uri => Uri,
range => Range,
version => Version
});
index_reference(M, Uri, #{kind := _Kind, id := {F, A}} = POI, Version) ->
index_reference(M, Uri, #{kind := Kind, id := {F, A}} = POI, Version) when
Kind =/= macro,
Kind =/= record_field ->
index_reference(M, Uri, POI#{id => {M, F, A}}, Version);
index_reference(_M, Uri, #{kind := Kind, id := Id, range := Range}, Version) ->
els_dt_references:versioned_insert(Kind, #{
Expand Down
49 changes: 36 additions & 13 deletions apps/els_lsp/src/els_references_provider.erl
Original file line number Diff line number Diff line change
Expand Up @@ -156,29 +156,52 @@ local_refs(Uri, Kind, Id) ->
LocalRefs.

-spec find_scoped_references_for_def(uri(), els_poi:poi()) -> [location()].
find_scoped_references_for_def(Uri, #{kind := Kind, id := Id}) when
Kind =:= record_def_field;
find_scoped_references_for_def(Uri, POI = #{kind := Kind, id := Id}) when
Kind =:= type_definition
->
%% TODO: This is a hack, ideally we shouldn't have any special handling for
%% these kinds
%% these kinds.
find_scoped_references_naive(Uri, POI);
find_scoped_references_for_def(Uri, POI) ->
%% Finding scoped references can be done in two ways:
%% * Naive, find all POIs that can reach our POI and matches the id.
%% * Indexed, use the index to find all matching POIs, then check if
%% they actually reference our POI by using goto_definition.
%% It varies from case to case which is the fastest, so we race both
%% functions to get the quickest answer.
Naive = fun() -> find_scoped_references_naive(Uri, POI) end,
Index = fun() -> find_scoped_references_with_index(Uri, POI) end,
els_utils:race([Naive, Index]).

-spec find_scoped_references_naive(uri(), els_poi:poi()) -> [location()].
find_scoped_references_naive(Uri, #{id := Id, kind := Kind}) ->
RefKind = kind_to_ref_kind(Kind),
Refs = els_scope:local_and_includer_pois(Uri, [RefKind]),
[
MatchingRefs = [
location(U, R)
|| {U, Pois} <- Refs,
#{id := N, range := R} <- Pois,
N =:= Id
];
find_scoped_references_for_def(Uri, POI = #{kind := Kind, id := Id}) ->
],
?LOG_DEBUG("Found scoped references (naive) for ~p: ~p",
[Id, length(MatchingRefs)]),
MatchingRefs.

-spec find_scoped_references_with_index(uri(), els_poi:poi()) -> [location()].
find_scoped_references_with_index(Uri, POI = #{kind := Kind, id := Id}) ->

RefPOI = POI#{kind := kind_to_ref_kind(Kind)},
F = fun(#{uri := RefUri}) ->
case els_code_navigation:goto_definition(RefUri, RefPOI) of
{ok, Uri, _} -> true;
_ -> false
end
end,
[Ref || Ref <- find_references_for_id(Kind, Id), F(Ref)].
Match = fun(#{uri := RefUri}) ->
case els_code_navigation:goto_definition(RefUri, RefPOI) of
{ok, [{Uri, _}]} -> true;
_Else ->
false
end
end,
Refs = [Ref || Ref <- find_references_for_id(Kind, Id), Match(Ref)],
?LOG_DEBUG("Found scoped references (with index) for ~p: ~p",
[Id, length(Refs)]),
Refs.

-spec kind_to_ref_kind(els_poi:poi_kind()) -> els_poi:poi_kind().
kind_to_ref_kind(define) ->
Expand Down
3 changes: 1 addition & 2 deletions apps/els_lsp/src/els_text_search.erl
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ extract_pattern({behaviour, Name}) ->
Name;
extract_pattern({atom, Name}) ->
Name;
extract_pattern({record, {_Record, Name}}) ->
%% Record fields
extract_pattern({record_field, {_Record, Name}}) ->
Name;
extract_pattern({record, Name}) ->
Name.
Expand Down

0 comments on commit b44a8b6

Please sign in to comment.