diff --git a/apps/els_lsp/priv/code_navigation/src/code_navigation.erl b/apps/els_lsp/priv/code_navigation/src/code_navigation.erl index 56fb6247c..0ceff8bc2 100644 --- a/apps/els_lsp/priv/code_navigation/src/code_navigation.erl +++ b/apps/els_lsp/priv/code_navigation/src/code_navigation.erl @@ -122,3 +122,13 @@ macro_b(_X, _Y) -> function_mb() -> ?MACRO_B(m, b). + +code_navigation() -> code_navigation. + +code_navigation(X) -> X. + +multiple_instances_same_file() -> {code_navigation, [simple_list], "abc"}. + +code_navigation_extra(X, Y, Z) -> [code_navigation_extra, X, Y, Z]. + +multiple_instances_diff_file() -> code_navigation_extra. diff --git a/apps/els_lsp/src/els_call_hierarchy_provider.erl b/apps/els_lsp/src/els_call_hierarchy_provider.erl index d374e97ce..d7171994a 100644 --- a/apps/els_lsp/src/els_call_hierarchy_provider.erl +++ b/apps/els_lsp/src/els_call_hierarchy_provider.erl @@ -90,7 +90,7 @@ application_to_item(Uri, Application) -> #{id := Id} = Application, Name = els_utils:function_signature(Id), case els_code_navigation:goto_definition(Uri, Application) of - {ok, DefUri, DefPOI} -> + {ok, [{DefUri, DefPOI} | _]} -> DefRange = maps:get(range, DefPOI), Data = #{poi => DefPOI}, {ok, els_call_hierarchy_item:new(Name, DefUri, DefRange, DefRange, Data)}; diff --git a/apps/els_lsp/src/els_code_navigation.erl b/apps/els_lsp/src/els_code_navigation.erl index e5dc405a0..86e8630c4 100644 --- a/apps/els_lsp/src/els_code_navigation.erl +++ b/apps/els_lsp/src/els_code_navigation.erl @@ -24,7 +24,7 @@ %%============================================================================== -spec goto_definition(uri(), els_poi:poi()) -> - {ok, uri(), els_poi:poi()} | {error, any()}. + {ok, [{uri(), els_poi:poi()}]} | {error, any()}. goto_definition( Uri, Var = #{kind := variable} @@ -33,7 +33,7 @@ goto_definition( %% first occurrence of the variable in variable scope. case find_in_scope(Uri, Var) of [Var | _] -> {error, already_at_definition}; - [POI | _] -> {ok, Uri, POI}; + [POI | _] -> {ok, [{Uri, POI}]}; % Probably due to parse error [] -> {error, nothing_in_scope} end; @@ -46,7 +46,7 @@ goto_definition( Kind =:= import_entry -> case els_utils:find_module(M) of - {ok, Uri} -> find(Uri, function, {F, A}); + {ok, Uri} -> defs_to_res(find(Uri, function, {F, A})); {error, Error} -> {error, Error} end; goto_definition( @@ -60,27 +60,26 @@ goto_definition( %% try to find local function first %% fall back to bif search if unsuccessful case find(Uri, function, {F, A}) of - {error, Error} -> + [] -> case is_imported_bif(Uri, F, A) of true -> goto_definition(Uri, POI#{id := {erlang, F, A}}); false -> - {error, Error} + {error, not_found} end; Result -> - Result + defs_to_res(Result) end; goto_definition( Uri, - #{kind := atom, id := Id} = POI + #{kind := atom, id := Id} ) -> - %% Two interesting cases for atoms: testcases and modules. - %% Testcases are functions with arity 1, so we first look for a function - %% with the same name and arity 1 in the local scope - %% If we can't find it, we hope that the atom refers to a module. - case find(Uri, function, {Id, 1}) of - {error, _Error} -> goto_definition(Uri, POI#{kind := module}); - Else -> Else + %% Two interesting cases for atoms: functions and modules. + %% We return all function defs with any arity combined with module defs. + DefsFun = find(Uri, function, {Id, any_arity}), + case els_utils:find_module(Id) of + {ok, ModUri} -> defs_to_res(DefsFun ++ find(ModUri, module, Id)); + {error, _Error} -> defs_to_res(DefsFun) end; goto_definition( _Uri, @@ -90,7 +89,7 @@ goto_definition( Kind =:= module -> case els_utils:find_module(Module) of - {ok, Uri} -> find(Uri, module, Module); + {ok, Uri} -> defs_to_res(find(Uri, module, Module)); {error, Error} -> {error, Error} end; goto_definition( @@ -101,37 +100,37 @@ goto_definition( } = POI ) -> case find(Uri, define, Define) of - {error, not_found} -> + [] -> goto_definition(Uri, POI#{id => MacroName}); Else -> - Else + defs_to_res(Else) end; goto_definition(Uri, #{kind := macro, id := Define}) -> - find(Uri, define, Define); + defs_to_res(find(Uri, define, Define)); goto_definition(Uri, #{kind := record_expr, id := Record}) -> - find(Uri, record, Record); + defs_to_res(find(Uri, record, Record)); goto_definition(Uri, #{kind := record_field, id := {Record, Field}}) -> - find(Uri, record_def_field, {Record, Field}); + defs_to_res(find(Uri, record_def_field, {Record, Field})); goto_definition(_Uri, #{kind := Kind, id := Id}) when Kind =:= include; Kind =:= include_lib -> case els_utils:find_header(els_utils:filename_to_atom(Id)) of - {ok, Uri} -> {ok, Uri, beginning()}; + {ok, Uri} -> {ok, [{Uri, beginning()}]}; {error, Error} -> {error, Error} end; goto_definition(_Uri, #{kind := type_application, id := {M, T, A}}) -> case els_utils:find_module(M) of - {ok, Uri} -> find(Uri, type_definition, {T, A}); + {ok, Uri} -> defs_to_res(find(Uri, type_definition, {T, A})); {error, Error} -> {error, Error} end; goto_definition(Uri, #{kind := Kind, id := {T, A}}) when Kind =:= type_application; Kind =:= export_type_entry -> - find(Uri, type_definition, {T, A}); + defs_to_res(find(Uri, type_definition, {T, A})); goto_definition(_Uri, #{kind := parse_transform, id := Module}) -> case els_utils:find_module(Module) of - {ok, Uri} -> find(Uri, module, Module); + {ok, Uri} -> defs_to_res(find(Uri, module, Module)); {error, Error} -> {error, Error} end; goto_definition(_Filename, _) -> @@ -153,15 +152,19 @@ is_imported_bif(_Uri, F, A) -> true end. +-spec defs_to_res([{uri(), els_poi:poi()}]) -> {ok, [{uri(), els_poi:poi()}]} | {error, not_found}. +defs_to_res([]) -> {error, not_found}; +defs_to_res(Defs) -> {ok, Defs}. + -spec find(uri() | [uri()], els_poi:poi_kind(), any()) -> - {ok, uri(), els_poi:poi()} | {error, not_found}. + [{uri(), els_poi:poi()}]. find(UriOrUris, Kind, Data) -> find(UriOrUris, Kind, Data, sets:new()). -spec find(uri() | [uri()], els_poi:poi_kind(), any(), sets:set(binary())) -> - {ok, uri(), els_poi:poi()} | {error, not_found}. + [{uri(), els_poi:poi()}]. find([], _Kind, _Data, _AlreadyVisited) -> - {error, not_found}; + []; find([Uri | Uris0], Kind, Data, AlreadyVisited) -> case sets:is_element(Uri, AlreadyVisited) of true -> @@ -185,24 +188,46 @@ find(Uri, Kind, Data, AlreadyVisited) -> any(), sets:set(binary()) ) -> - {ok, uri(), els_poi:poi()} | {error, any()}. + [{uri(), els_poi:poi()}]. find_in_document([Uri | Uris0], Document, Kind, Data, AlreadyVisited) -> POIs = els_dt_document:pois(Document, [Kind]), - case [POI || #{id := Id} = POI <- POIs, Id =:= Data] of + Defs = [POI || #{id := Id} = POI <- POIs, Id =:= Data], + {AllDefs, MultipleDefs} = + case Data of + {_, any_arity} when Kind =:= function -> + %% Including defs with any arity + AnyArity = [ + POI + || #{id := {F, _}} = POI <- POIs, Kind =:= function, Data =:= {F, any_arity} + ], + {AnyArity, true}; + _ -> + {Defs, false} + end, + case AllDefs of [] -> case maybe_imported(Document, Kind, Data) of - {ok, U, P} -> - {ok, U, P}; - {error, not_found} -> + [] -> find( lists:usort(include_uris(Document) ++ Uris0), Kind, Data, AlreadyVisited - ) + ); + Else -> + Else end; Definitions -> - {ok, Uri, hd(els_poi:sort(Definitions))} + SortedDefs = els_poi:sort(Definitions), + case MultipleDefs of + true -> + %% This will be the case only when the user tries to + %% navigate to the definition of an atom + [{Uri, POI} || POI <- SortedDefs]; + false -> + %% In the general case, we return only one def + [{Uri, hd(SortedDefs)}] + end end. -spec include_uris(els_dt_document:item()) -> [uri()]. @@ -223,20 +248,20 @@ beginning() -> %% @doc check for a match in any of the module imported functions. -spec maybe_imported(els_dt_document:item(), els_poi:poi_kind(), any()) -> - {ok, uri(), els_poi:poi()} | {error, not_found}. + [{uri(), els_poi:poi()}]. maybe_imported(Document, function, {F, A}) -> POIs = els_dt_document:pois(Document, [import_entry]), case [{M, F, A} || #{id := {M, FP, AP}} <- POIs, FP =:= F, AP =:= A] of [] -> - {error, not_found}; + []; [{M, F, A} | _] -> case els_utils:find_module(M) of {ok, Uri0} -> find(Uri0, function, {F, A}); - {error, not_found} -> {error, not_found} + {error, not_found} -> [] end end; maybe_imported(_Document, _Kind, _Data) -> - {error, not_found}. + []. -spec find_in_scope(uri(), els_poi:poi()) -> [els_poi:poi()]. find_in_scope(Uri, #{kind := variable, id := VarId, range := VarRange}) -> diff --git a/apps/els_lsp/src/els_crossref_diagnostics.erl b/apps/els_lsp/src/els_crossref_diagnostics.erl index 927121c60..c89abbc79 100644 --- a/apps/els_lsp/src/els_crossref_diagnostics.erl +++ b/apps/els_lsp/src/els_crossref_diagnostics.erl @@ -142,7 +142,7 @@ has_definition( lager_definition(Level, Arity); has_definition(POI, #{uri := Uri}) -> case els_code_navigation:goto_definition(Uri, POI) of - {ok, _Uri, _POI} -> + {ok, _Defs} -> true; {error, _Error} -> false diff --git a/apps/els_lsp/src/els_definition_provider.erl b/apps/els_lsp/src/els_definition_provider.erl index d9fa53737..28b737bd5 100644 --- a/apps/els_lsp/src/els_definition_provider.erl +++ b/apps/els_lsp/src/els_definition_provider.erl @@ -40,13 +40,19 @@ handle_request({definition, Params}) -> {response, GoTo} end. --spec goto_definition(uri(), [els_poi:poi()]) -> map() | null. +-spec goto_definition(uri(), [els_poi:poi()]) -> [map()] | null. goto_definition(_Uri, []) -> null; goto_definition(Uri, [POI | Rest]) -> case els_code_navigation:goto_definition(Uri, POI) of - {ok, DefUri, #{range := Range}} -> - #{uri => DefUri, range => els_protocol:range(Range)}; + {ok, Definitions} -> + lists:map( + fun({DefUri, DefPOI}) -> + #{range := Range} = DefPOI, + #{uri => DefUri, range => els_protocol:range(Range)} + end, + Definitions + ); _ -> goto_definition(Uri, Rest) end. diff --git a/apps/els_lsp/src/els_docs.erl b/apps/els_lsp/src/els_docs.erl index 9b475dbbf..3f56bfe18 100644 --- a/apps/els_lsp/src/els_docs.erl +++ b/apps/els_lsp/src/els_docs.erl @@ -59,7 +59,7 @@ docs(Uri, #{kind := Kind, id := {F, A}}) when function_docs('local', M, F, A); docs(Uri, #{kind := macro, id := Name} = POI) -> case els_code_navigation:goto_definition(Uri, POI) of - {ok, DefUri, #{data := #{args := Args, value_range := ValueRange}}} when + {ok, [{DefUri, #{data := #{args := Args, value_range := ValueRange}}}]} when is_list(Args); is_atom(Name) -> NameStr = macro_signature(Name, Args), @@ -73,7 +73,7 @@ docs(Uri, #{kind := macro, id := Name} = POI) -> end; docs(Uri, #{kind := record_expr} = POI) -> case els_code_navigation:goto_definition(Uri, POI) of - {ok, DefUri, #{data := #{value_range := ValueRange}}} -> + {ok, [{DefUri, #{data := #{value_range := ValueRange}}}]} -> ValueText = get_valuetext(DefUri, ValueRange), [{code_line, ValueText}]; diff --git a/apps/els_lsp/src/els_references_provider.erl b/apps/els_lsp/src/els_references_provider.erl index aa67b70b1..ffdbced47 100644 --- a/apps/els_lsp/src/els_references_provider.erl +++ b/apps/els_lsp/src/els_references_provider.erl @@ -109,9 +109,9 @@ find_references(Uri, Poi = #{kind := Kind}) when Kind =:= type_application -> case els_code_navigation:goto_definition(Uri, Poi) of - {ok, DefUri, DefPoi} -> + {ok, [{DefUri, DefPoi}]} -> find_references(DefUri, DefPoi); - {error, _} -> + _ -> %% look for references only in the current document uri_pois_to_locations( find_scoped_references_for_def(Uri, Poi) diff --git a/apps/els_lsp/src/els_rename_provider.erl b/apps/els_lsp/src/els_rename_provider.erl index 6d33e0ffb..1a6fa7a12 100644 --- a/apps/els_lsp/src/els_rename_provider.erl +++ b/apps/els_lsp/src/els_rename_provider.erl @@ -114,7 +114,7 @@ workspace_edits(Uri, [#{kind := Kind} = POI | _], NewName) when Kind =:= type_application -> case els_code_navigation:goto_definition(Uri, POI) of - {ok, DefUri, DefPOI} -> + {ok, [{DefUri, DefPOI}]} -> #{changes => changes(DefUri, DefPOI, NewName)}; _ -> null diff --git a/apps/els_lsp/src/els_unused_includes_diagnostics.erl b/apps/els_lsp/src/els_unused_includes_diagnostics.erl index e29c142a0..3aae099d1 100644 --- a/apps/els_lsp/src/els_unused_includes_diagnostics.erl +++ b/apps/els_lsp/src/els_unused_includes_diagnostics.erl @@ -98,16 +98,16 @@ update_unused(Acc, _Graph, _Uri, _POIs = []) -> update_unused(Acc, Graph, Uri, [POI | POIs]) -> NewAcc = case els_code_navigation:goto_definition(Uri, POI) of - {ok, DefinitionUri, _DefinitionPOI} when DefinitionUri =:= Uri -> + {ok, [{DefinitionUri, _DefinitionPOI} | _]} when DefinitionUri =:= Uri -> Acc; - {ok, DefinitionUri, _DefinitionPOI} -> + {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). diff --git a/apps/els_lsp/test/els_code_lens_SUITE.erl b/apps/els_lsp/test/els_code_lens_SUITE.erl index 7090dcd33..fcd104947 100644 --- a/apps/els_lsp/test/els_code_lens_SUITE.erl +++ b/apps/els_lsp/test/els_code_lens_SUITE.erl @@ -96,7 +96,7 @@ default_lenses(Config) -> ], lists:usort(Commands) ), - ?assertEqual(40, length(Commands)), + ?assertEqual(50, length(Commands)), ok. -spec server_info(config()) -> ok. diff --git a/apps/els_lsp/test/els_completion_SUITE.erl b/apps/els_lsp/test/els_completion_SUITE.erl index 1c84091cd..1313ad042 100644 --- a/apps/els_lsp/test/els_completion_SUITE.erl +++ b/apps/els_lsp/test/els_completion_SUITE.erl @@ -665,7 +665,12 @@ functions_arity(Config) -> {<<"function_p">>, 1}, {<<"function_q">>, 0}, {<<"macro_b">>, 2}, - {<<"function_mb">>, 0} + {<<"function_mb">>, 0}, + {<<"code_navigation">>, 0}, + {<<"code_navigation">>, 1}, + {<<"multiple_instances_same_file">>, 0}, + {<<"code_navigation_extra">>, 3}, + {<<"multiple_instances_diff_file">>, 0} ], ExpectedCompletion = [ diff --git a/apps/els_lsp/test/els_definition_SUITE.erl b/apps/els_lsp/test/els_definition_SUITE.erl index e0d82a53f..dcc14f568 100644 --- a/apps/els_lsp/test/els_definition_SUITE.erl +++ b/apps/els_lsp/test/els_definition_SUITE.erl @@ -34,6 +34,8 @@ macro_with_args/1, macro_with_args_included/1, macro_with_implicit_args/1, + multiple_atom_instances_same_mod/1, + multiple_atom_instances_diff_mod/1, parse_transform/1, record_access/1, record_access_included/1, @@ -100,7 +102,7 @@ suite() -> application_local(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 22, 5), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {25, 1}, to => {25, 11}}), @@ -112,7 +114,7 @@ application_local(Config) -> application_remote(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 32, 13), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(?config(code_navigation_extra_uri, Config), DefUri), ?assertEqual( els_protocol:range(#{from => {5, 1}, to => {5, 3}}), @@ -127,23 +129,35 @@ atom(Config) -> Def1 = els_client:definition(Uri, 85, 20), Def2 = els_client:definition(Uri, 86, 20), Def3 = els_client:definition(Uri, 85, 27), - #{result := #{range := Range0, uri := DefUri0}} = Def0, - #{result := #{range := Range1, uri := DefUri1}} = Def1, - #{result := #{range := Range2, uri := DefUri2}} = Def2, - #{result := #{range := Range3, uri := DefUri3}} = Def3, + #{result := [#{range := Range0, uri := DefUri0}]} = Def0, + #{result := [#{range := Range1, uri := DefUri1}, #{range := Range12, uri := DefUri12}]} = + Def1, + #{result := [#{range := Range2, uri := DefUri2}, #{range := Range22, uri := DefUri22}]} = + Def2, + #{result := [#{range := Range3, uri := DefUri3}]} = Def3, ?assertEqual(?config(code_navigation_types_uri, Config), DefUri0), ?assertEqual( els_protocol:range(#{from => {1, 9}, to => {1, 30}}), Range0 ), - ?assertEqual(?config(code_navigation_extra_uri, Config), DefUri1), + ?assertEqual(?config(code_navigation_extra_uri, Config), DefUri12), ?assertEqual( els_protocol:range(#{from => {1, 9}, to => {1, 30}}), + Range12 + ), + ?assertEqual(Uri, DefUri1), + ?assertEqual( + els_protocol:range(#{from => {132, 1}, to => {132, 22}}), Range1 ), - ?assertEqual(?config(code_navigation_extra_uri, Config), DefUri2), + ?assertEqual(?config(code_navigation_extra_uri, Config), DefUri22), ?assertEqual( els_protocol:range(#{from => {1, 9}, to => {1, 30}}), + Range22 + ), + ?assertEqual(Uri, DefUri2), + ?assertEqual( + els_protocol:range(#{from => {132, 1}, to => {132, 22}}), Range2 ), ?assertEqual(?config('Code.Navigation.Elixirish_uri', Config), DefUri3), @@ -157,7 +171,7 @@ atom(Config) -> behaviour(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 3, 16), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(?config(behaviour_a_uri, Config), DefUri), ?assertEqual( els_protocol:range(#{from => {1, 9}, to => {1, 20}}), @@ -169,7 +183,7 @@ behaviour(Config) -> testcase(Config) -> Uri = ?config(sample_SUITE_uri, Config), Def = els_client:definition(Uri, 35, 6), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {58, 1}, to => {58, 4}}), @@ -177,13 +191,58 @@ testcase(Config) -> ), ok. +-spec multiple_atom_instances_same_mod(config()) -> ok. +multiple_atom_instances_same_mod(Config) -> + Uri = ?config(code_navigation_uri, Config), + Defs = els_client:definition(Uri, 130, 36), + #{result := Results} = Defs, + ?assertEqual(3, length(Results)), + ExpectedRanges = [ + els_protocol:range(#{from => {1, 9}, to => {1, 24}}), + els_protocol:range(#{from => {126, 1}, to => {126, 16}}), + els_protocol:range(#{from => {128, 1}, to => {128, 16}}) + ], + lists:foreach( + fun(Def) -> + #{range := Range, uri := DefUri} = Def, + ?assertEqual(Uri, DefUri), + ?assert(lists:member(Range, ExpectedRanges)) + end, + Results + ), + ok. + +-spec multiple_atom_instances_diff_mod(config()) -> ok. +multiple_atom_instances_diff_mod(Config) -> + Uri = ?config(code_navigation_uri, Config), + Defs = els_client:definition(Uri, 134, 35), + #{result := Results} = Defs, + ?assertEqual(2, length(Results)), + RangeDef1 = els_protocol:range(#{from => {132, 1}, to => {132, 22}}), + RangeDef2 = els_protocol:range(#{from => {1, 9}, to => {1, 30}}), + Uri2 = ?config(code_navigation_extra_uri, Config), + ?assertMatch( + [ + #{ + range := RangeDef1, + uri := Uri + }, + #{ + range := RangeDef2, + uri := Uri2 + } + ], + Results + ), + ok. + %% Issue #191: Definition not found after document is closed -spec definition_after_closing(config()) -> ok. definition_after_closing(Config) -> Uri = ?config(code_navigation_uri, Config), ExtraUri = ?config(code_navigation_extra_uri, Config), Def = els_client:definition(Uri, 32, 13), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(ExtraUri, DefUri), ?assertEqual( els_protocol:range(#{from => {5, 1}, to => {5, 3}}), @@ -193,14 +252,14 @@ definition_after_closing(Config) -> %% Close file, get definition ok = els_client:did_close(ExtraUri), Def1 = els_client:definition(Uri, 32, 13), - #{result := #{range := Range, uri := DefUri}} = Def1, + #{result := [#{range := Range, uri := DefUri}]} = Def1, ok. -spec duplicate_definition(config()) -> ok. duplicate_definition(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 57, 5), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {60, 1}, to => {60, 11}}), @@ -212,7 +271,7 @@ duplicate_definition(Config) -> export_entry(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 8, 15), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {28, 1}, to => {28, 11}}), @@ -224,7 +283,7 @@ export_entry(Config) -> fun_local(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 51, 16), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {25, 1}, to => {25, 11}}), @@ -236,7 +295,7 @@ fun_local(Config) -> fun_remote(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 52, 14), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(?config(code_navigation_extra_uri, Config), DefUri), ?assertEqual( els_protocol:range(#{from => {5, 1}, to => {5, 3}}), @@ -248,7 +307,7 @@ fun_remote(Config) -> import_entry(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 10, 34), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(?config(code_navigation_extra_uri, Config), DefUri), ?assertEqual( els_protocol:range(#{from => {5, 1}, to => {5, 3}}), @@ -260,7 +319,7 @@ import_entry(Config) -> module_import_entry(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 90, 3), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(?config(code_navigation_extra_uri, Config), DefUri), ?assertEqual( els_protocol:range(#{from => {5, 1}, to => {5, 3}}), @@ -272,7 +331,7 @@ module_import_entry(Config) -> include(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 12, 20), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(?config(code_navigation_h_uri, Config), DefUri), ?assertEqual( els_protocol:range(#{from => {1, 1}, to => {1, 1}}), @@ -284,7 +343,7 @@ include(Config) -> include_lib(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 13, 22), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(?config(code_navigation_h_uri, Config), DefUri), ?assertEqual( els_protocol:range(#{from => {1, 1}, to => {1, 1}}), @@ -296,7 +355,7 @@ include_lib(Config) -> macro(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 26, 5), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {18, 9}, to => {18, 16}}), @@ -308,7 +367,7 @@ macro(Config) -> macro_lowercase(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 48, 3), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {45, 9}, to => {45, 16}}), @@ -320,14 +379,14 @@ macro_lowercase(Config) -> macro_included(Config) -> Uri = ?config(code_navigation_uri, Config), UriHeader = ?config(code_navigation_h_uri, Config), - #{result := #{range := Range1, uri := DefUri1}} = + #{result := [#{range := Range1, uri := DefUri1}]} = els_client:definition(Uri, 53, 19), ?assertEqual(UriHeader, DefUri1), ?assertEqual( els_protocol:range(#{from => {3, 9}, to => {3, 25}}), Range1 ), - #{result := #{range := RangeQuoted, uri := DefUri2}} = + #{result := [#{range := RangeQuoted, uri := DefUri2}]} = els_client:definition(Uri, 52, 75), ?assertEqual(UriHeader, DefUri2), ?assertEqual( @@ -340,7 +399,7 @@ macro_included(Config) -> macro_with_args(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 40, 9), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {19, 9}, to => {19, 16}}), @@ -352,7 +411,7 @@ macro_with_args(Config) -> macro_with_args_included(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 43, 9), - #{result := #{uri := DefUri}} = Def, + #{result := [#{uri := DefUri}]} = Def, ?assertEqual( <<"assert.hrl">>, filename:basename(els_uri:path(DefUri)) @@ -364,7 +423,7 @@ macro_with_args_included(Config) -> macro_with_implicit_args(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 124, 5), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {118, 9}, to => {118, 16}}), @@ -376,7 +435,7 @@ macro_with_implicit_args(Config) -> parse_transform(Config) -> Uri = ?config(diagnostics_parse_transform_usage_uri, Config), Def = els_client:definition(Uri, 5, 45), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(?config(diagnostics_parse_transform_uri, Config), DefUri), ?assertEqual( els_protocol:range(#{from => {1, 9}, to => {1, 36}}), @@ -388,7 +447,7 @@ parse_transform(Config) -> record_access(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 34, 13), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {16, 9}, to => {16, 17}}), @@ -400,7 +459,7 @@ record_access(Config) -> record_access_included(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 52, 43), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(?config(code_navigation_h_uri, Config), DefUri), ?assertEqual( els_protocol:range(#{from => {1, 9}, to => {1, 26}}), @@ -412,7 +471,7 @@ record_access_included(Config) -> record_access_macro_name(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 116, 33), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {111, 9}, to => {111, 16}}), @@ -426,7 +485,7 @@ record_access_macro_name(Config) -> record_expr(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 33, 11), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {16, 9}, to => {16, 17}}), @@ -438,7 +497,7 @@ record_expr(Config) -> record_expr_included(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 53, 30), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(?config(code_navigation_h_uri, Config), DefUri), ?assertEqual( els_protocol:range(#{from => {1, 9}, to => {1, 26}}), @@ -450,7 +509,7 @@ record_expr_included(Config) -> record_expr_macro_name(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 115, 11), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {111, 9}, to => {111, 16}}), @@ -462,7 +521,7 @@ record_expr_macro_name(Config) -> record_field(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 33, 20), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {16, 20}, to => {16, 27}}), @@ -474,7 +533,7 @@ record_field(Config) -> record_field_included(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 53, 45), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(?config(code_navigation_h_uri, Config), DefUri), ?assertEqual( els_protocol:range(#{from => {1, 29}, to => {1, 45}}), @@ -486,7 +545,7 @@ record_field_included(Config) -> record_type_macro_name(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 113, 28), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {111, 9}, to => {111, 16}}), @@ -499,7 +558,7 @@ type_application_remote(Config) -> ExtraUri = ?config(code_navigation_extra_uri, Config), TypesUri = ?config(code_navigation_types_uri, Config), Def = els_client:definition(ExtraUri, 11, 38), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(TypesUri, DefUri), ?assertEqual( els_protocol:range(#{from => {3, 1}, to => {3, 26}}), @@ -528,7 +587,7 @@ type_application_undefined(Config) -> type_application_user(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 55, 25), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {37, 1}, to => {37, 25}}), @@ -540,7 +599,7 @@ type_application_user(Config) -> type_export_entry(Config) -> Uri = ?config(code_navigation_uri, Config), Def = els_client:definition(Uri, 9, 17), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(Uri, DefUri), ?assertEqual( els_protocol:range(#{from => {37, 1}, to => {37, 25}}), @@ -556,11 +615,11 @@ variable(Config) -> Def2 = els_client:definition(Uri, 107, 10), Def3 = els_client:definition(Uri, 108, 10), Def4 = els_client:definition(Uri, 19, 36), - #{result := #{range := Range0, uri := DefUri0}} = Def0, - #{result := #{range := Range1, uri := DefUri0}} = Def1, - #{result := #{range := Range2, uri := DefUri0}} = Def2, - #{result := #{range := Range3, uri := DefUri0}} = Def3, - #{result := #{range := Range4, uri := DefUri0}} = Def4, + #{result := [#{range := Range0, uri := DefUri0}]} = Def0, + #{result := [#{range := Range1, uri := DefUri0}]} = Def1, + #{result := [#{range := Range2, uri := DefUri0}]} = Def2, + #{result := [#{range := Range3, uri := DefUri0}]} = Def3, + #{result := [#{range := Range4, uri := DefUri0}]} = Def4, ?assertEqual(?config(code_navigation_uri, Config), DefUri0), ?assertEqual( @@ -591,7 +650,7 @@ opaque_application_remote(Config) -> ExtraUri = ?config(code_navigation_extra_uri, Config), TypesUri = ?config(code_navigation_types_uri, Config), Def = els_client:definition(ExtraUri, 16, 61), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(TypesUri, DefUri), ?assertEqual( els_protocol:range(#{from => {7, 1}, to => {7, 35}}), @@ -603,7 +662,7 @@ opaque_application_remote(Config) -> opaque_application_user(Config) -> ExtraUri = ?config(code_navigation_extra_uri, Config), Def = els_client:definition(ExtraUri, 16, 24), - #{result := #{range := Range, uri := DefUri}} = Def, + #{result := [#{range := Range, uri := DefUri}]} = Def, ?assertEqual(ExtraUri, DefUri), ?assertEqual( els_protocol:range(#{from => {20, 1}, to => {20, 34}}), @@ -616,31 +675,31 @@ parse_incomplete(Config) -> Uri = ?config(code_navigation_broken_uri, Config), Range = els_protocol:range(#{from => {3, 1}, to => {3, 11}}), ?assertMatch( - #{result := #{range := Range, uri := Uri}}, + #{result := [#{range := Range, uri := Uri}]}, els_client:definition(Uri, 7, 3) ), ?assertMatch( - #{result := #{range := Range, uri := Uri}}, + #{result := [#{range := Range, uri := Uri}]}, els_client:definition(Uri, 8, 3) ), ?assertMatch( - #{result := #{range := Range, uri := Uri}}, + #{result := [#{range := Range, uri := Uri}]}, els_client:definition(Uri, 9, 8) ), ?assertMatch( - #{result := #{range := Range, uri := Uri}}, + #{result := [#{range := Range, uri := Uri}]}, els_client:definition(Uri, 11, 7) ), ?assertMatch( - #{result := #{range := Range, uri := Uri}}, + #{result := [#{range := Range, uri := Uri}]}, els_client:definition(Uri, 12, 12) ), ?assertMatch( - #{result := #{range := Range, uri := Uri}}, + #{result := [#{range := Range, uri := Uri}]}, els_client:definition(Uri, 17, 3) ), ?assertMatch( - #{result := #{range := Range, uri := Uri}}, + #{result := [#{range := Range, uri := Uri}]}, els_client:definition(Uri, 19, 3) ), ok. diff --git a/apps/els_lsp/test/els_document_symbol_SUITE.erl b/apps/els_lsp/test/els_document_symbol_SUITE.erl index 1f4919a1d..2c53ee087 100644 --- a/apps/els_lsp/test/els_document_symbol_SUITE.erl +++ b/apps/els_lsp/test/els_document_symbol_SUITE.erl @@ -169,7 +169,12 @@ functions() -> {<<"function_p/1">>, {102, 0}, {102, 10}}, {<<"function_q/0">>, {113, 0}, {113, 10}}, {<<"macro_b/2">>, {119, 0}, {119, 7}}, - {<<"function_mb/0">>, {122, 0}, {122, 11}} + {<<"function_mb/0">>, {122, 0}, {122, 11}}, + {<<"code_navigation/0">>, {125, 0}, {125, 15}}, + {<<"code_navigation/1">>, {127, 0}, {127, 15}}, + {<<"multiple_instances_same_file/0">>, {129, 0}, {129, 28}}, + {<<"code_navigation_extra/3">>, {131, 0}, {131, 21}}, + {<<"multiple_instances_diff_file/0">>, {133, 0}, {133, 28}} ]. macros() -> diff --git a/apps/els_lsp/test/els_rebar3_release_SUITE.erl b/apps/els_lsp/test/els_rebar3_release_SUITE.erl index d5cbb9bce..01ae7a399 100644 --- a/apps/els_lsp/test/els_rebar3_release_SUITE.erl +++ b/apps/els_lsp/test/els_rebar3_release_SUITE.erl @@ -87,7 +87,7 @@ code_navigation(Config) -> AppUri = ?config(app_uri, Config), SupUri = ?config(sup_uri, Config), #{result := Result} = els_client:definition(AppUri, 13, 12), - #{range := DefRange, uri := SupUri} = Result, + [#{range := DefRange, uri := SupUri}] = Result, ?assertEqual( els_protocol:range(#{from => {16, 1}, to => {16, 11}}), DefRange