24
24
% %==============================================================================
25
25
26
26
-spec goto_definition (uri (), els_poi :poi ()) ->
27
- {ok , uri (), els_poi :poi ()} | {error , any ()}.
27
+ {ok , [{ uri (), els_poi :poi ()}] } | {error , any ()}.
28
28
goto_definition (
29
29
Uri ,
30
30
Var = #{kind := variable }
@@ -33,7 +33,7 @@ goto_definition(
33
33
% % first occurrence of the variable in variable scope.
34
34
case find_in_scope (Uri , Var ) of
35
35
[Var | _ ] -> {error , already_at_definition };
36
- [POI | _ ] -> {ok , Uri , POI };
36
+ [POI | _ ] -> {ok , [{ Uri , POI }] };
37
37
% Probably due to parse error
38
38
[] -> {error , nothing_in_scope }
39
39
end ;
@@ -46,7 +46,7 @@ goto_definition(
46
46
Kind =:= import_entry
47
47
->
48
48
case els_utils :find_module (M ) of
49
- {ok , Uri } -> find (Uri , function , {F , A });
49
+ {ok , Uri } -> defs_to_res ( find (Uri , function , {F , A }) );
50
50
{error , Error } -> {error , Error }
51
51
end ;
52
52
goto_definition (
@@ -60,27 +60,26 @@ goto_definition(
60
60
% % try to find local function first
61
61
% % fall back to bif search if unsuccessful
62
62
case find (Uri , function , {F , A }) of
63
- { error , Error } ->
63
+ [] ->
64
64
case is_imported_bif (Uri , F , A ) of
65
65
true ->
66
66
goto_definition (Uri , POI #{id := {erlang , F , A }});
67
67
false ->
68
- {error , Error }
68
+ {error , not_found }
69
69
end ;
70
70
Result ->
71
- Result
71
+ defs_to_res ( Result )
72
72
end ;
73
73
goto_definition (
74
74
Uri ,
75
- #{kind := atom , id := Id } = POI
75
+ #{kind := atom , id := Id }
76
76
) ->
77
- % % Two interesting cases for atoms: testcases and modules.
78
- % % Testcases are functions with arity 1, so we first look for a function
79
- % % with the same name and arity 1 in the local scope
80
- % % If we can't find it, we hope that the atom refers to a module.
81
- case find (Uri , function , {Id , 1 }) of
82
- {error , _Error } -> goto_definition (Uri , POI #{kind := module });
83
- Else -> Else
77
+ % % Two interesting cases for atoms: functions and modules.
78
+ % % We return all function defs with any arity combined with module defs.
79
+ DefsFun = find (Uri , function , {Id , any_arity }),
80
+ case els_utils :find_module (Id ) of
81
+ {ok , ModUri } -> defs_to_res (DefsFun ++ find (ModUri , module , Id ));
82
+ {error , _Error } -> defs_to_res (DefsFun )
84
83
end ;
85
84
goto_definition (
86
85
_Uri ,
@@ -90,7 +89,7 @@ goto_definition(
90
89
Kind =:= module
91
90
->
92
91
case els_utils :find_module (Module ) of
93
- {ok , Uri } -> find (Uri , module , Module );
92
+ {ok , Uri } -> defs_to_res ( find (Uri , module , Module ) );
94
93
{error , Error } -> {error , Error }
95
94
end ;
96
95
goto_definition (
@@ -101,37 +100,37 @@ goto_definition(
101
100
} = POI
102
101
) ->
103
102
case find (Uri , define , Define ) of
104
- { error , not_found } ->
103
+ [] ->
105
104
goto_definition (Uri , POI #{id => MacroName });
106
105
Else ->
107
- Else
106
+ defs_to_res ( Else )
108
107
end ;
109
108
goto_definition (Uri , #{kind := macro , id := Define }) ->
110
- find (Uri , define , Define );
109
+ defs_to_res ( find (Uri , define , Define ) );
111
110
goto_definition (Uri , #{kind := record_expr , id := Record }) ->
112
- find (Uri , record , Record );
111
+ defs_to_res ( find (Uri , record , Record ) );
113
112
goto_definition (Uri , #{kind := record_field , id := {Record , Field }}) ->
114
- find (Uri , record_def_field , {Record , Field });
113
+ defs_to_res ( find (Uri , record_def_field , {Record , Field }) );
115
114
goto_definition (_Uri , #{kind := Kind , id := Id }) when
116
115
Kind =:= include ;
117
116
Kind =:= include_lib
118
117
->
119
118
case els_utils :find_header (els_utils :filename_to_atom (Id )) of
120
- {ok , Uri } -> {ok , Uri , beginning ()};
119
+ {ok , Uri } -> {ok , [{ Uri , beginning ()}] };
121
120
{error , Error } -> {error , Error }
122
121
end ;
123
122
goto_definition (_Uri , #{kind := type_application , id := {M , T , A }}) ->
124
123
case els_utils :find_module (M ) of
125
- {ok , Uri } -> find (Uri , type_definition , {T , A });
124
+ {ok , Uri } -> defs_to_res ( find (Uri , type_definition , {T , A }) );
126
125
{error , Error } -> {error , Error }
127
126
end ;
128
127
goto_definition (Uri , #{kind := Kind , id := {T , A }}) when
129
128
Kind =:= type_application ; Kind =:= export_type_entry
130
129
->
131
- find (Uri , type_definition , {T , A });
130
+ defs_to_res ( find (Uri , type_definition , {T , A }) );
132
131
goto_definition (_Uri , #{kind := parse_transform , id := Module }) ->
133
132
case els_utils :find_module (Module ) of
134
- {ok , Uri } -> find (Uri , module , Module );
133
+ {ok , Uri } -> defs_to_res ( find (Uri , module , Module ) );
135
134
{error , Error } -> {error , Error }
136
135
end ;
137
136
goto_definition (_Filename , _ ) ->
@@ -153,15 +152,19 @@ is_imported_bif(_Uri, F, A) ->
153
152
true
154
153
end .
155
154
155
+ -spec defs_to_res ([{uri (), els_poi :poi ()}]) -> {ok , [{uri (), els_poi :poi ()}]} | {error , not_found }.
156
+ defs_to_res ([]) -> {error , not_found };
157
+ defs_to_res (Defs ) -> {ok , Defs }.
158
+
156
159
-spec find (uri () | [uri ()], els_poi :poi_kind (), any ()) ->
157
- { ok , uri (), els_poi :poi ()} | { error , not_found } .
160
+ [{ uri (), els_poi :poi ()}] .
158
161
find (UriOrUris , Kind , Data ) ->
159
162
find (UriOrUris , Kind , Data , sets :new ()).
160
163
161
164
-spec find (uri () | [uri ()], els_poi :poi_kind (), any (), sets :set (binary ())) ->
162
- { ok , uri (), els_poi :poi ()} | { error , not_found } .
165
+ [{ uri (), els_poi :poi ()}] .
163
166
find ([], _Kind , _Data , _AlreadyVisited ) ->
164
- { error , not_found } ;
167
+ [] ;
165
168
find ([Uri | Uris0 ], Kind , Data , AlreadyVisited ) ->
166
169
case sets :is_element (Uri , AlreadyVisited ) of
167
170
true ->
@@ -185,24 +188,46 @@ find(Uri, Kind, Data, AlreadyVisited) ->
185
188
any (),
186
189
sets :set (binary ())
187
190
) ->
188
- { ok , uri (), els_poi :poi ()} | { error , any ()} .
191
+ [{ uri (), els_poi :poi ()}] .
189
192
find_in_document ([Uri | Uris0 ], Document , Kind , Data , AlreadyVisited ) ->
190
193
POIs = els_dt_document :pois (Document , [Kind ]),
191
- case [POI || #{id := Id } = POI <- POIs , Id =:= Data ] of
194
+ Defs = [POI || #{id := Id } = POI <- POIs , Id =:= Data ],
195
+ {AllDefs , MultipleDefs } =
196
+ case Data of
197
+ {_ , any_arity } when Kind =:= function ->
198
+ % % Including defs with any arity
199
+ AnyArity = [
200
+ POI
201
+ || #{id := {F , _ }} = POI <- POIs , Kind =:= function , Data =:= {F , any_arity }
202
+ ],
203
+ {AnyArity , true };
204
+ _ ->
205
+ {Defs , false }
206
+ end ,
207
+ case AllDefs of
192
208
[] ->
193
209
case maybe_imported (Document , Kind , Data ) of
194
- {ok , U , P } ->
195
- {ok , U , P };
196
- {error , not_found } ->
210
+ [] ->
197
211
find (
198
212
lists :usort (include_uris (Document ) ++ Uris0 ),
199
213
Kind ,
200
214
Data ,
201
215
AlreadyVisited
202
- )
216
+ );
217
+ Else ->
218
+ Else
203
219
end ;
204
220
Definitions ->
205
- {ok , Uri , hd (els_poi :sort (Definitions ))}
221
+ SortedDefs = els_poi :sort (Definitions ),
222
+ case MultipleDefs of
223
+ true ->
224
+ % % This will be the case only when the user tries to
225
+ % % navigate to the definition of an atom
226
+ [{Uri , POI } || POI <- SortedDefs ];
227
+ false ->
228
+ % % In the general case, we return only one def
229
+ [{Uri , hd (SortedDefs )}]
230
+ end
206
231
end .
207
232
208
233
-spec include_uris (els_dt_document :item ()) -> [uri ()].
@@ -223,20 +248,20 @@ beginning() ->
223
248
224
249
% % @doc check for a match in any of the module imported functions.
225
250
-spec maybe_imported (els_dt_document :item (), els_poi :poi_kind (), any ()) ->
226
- { ok , uri (), els_poi :poi ()} | { error , not_found } .
251
+ [{ uri (), els_poi :poi ()}] .
227
252
maybe_imported (Document , function , {F , A }) ->
228
253
POIs = els_dt_document :pois (Document , [import_entry ]),
229
254
case [{M , F , A } || #{id := {M , FP , AP }} <- POIs , FP =:= F , AP =:= A ] of
230
255
[] ->
231
- { error , not_found } ;
256
+ [] ;
232
257
[{M , F , A } | _ ] ->
233
258
case els_utils :find_module (M ) of
234
259
{ok , Uri0 } -> find (Uri0 , function , {F , A });
235
- {error , not_found } -> { error , not_found }
260
+ {error , not_found } -> []
236
261
end
237
262
end ;
238
263
maybe_imported (_Document , _Kind , _Data ) ->
239
- { error , not_found } .
264
+ [] .
240
265
241
266
-spec find_in_scope (uri (), els_poi :poi ()) -> [els_poi :poi ()].
242
267
find_in_scope (Uri , #{kind := variable , id := VarId , range := VarRange }) ->
0 commit comments