Skip to content

Commit f094199

Browse files
committed
improvements to call tracing
call tracing during expansion now fully mimics what elixir compiler does when emitting trace events applied tracing fixes to import quoted and super calls from elixir main added custom implementation of MacroEnv.expand_import
1 parent 145ca7a commit f094199

File tree

14 files changed

+1172
-664
lines changed

14 files changed

+1172
-664
lines changed

lib/elixir_sense/core/compiler.ex

+83-63
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,35 @@ defmodule ElixirSense.Core.Compiler do
3333
{:alias_reference, meta, alias} ->
3434
# emitted by Macro.expand/2 and Macro.expand_once/2
3535
acc
36-
|> State.add_call_to_line({alias, nil, nil}, meta)
37-
|> State.add_current_env_to_line(meta, env)
36+
|> State.add_call_to_line({alias, nil, nil}, meta, :alias_reference)
3837

3938
{:alias, meta, module, _as, _opts} ->
4039
# emitted by Macro.Env.define_alias/3 and Macro.Env.define_require/3
4140
acc
42-
|> State.add_call_to_line({module, nil, nil}, meta)
43-
|> State.add_current_env_to_line(meta, env)
41+
|> State.add_call_to_line({module, nil, nil}, meta, :alias)
4442

4543
{kind, meta, module, _opts} when kind in [:import, :require] ->
4644
# emitted by Macro.Env.define_import/3 and Macro.Env.define_require/3
4745
acc
48-
|> State.add_call_to_line({module, nil, nil}, meta)
49-
|> State.add_current_env_to_line(meta, env)
46+
|> State.add_call_to_line({module, nil, nil}, meta, kind)
47+
48+
{kind, meta, receiver, name, arity}
49+
when kind in [:remote_function, :remote_macro, :imported_function, :imported_macro] ->
50+
# emitted by MacroEnv.expand_require/6, MacroEnv.expand_import/5
51+
acc
52+
|> State.add_call_to_line({receiver, name, arity}, meta, kind)
53+
54+
{:imported_quoted, meta, module, name, arities} ->
55+
for arity <- arities, reduce: acc do
56+
acc ->
57+
acc
58+
|> State.add_call_to_line({module, name, arity}, meta, :imported_quoted)
59+
end
60+
61+
{kind, meta, name, arity} when kind in [:local_function, :local_macro] ->
62+
# emitted by MacroEnv.expand_require/6, MacroEnv.expand_import/5
63+
acc
64+
|> State.add_call_to_line({env.module, name, arity}, meta, kind)
5065

5166
_ ->
5267
Logger.warning("Unhandled trace event: #{inspect(event)}")
@@ -204,7 +219,6 @@ defmodule ElixirSense.Core.Compiler do
204219
if is_atom(arg) do
205220
case NormalizedMacroEnv.define_alias(env, meta, arg, [trace: true] ++ opts) do
206221
{:ok, env} ->
207-
state = collect_traces(state)
208222
{arg, state, env}
209223

210224
{:error, _} ->
@@ -235,7 +249,6 @@ defmodule ElixirSense.Core.Compiler do
235249
# and optionally waits until required module is compiled
236250
case NormalizedMacroEnv.define_require(env, meta, arg, [trace: true] ++ opts) do
237251
{:ok, env} ->
238-
state = collect_traces(state)
239252
{arg, state, env}
240253

241254
{:error, _} ->
@@ -267,7 +280,6 @@ defmodule ElixirSense.Core.Compiler do
267280

268281
case NormalizedMacroEnv.define_import(env, meta, arg, opts) do
269282
{:ok, env} ->
270-
state = collect_traces(state)
271283
{arg, state, env}
272284

273285
_ ->
@@ -456,12 +468,7 @@ defmodule ElixirSense.Core.Compiler do
456468
when is_atom(context) and is_integer(arity) do
457469
case resolve_super(meta, arity, s, e) do
458470
{kind, name, _} when kind in [:def, :defp] ->
459-
s =
460-
s
461-
|> State.add_call_to_line({nil, name, arity}, super_meta)
462-
|> State.add_current_env_to_line(super_meta, e)
463-
464-
{{:&, meta, [{:/, arity_meta, [{name, super_meta, context}, arity]}]}, s, e}
471+
expand({:&, meta, [{:/, arity_meta, [{name, super_meta, context}, arity]}]}, s, e)
465472

466473
_ ->
467474
expand_fn_capture(meta, expr, s, e)
@@ -535,7 +542,7 @@ defmodule ElixirSense.Core.Compiler do
535542

536543
sa =
537544
sa
538-
|> State.add_call_to_line({nil, name, arity}, meta)
545+
|> State.add_call_to_line({e.module, name, arity}, meta, :local_function)
539546
|> State.add_current_env_to_line(meta, ea)
540547

541548
{{:super, [{:super, {kind, name}} | meta], e_args}, sa, ea}
@@ -705,17 +712,38 @@ defmodule ElixirSense.Core.Compiler do
705712
allow_locals = match?({n, a} when fun != n or arity != a, env.function)
706713

707714
case NormalizedMacroEnv.expand_import(env, meta, fun, arity,
708-
trace: false,
715+
trace: true,
709716
allow_locals: allow_locals,
710-
check_deprecations: false
717+
check_deprecations: false,
718+
local_for_callback: fn meta, name, arity, kinds, e ->
719+
case state.mods_funs_to_positions[{e.module, name, arity}] do
720+
nil ->
721+
false
722+
723+
%ModFunInfo{} = info ->
724+
category = ModFunInfo.get_category(info)
725+
definition_line = info.positions |> List.first() |> elem(0)
726+
usage_line = meta |> Keyword.get(:line)
727+
728+
if ModFunInfo.get_def_kind(info) in kinds and
729+
(category != :macro or usage_line >= definition_line) do
730+
if macro_exported?(e.module, name, arity) do
731+
proper_name = :"MACRO-#{name}"
732+
proper_arity = arity + 1
733+
Function.capture(e.module, proper_name, proper_arity)
734+
else
735+
# return a fake macro
736+
true
737+
end
738+
else
739+
false
740+
end
741+
end
742+
end
711743
) do
712744
{:macro, module, callback} ->
713745
# NOTE there is a subtle difference - callback will call expander with state derived from env via
714746
# :elixir_env.env_to_ex(env) possibly losing some details. Jose Valim is convinced this is not a problem
715-
state =
716-
state
717-
|> State.add_call_to_line({module, fun, length(args)}, meta)
718-
|> State.add_current_env_to_line(meta, env)
719747

720748
expand_macro(meta, module, fun, args, callback, state, env)
721749

@@ -751,35 +779,55 @@ defmodule ElixirSense.Core.Compiler do
751779
defp do_expand({{:., dot_meta, [module, fun]}, meta, args}, state, env)
752780
when (is_tuple(module) or is_atom(module)) and is_atom(fun) and is_list(meta) and
753781
is_list(args) do
754-
# dbg({module, fun, args})
755782
{module, state_l, env} = expand(module, State.prepare_write(state, env), env)
756783
arity = length(args)
757784

758785
if is_atom(module) do
759786
case __MODULE__.Rewrite.inline(module, fun, arity) do
760787
{ar, an} ->
788+
state_l =
789+
state_l
790+
|> State.add_call_to_line({module, fun, arity}, meta, :remote_function)
791+
|> State.add_current_env_to_line(meta, env)
792+
761793
expand_remote(ar, dot_meta, an, meta, args, state, state_l, env)
762794

763795
false ->
764796
case NormalizedMacroEnv.expand_require(env, meta, module, fun, arity,
765-
trace: false,
797+
trace: true,
766798
check_deprecations: false
767799
) do
768800
{:macro, module, callback} ->
769801
# NOTE there is a subtle difference - callback will call expander with state derived from env via
770802
# :elixir_env.env_to_ex(env) possibly losing some details. Jose Valim is convinced this is not a problem
771-
state_l =
803+
# elixir expands the macro with original state, we pass state after left expand and need to revert some props
804+
state_l = %{
772805
state_l
773-
|> State.add_call_to_line({module, fun, length(args)}, meta)
774-
|> State.add_current_env_to_line(meta, env)
806+
| vars: state.vars,
807+
prematch: state.prematch,
808+
unused: state.unused,
809+
stacktrace: state.stacktrace,
810+
caller: state.caller,
811+
runtime_modules: state.runtime_modules
812+
}
775813

776814
expand_macro(meta, module, fun, args, callback, state_l, env)
777815

778816
:error ->
817+
state_l =
818+
state_l
819+
|> State.add_call_to_line({module, fun, arity}, meta, :remote_function)
820+
|> State.add_current_env_to_line(meta, env)
821+
779822
expand_remote(module, dot_meta, fun, meta, args, state, state_l, env)
780823
end
781824
end
782825
else
826+
state_l =
827+
state_l
828+
|> State.add_call_to_line({module, fun, arity}, meta, :remote_function)
829+
|> State.add_current_env_to_line(meta, env)
830+
783831
expand_remote(module, dot_meta, fun, meta, args, state, state_l, env)
784832
end
785833
end
@@ -797,7 +845,7 @@ defmodule ElixirSense.Core.Compiler do
797845

798846
sa =
799847
sa
800-
|> State.add_call_to_line({nil, e_expr, length(e_args)}, dot_meta)
848+
|> State.add_call_to_line({nil, e_expr, length(e_args)}, dot_meta, :anonymous_function)
801849
|> State.add_current_env_to_line(meta, e)
802850

803851
{{{:., dot_meta, [e_expr]}, meta, e_args}, sa, ea}
@@ -1502,6 +1550,8 @@ defmodule ElixirSense.Core.Compiler do
15021550
{ast, state, env} =
15031551
expand_macro_callback!(meta, Kernel, :defprotocol, args, callback, state, env)
15041552

1553+
# TODO
1554+
# [warning] Unable to expand ast node {:defprotocol, [end_of_expression: [newlines: 1, line: 3, column: 4], do: [line: 1, column: 19], end: [line: 3, column: 1], line: 1, column: 1], [{:__aliases__, [last: [line: 1, column: 13], line: 1, column: 13], [:Proto]}, [do: {:def, [end_of_expression: [newlines: 1, line: 2, column: 20], line: 2, column: 3], [{:reverse, [closing: [line: 2, column: 19], line: 2, column: 7], [{:term, [line: 2, column: 15], nil}]}]}]]}: ** (MatchError) no match of right hand side value: []
15051555
[module] = env.context_modules -- original_env.context_modules
15061556
# add behaviour_info builtin
15071557
# generate callbacks as macro expansion currently fails
@@ -1564,8 +1614,6 @@ defmodule ElixirSense.Core.Compiler do
15641614
function: {:__impl__, 1}
15651615
})
15661616

1567-
state = collect_traces(state)
1568-
15691617
{for, state} =
15701618
if is_atom(for) or (is_list(for) and Enum.all?(for, &is_atom/1)) do
15711619
{for, state}
@@ -1641,8 +1689,6 @@ defmodule ElixirSense.Core.Compiler do
16411689
{:"Elixir.__Unknown__", env}
16421690
end
16431691

1644-
state = collect_traces(state)
1645-
16461692
# elixir emits a special require directive with :defined key set in meta
16471693
# require expand does alias, updates context_modules and runtime_modules
16481694
# we do it here instead
@@ -2167,11 +2213,6 @@ defmodule ElixirSense.Core.Compiler do
21672213
# look for cursor in discarded args
21682214
{_ast, sl, _env} = expand(args, sl, e)
21692215

2170-
sl =
2171-
sl
2172-
|> State.add_call_to_line({receiver, right, length(args)}, meta)
2173-
|> State.add_current_env_to_line(meta, e)
2174-
21752216
{{{:., dot_meta, [receiver, right]}, meta, []}, sl, e}
21762217

21772218
context == nil ->
@@ -2190,7 +2231,6 @@ defmodule ElixirSense.Core.Compiler do
21902231
{:ok, rewritten} ->
21912232
s =
21922233
State.close_write(sa, s)
2193-
|> State.add_call_to_line({receiver, right, length(e_args)}, meta)
21942234
|> State.add_current_env_to_line(meta, e)
21952235

21962236
{rewritten, s, ea}
@@ -2199,7 +2239,6 @@ defmodule ElixirSense.Core.Compiler do
21992239
# elixir raises here elixir_rewrite
22002240
s =
22012241
State.close_write(sa, s)
2202-
|> State.add_call_to_line({receiver, right, length(e_args)}, meta)
22032242
|> State.add_current_env_to_line(meta, e)
22042243

22052244
{{{:., dot_meta, [receiver, right]}, attached_meta, e_args}, s, ea}
@@ -2224,7 +2263,6 @@ defmodule ElixirSense.Core.Compiler do
22242263
# elixir raises here elixir_rewrite
22252264
s =
22262265
sa
2227-
|> State.add_call_to_line({receiver, right, length(e_args)}, meta)
22282266
|> State.add_current_env_to_line(meta, e)
22292267

22302268
{{{:., dot_meta, [receiver, right]}, meta, e_args}, s, ea}
@@ -2239,7 +2277,6 @@ defmodule ElixirSense.Core.Compiler do
22392277

22402278
s =
22412279
State.close_write(sa, s)
2242-
|> State.add_call_to_line({receiver, right, length(e_args)}, meta)
22432280
|> State.add_current_env_to_line(meta, e)
22442281

22452282
{{{:., dot_meta, [receiver, right]}, meta, e_args}, s, ea}
@@ -2282,7 +2319,7 @@ defmodule ElixirSense.Core.Compiler do
22822319

22832320
state =
22842321
state
2285-
|> State.add_call_to_line({nil, fun, length(args)}, meta)
2322+
|> State.add_call_to_line({env.module, fun, length(args)}, meta, :local_function)
22862323
|> State.add_current_env_to_line(meta, env)
22872324

22882325
{args, state, env} = expand_args(args, state, env)
@@ -2410,13 +2447,7 @@ defmodule ElixirSense.Core.Compiler do
24102447

24112448
case state.mods_funs_to_positions[{module, name, arity}] do
24122449
%ModFunInfo{overridable: {true, _}} = info ->
2413-
kind =
2414-
case info.type do
2415-
:defdelegate -> :def
2416-
:defguard -> :defmacro
2417-
:defguardp -> :defmacrop
2418-
other -> other
2419-
end
2450+
kind = ModFunInfo.get_def_kind(info)
24202451

24212452
hidden = Map.get(info.meta, :hidden, false)
24222453
# def meta is not used anyway so let's pass empty
@@ -2451,22 +2482,12 @@ defmodule ElixirSense.Core.Compiler do
24512482
{{:remote, remote, fun, arity}, require_meta, dot_meta, se, ee} ->
24522483
attached_meta = attach_runtime_module(remote, require_meta, s, e)
24532484

2454-
se =
2455-
se
2456-
|> State.add_call_to_line({remote, fun, arity}, attached_meta)
2457-
|> State.add_current_env_to_line(attached_meta, ee)
2458-
24592485
{{:&, meta, [{:/, [], [{{:., dot_meta, [remote, fun]}, attached_meta, []}, arity]}]}, se,
24602486
ee}
24612487

24622488
{{:local, fun, arity}, local_meta, _, se, ee} ->
24632489
# elixir raises undefined_local_capture if ee.function is nil
24642490

2465-
se =
2466-
se
2467-
|> State.add_call_to_line({nil, fun, arity}, local_meta)
2468-
|> State.add_current_env_to_line(local_meta, ee)
2469-
24702491
{{:&, meta, [{:/, [], [{fun, local_meta, nil}, arity]}]}, se, ee}
24712492

24722493
{:expand, expr, se, ee} ->
@@ -2780,13 +2801,13 @@ defmodule ElixirSense.Core.Compiler do
27802801
end
27812802

27822803
defp expand_aliases({:__aliases__, meta, [head | tail] = list}, state, env, report) do
2804+
# TODO pass true to track alias_expansion?
27832805
case NormalizedMacroEnv.expand_alias(env, meta, list, trace: false) do
27842806
{:alias, alias} ->
27852807
state =
27862808
if report do
27872809
state
2788-
|> State.add_call_to_line({alias, nil, nil}, meta)
2789-
|> State.add_current_env_to_line(meta, env)
2810+
|> State.add_call_to_line({alias, nil, nil}, meta, :alias_reference)
27902811
else
27912812
state
27922813
end
@@ -2802,8 +2823,7 @@ defmodule ElixirSense.Core.Compiler do
28022823
state =
28032824
if report do
28042825
state
2805-
|> State.add_call_to_line({alias, nil, nil}, meta)
2806-
|> State.add_current_env_to_line(meta, env)
2826+
|> State.add_call_to_line({alias, nil, nil}, meta, :alias_reference)
28072827
else
28082828
state
28092829
end

lib/elixir_sense/core/compiler/bitstring.ex

-1
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,6 @@ defmodule ElixirSense.Core.Compiler.Bitstring do
196196

197197
# TODO how to check for cursor here?
198198
expanded = Compiler.Macro.expand(ha, Map.put(e, :line, Utils.get_line(meta)))
199-
s = Compiler.collect_traces(s)
200199

201200
case expanded do
202201
^ha ->

lib/elixir_sense/core/compiler/clauses.ex

-1
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,6 @@ defmodule ElixirSense.Core.Compiler.Clauses do
614614
defp expand_rescue({_, meta, _} = arg, s, e) do
615615
# TODO how to check for cursor here?
616616
expanded = Compiler.Macro.expand_once(arg, %{e | line: Utils.get_line(meta)})
617-
s = Compiler.collect_traces(s)
618617

619618
case expanded do
620619
^arg ->

0 commit comments

Comments
 (0)