Skip to content

Commit 29bb511

Browse files
authored
Allow to override the info callback in Macro.Env.define_import (#13628)
1 parent 478256b commit 29bb511

File tree

2 files changed

+56
-32
lines changed

2 files changed

+56
-32
lines changed

lib/elixir/lib/macro/env.ex

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,10 @@ defmodule Macro.Env do
349349
350350
* #{trace_option}
351351
352+
* `:info_callback` - a function to use instead of `c:Module.__info__/1`.
353+
The function will be invoked with `:functions` or `:macros` argument.
354+
It has to return a list of `{function, arity}` key value pairs
355+
352356
## Examples
353357
354358
iex> env = __ENV__
@@ -367,15 +371,27 @@ defmodule Macro.Env do
367371
iex> Macro.Env.lookup_import(env, {:is_odd, 1})
368372
[{:macro, Integer}]
369373
374+
## Resolver override
375+
376+
iex> env = __ENV__
377+
iex> Macro.Env.lookup_import(env, {:flatten, 1})
378+
[]
379+
iex> {:ok, env} = Macro.Env.define_import(env, [line: 10], SomeModule, [info_callback: fn :functions -> [{:flatten, 1}]; :macros -> [{:some, 2}]; end])
380+
iex> Macro.Env.lookup_import(env, {:flatten, 1})
381+
[{:function, SomeModule}]
382+
iex> Macro.Env.lookup_import(env, {:some, 2})
383+
[{:macro, SomeModule}]
384+
370385
"""
371386
@doc since: "1.17.0"
372-
@spec define_import(t, Macro.metadata(), module) :: {:ok, t} | {:error, String.t()}
387+
@spec define_import(t, Macro.metadata(), module, keyword) :: {:ok, t} | {:error, String.t()}
373388
def define_import(env, meta, module, opts \\ [])
374389
when is_list(meta) and is_atom(module) and is_list(opts) do
375390
{trace, opts} = Keyword.pop(opts, :trace, true)
376391
{warnings, opts} = Keyword.pop(opts, :emit_warnings, true)
392+
{info_callback, opts} = Keyword.pop(opts, :info_callback, nil)
377393

378-
result = :elixir_import.import(meta, module, opts, env, warnings, trace)
394+
result = :elixir_import.import(meta, module, opts, env, warnings, trace, info_callback)
379395
maybe_define_error(result, :elixir_import)
380396
end
381397

lib/elixir/src/elixir_import.erl

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,38 @@
22
%% between local functions and imports.
33
%% For imports dispatch, please check elixir_dispatch.
44
-module(elixir_import).
5-
-export([import/6, special_form/2, format_error/1]).
5+
-export([import/6, import/7, special_form/2, format_error/1]).
66
-compile(inline_list_funcs).
77
-include("elixir.hrl").
88

99
import(Meta, Ref, Opts, E, Warn, Trace) ->
10-
case import_only_except(Meta, Ref, Opts, E, Warn) of
10+
import(Meta, Ref, Opts, E, Warn, Trace, nil).
11+
12+
import(Meta, Ref, Opts, E, Warn, Trace, InfoCallback) when is_function(InfoCallback, 1) ->
13+
case import_only_except(Meta, Ref, Opts, E, Warn, InfoCallback) of
1114
{Functions, Macros, Added} ->
1215
Trace andalso elixir_env:trace({import, [{imported, Added} | Meta], Ref, Opts}, E),
1316
EI = E#{functions := Functions, macros := Macros},
1417
{ok, elixir_aliases:require(Meta, Ref, Opts, EI, Trace)};
1518

1619
{error, Reason} ->
1720
{error, Reason}
18-
end.
21+
end;
22+
import(Meta, Ref, Opts, E, Warn, Trace, _) ->
23+
import(Meta, Ref, Opts, E, Warn, Trace, info_callback(Ref)).
1924

20-
import_only_except(Meta, Ref, Opts, E, Warn) ->
25+
import_only_except(Meta, Ref, Opts, E, Warn, InfoCallback) ->
2126
MaybeOnly = lists:keyfind(only, 1, Opts),
2227

2328
case lists:keyfind(except, 1, Opts) of
2429
false ->
25-
import_only_except(Meta, Ref, MaybeOnly, false, E, Warn);
30+
import_only_except(Meta, Ref, MaybeOnly, false, E, Warn, InfoCallback);
2631

2732
{except, DupExcept} when is_list(DupExcept) ->
2833
case ensure_keyword_list(DupExcept) of
2934
ok ->
3035
Except = ensure_no_duplicates(DupExcept, except, Meta, E, Warn),
31-
import_only_except(Meta, Ref, MaybeOnly, Except, E, Warn);
36+
import_only_except(Meta, Ref, MaybeOnly, Except, E, Warn, InfoCallback);
3237

3338
error ->
3439
{error, {invalid_option, except, DupExcept}}
@@ -38,27 +43,27 @@ import_only_except(Meta, Ref, Opts, E, Warn) ->
3843
{error, {invalid_option, except, Other}}
3944
end.
4045

41-
import_only_except(Meta, Ref, MaybeOnly, Except, E, Warn) ->
46+
import_only_except(Meta, Ref, MaybeOnly, Except, E, Warn, InfoCallback) ->
4247
case MaybeOnly of
4348
{only, functions} ->
44-
{Added1, _Used1, Funs} = import_functions(Meta, Ref, Except, E, Warn),
49+
{Added1, _Used1, Funs} = import_functions(Meta, Ref, Except, E, Warn, InfoCallback),
4550
{Funs, keydelete(Ref, ?key(E, macros)), Added1};
4651

4752
{only, macros} ->
48-
{Added2, _Used2, Macs} = import_macros(Meta, Ref, Except, E, Warn),
53+
{Added2, _Used2, Macs} = import_macros(Meta, Ref, Except, E, Warn, InfoCallback),
4954
{keydelete(Ref, ?key(E, functions)), Macs, Added2};
5055

5156
{only, sigils} ->
52-
{Added1, _Used1, Funs} = import_sigil_functions(Meta, Ref, Except, E, Warn),
53-
{Added2, _Used2, Macs} = import_sigil_macros(Meta, Ref, Except, E, Warn),
57+
{Added1, _Used1, Funs} = import_sigil_functions(Meta, Ref, Except, E, Warn, InfoCallback),
58+
{Added2, _Used2, Macs} = import_sigil_macros(Meta, Ref, Except, E, Warn, InfoCallback),
5459
{Funs, Macs, Added1 or Added2};
5560

5661
{only, DupOnly} when is_list(DupOnly) ->
5762
case ensure_keyword_list(DupOnly) of
5863
ok when Except =:= false ->
5964
Only = ensure_no_duplicates(DupOnly, only, Meta, E, Warn),
60-
{Added1, Used1, Funs} = import_listed_functions(Meta, Ref, Only, E, Warn),
61-
{Added2, Used2, Macs} = import_listed_macros(Meta, Ref, Only, E, Warn),
65+
{Added1, Used1, Funs} = import_listed_functions(Meta, Ref, Only, E, Warn, InfoCallback),
66+
{Added2, Used2, Macs} = import_listed_macros(Meta, Ref, Only, E, Warn, InfoCallback),
6267
[Warn andalso elixir_errors:file_warn(Meta, E, ?MODULE, {invalid_import, {Ref, Name, Arity}}) ||
6368
{Name, Arity} <- (Only -- Used1) -- Used2],
6469
{Funs, Macs, Added1 or Added2};
@@ -74,37 +79,37 @@ import_only_except(Meta, Ref, MaybeOnly, Except, E, Warn) ->
7479
{error, {invalid_option, only, Other}};
7580

7681
false ->
77-
{Added1, _Used1, Funs} = import_functions(Meta, Ref, Except, E, Warn),
78-
{Added2, _Used2, Macs} = import_macros(Meta, Ref, Except, E, Warn),
82+
{Added1, _Used1, Funs} = import_functions(Meta, Ref, Except, E, Warn, InfoCallback),
83+
{Added2, _Used2, Macs} = import_macros(Meta, Ref, Except, E, Warn, InfoCallback),
7984
{Funs, Macs, Added1 or Added2}
8085
end.
8186

82-
import_listed_functions(Meta, Ref, Only, E, Warn) ->
83-
New = intersection(Only, get_functions(Ref)),
87+
import_listed_functions(Meta, Ref, Only, E, Warn, InfoCallback) ->
88+
New = intersection(Only, InfoCallback(functions)),
8489
calculate_key(Meta, Ref, ?key(E, functions), New, E, Warn).
8590

86-
import_listed_macros(Meta, Ref, Only, E, Warn) ->
87-
New = intersection(Only, get_macros(Ref)),
91+
import_listed_macros(Meta, Ref, Only, E, Warn, InfoCallback) ->
92+
New = intersection(Only, InfoCallback(macros)),
8893
calculate_key(Meta, Ref, ?key(E, macros), New, E, Warn).
8994

90-
import_functions(Meta, Ref, Except, E, Warn) ->
95+
import_functions(Meta, Ref, Except, E, Warn, InfoCallback) ->
9196
calculate_except(Meta, Ref, Except, ?key(E, functions), E, Warn, fun() ->
92-
get_functions(Ref)
97+
InfoCallback(functions)
9398
end).
9499

95-
import_macros(Meta, Ref, Except, E, Warn) ->
100+
import_macros(Meta, Ref, Except, E, Warn, InfoCallback) ->
96101
calculate_except(Meta, Ref, Except, ?key(E, macros), E, Warn, fun() ->
97-
get_macros(Ref)
102+
InfoCallback(macros)
98103
end).
99104

100-
import_sigil_functions(Meta, Ref, Except, E, Warn) ->
105+
import_sigil_functions(Meta, Ref, Except, E, Warn, InfoCallback) ->
101106
calculate_except(Meta, Ref, Except, ?key(E, functions), E, Warn, fun() ->
102-
filter_sigils(get_functions(Ref))
107+
filter_sigils(InfoCallback(functions))
103108
end).
104109

105-
import_sigil_macros(Meta, Ref, Except, E, Warn) ->
110+
import_sigil_macros(Meta, Ref, Except, E, Warn, InfoCallback) ->
106111
calculate_except(Meta, Ref, Except, ?key(E, macros), E, Warn, fun() ->
107-
filter_sigils(get_macros(Ref))
112+
filter_sigils(InfoCallback(macros))
108113
end).
109114

110115
calculate_except(Meta, Key, false, Old, E, Warn, Existing) ->
@@ -134,14 +139,17 @@ calculate_key(Meta, Key, Old, New, E, Warn) ->
134139

135140
%% Retrieve functions and macros from modules
136141

137-
get_functions(Module) ->
142+
info_callback(Module) ->
143+
fun(Kind) -> info_callback(Module, Kind) end.
144+
145+
info_callback(Module, functions) ->
138146
try
139147
Module:'__info__'(functions)
140148
catch
141149
error:undef -> remove_internals(Module:module_info(exports))
142-
end.
150+
end;
143151

144-
get_macros(Module) ->
152+
info_callback(Module, macros) ->
145153
try
146154
Module:'__info__'(macros)
147155
catch

0 commit comments

Comments
 (0)