Skip to content

Commit 51c877d

Browse files
committed
Add support for checking if a function is exported in crossref diagnostics
1 parent ed1daaa commit 51c877d

File tree

5 files changed

+55
-24
lines changed

5 files changed

+55
-24
lines changed

apps/els_lsp/priv/code_navigation/src/diagnostics_xref.erl

+3
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ existing() ->
1212
dynamic_call(Foo, Bar) ->
1313
Foo:bar(),
1414
foo:Bar().
15+
16+
not_exported() ->
17+
lists:map_1(foo, [1,2,3]).

apps/els_lsp/src/els_crossref_diagnostics.erl

+24-12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
source/0
1919
]).
2020

21+
-type missing_reason() :: module | function | export.
22+
2123
%%==============================================================================
2224
%% Includes
2325
%%==============================================================================
@@ -114,19 +116,23 @@ make_diagnostic({missing, Kind}, #{id := Id} = POI) ->
114116
make_diagnostic(true, _) ->
115117
[].
116118

117-
-spec range(module | function, els_poi:poi()) -> els_poi:poi_range().
119+
-spec range(missing_reason(), els_poi:poi()) -> els_poi:poi_range().
118120
range(module, #{data := #{mod_range := Range}}) ->
119121
Range;
120122
range(function, #{data := #{name_range := Range}}) ->
121123
Range;
124+
range(export, #{data := #{name_range := Range}}) ->
125+
Range;
122126
range(_, #{range := Range}) ->
123127
Range.
124128

125-
-spec error_msg(module | function, els_poi:poi_id()) -> binary().
129+
-spec error_msg(missing_reason(), els_poi:poi_id()) -> binary().
126130
error_msg(module, {M, _F, _A}) ->
127131
els_utils:to_binary(io_lib:format("Cannot find module ~p", [M]));
128132
error_msg(function, Id) ->
129-
els_utils:to_binary(io_lib:format("Cannot find definition for function ~s", [id_str(Id)])).
133+
els_utils:to_binary(io_lib:format("Cannot find definition for function ~s", [id_str(Id)]));
134+
error_msg(export, Id) ->
135+
els_utils:to_binary(io_lib:format("Function ~s is not exported.", [id_str(Id)])).
130136

131137
-spec id_str(els_poi:poi_id()) -> string().
132138
id_str(Id) ->
@@ -136,7 +142,7 @@ id_str(Id) ->
136142
end.
137143

138144
-spec has_definition(els_poi:poi(), els_dt_document:item(), _) ->
139-
true | {missing, function | module}.
145+
true | {missing, missing_reason()}.
140146
has_definition(#{data := #{imported := true}}, _Document, _Opts) ->
141147
%% Call to a bif
142148
true;
@@ -177,7 +183,9 @@ has_definition(
177183
case function_lookup(MFA) of
178184
true ->
179185
true;
180-
false ->
186+
{missing, export} ->
187+
true;
188+
{missing, function} ->
181189
case els_code_navigation:goto_definition(Uri, POI) of
182190
{ok, _Defs} ->
183191
true;
@@ -189,12 +197,14 @@ has_definition(#{id := {M, _F, _A} = MFA} = POI, _Document, _Opts) ->
189197
case function_lookup(MFA) of
190198
true ->
191199
true;
192-
false ->
200+
{missing, export} ->
201+
{missing, export};
202+
{missing, function} ->
193203
case els_utils:find_module(M) of
194204
{ok, Uri} ->
195205
case els_code_navigation:goto_definition(Uri, POI) of
196206
{ok, _Defs} ->
197-
true;
207+
function_lookup(MFA);
198208
{error, _Error} ->
199209
{missing, function}
200210
end;
@@ -205,13 +215,15 @@ has_definition(#{id := {M, _F, _A} = MFA} = POI, _Document, _Opts) ->
205215
has_definition(_POI, #{uri := _Uri}, _Opts) ->
206216
true.
207217

208-
-spec function_lookup(mfa()) -> boolean().
218+
-spec function_lookup(mfa()) -> true | {missing, missing_reason()}.
209219
function_lookup(MFA) ->
210-
case els_db:lookup(els_dt_functions:name(), MFA) of
220+
case els_dt_functions:lookup(MFA) of
211221
{ok, []} ->
212-
false;
213-
{ok, _} ->
214-
true
222+
{missing, function};
223+
{ok, [#{is_exported := true}]} ->
224+
true;
225+
{ok, [#{is_exported := false}]} ->
226+
{missing, export}
215227
end.
216228

217229
-spec lager_definition(atom(), integer()) -> boolean().

apps/els_lsp/src/els_dt_functions.erl

+13-8
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@
3737

3838
-record(els_dt_functions, {
3939
mfa :: mfa() | '_' | {atom(), '_', '_'},
40-
version :: version() | '_'
40+
version :: version() | '_',
41+
is_exported :: boolean() | '_'
4142
}).
4243
-type els_dt_functions() :: #els_dt_functions{}.
4344
-type version() :: null | integer().
4445
-type item() :: #{
4546
mfa := mfa(),
46-
version := version()
47+
version := version(),
48+
is_exported := boolean()
4749
}.
4850
-export_type([item/0]).
4951

@@ -65,21 +67,25 @@ opts() ->
6567
-spec from_item(item()) -> els_dt_functions().
6668
from_item(#{
6769
mfa := MFA,
68-
version := Version
70+
version := Version,
71+
is_exported := IsExported
6972
}) ->
7073
#els_dt_functions{
7174
mfa = MFA,
72-
version = Version
75+
version = Version,
76+
is_exported = IsExported
7377
}.
7478

7579
-spec to_item(els_dt_functions()) -> item().
7680
to_item(#els_dt_functions{
7781
mfa = MFA,
78-
version = Version
82+
version = Version,
83+
is_exported = IsExported
7984
}) ->
8085
#{
8186
mfa => MFA,
82-
version => Version
87+
version => Version,
88+
is_exported => IsExported
8389
}.
8490

8591
-spec insert(item()) -> ok | {error, any()}.
@@ -96,8 +102,7 @@ versioned_insert(#{mfa := MFA, version := Version} = Map) ->
96102
els_db:conditional_write(name(), MFA, Record, Condition).
97103

98104
-spec lookup(mfa()) -> {ok, [item()]}.
99-
lookup({M, _F, _A} = MFA) ->
100-
{ok, _Uris} = els_utils:find_modules(M),
105+
lookup(MFA) ->
101106
{ok, Items} = els_db:lookup(name(), MFA),
102107
{ok, [to_item(Item) || Item <- Items]}.
103108

apps/els_lsp/src/els_indexing.erl

+7-4
Original file line numberDiff line numberDiff line change
@@ -137,14 +137,17 @@ index_signature(M, Text, #{id := {F, A}, range := Range, data := #{args := Args}
137137
-spec index_functions(atom(), uri(), [els_poi:poi()], version()) -> ok.
138138
index_functions(M, Uri, POIs, Version) ->
139139
ok = els_dt_functions:versioned_delete_by_uri(Uri, Version),
140-
[index_function(M, POI, Version) || #{kind := function} = POI <- POIs],
140+
Exports = [{F, A} || #{id := {F, A}, kind := export_entry} <- POIs],
141+
[index_function(M, POI, Exports, Version) || #{kind := function} = POI <- POIs],
141142
ok.
142143

143-
-spec index_function(atom(), els_poi:poi(), version()) -> ok.
144-
index_function(M, #{id := {F, A}}, Version) ->
144+
-spec index_function(atom(), els_poi:poi(), els_poi:poi_id(), version()) -> ok.
145+
index_function(M, #{id := {F, A}}, Exports, Version) ->
146+
IsExported = lists:member({F, A}, Exports),
145147
els_dt_functions:versioned_insert(#{
146148
mfa => {M, F, A},
147-
version => Version
149+
version => Version,
150+
is_exported => IsExported
148151
}).
149152

150153
-spec index_references(atom(), uri(), [els_poi:poi()], version()) -> ok.

apps/els_lsp/test/els_diagnostics_SUITE.erl

+8
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,10 @@ crossref(_Config) ->
786786
#{
787787
message => <<"Cannot find definition for function lists:map/3">>,
788788
range => {{5, 8}, {5, 11}}
789+
},
790+
#{
791+
message => <<"Function lists:map_1/2 is not exported.">>,
792+
range => {{16, 10}, {16, 15}}
789793
}
790794
],
791795
Warnings = [],
@@ -802,6 +806,10 @@ crossref_compiler_enabled(_Config) ->
802806
#{
803807
message => <<"Cannot find definition for function lists:map/3">>,
804808
range => {{5, 8}, {5, 11}}
809+
},
810+
#{
811+
message => <<"Function lists:map_1/2 is not exported.">>,
812+
range => {{16, 10}, {16, 15}}
805813
}
806814
],
807815
Warnings = [],

0 commit comments

Comments
 (0)