@@ -8,8 +8,60 @@ defmodule ElixirSense.Core.Compiler do
88 alias ElixirSense.Core.Normalized.Macro.Env , as: NormalizedMacroEnv
99 alias ElixirSense.Core.State.ModFunInfo
1010
11- @ env :elixir_env . new ( )
12- def env , do: @ env
11+ @ trace_key :elixir_sense_trace
12+
13+ def trace ( event , env ) do
14+ trace = get_trace ( )
15+ Process . put ( @ trace_key , [ { event , env } | trace ] )
16+ :ok
17+ end
18+
19+ defp get_trace do
20+ Process . get ( @ trace_key , [ ] )
21+ end
22+
23+ defp clear_trace do
24+ Process . delete ( @ trace_key )
25+ end
26+
27+ def collect_traces ( state ) do
28+ trace = get_trace ( )
29+
30+ state =
31+ Enum . reduce ( trace , state , fn { event , env } , acc ->
32+ case event do
33+ { :alias_reference , meta , alias } ->
34+ # emitted by Macro.expand/2 and Macro.expand_once/2
35+ acc
36+ |> State . add_call_to_line ( { alias , nil , nil } , meta )
37+ |> State . add_current_env_to_line ( meta , env )
38+
39+ { :alias , meta , module , _as , _opts } ->
40+ # emitted by Macro.Env.define_alias/3 and Macro.Env.define_require/3
41+ acc
42+ |> State . add_call_to_line ( { module , nil , nil } , meta )
43+ |> State . add_current_env_to_line ( meta , env )
44+
45+ { kind , meta , module , _opts } when kind in [ :import , :require ] ->
46+ # emitted by Macro.Env.define_import/3 and Macro.Env.define_require/3
47+ acc
48+ |> State . add_call_to_line ( { module , nil , nil } , meta )
49+ |> State . add_current_env_to_line ( meta , env )
50+
51+ _ ->
52+ Logger . warning ( "Unhandled trace event: #{ inspect ( event ) } " )
53+ acc
54+ end
55+ end )
56+
57+ clear_trace ( )
58+ state
59+ end
60+
61+ def env do
62+ env = :elixir_env . new ( )
63+ % { env | tracers: [ __MODULE__ ] }
64+ end
1365
1466 def expand ( ast , state , env ) do
1567 try do
@@ -116,23 +168,8 @@ defmodule ElixirSense.Core.Compiler do
116168
117169 # __aliases__
118170
119- defp do_expand ( { :__aliases__ , meta , [ head | tail ] = list } , state , env ) do
120- case NormalizedMacroEnv . expand_alias ( env , meta , list , trace: false ) do
121- { :alias , alias } ->
122- # TODO track alias
123- { alias , state , env }
124-
125- :error ->
126- { head , state , env } = expand ( head , state , env )
127-
128- if is_atom ( head ) do
129- # TODO track alias
130- { Module . concat ( [ head | tail ] ) , state , env }
131- else
132- # elixir raises here invalid_alias
133- { { :__aliases__ , meta , [ head | tail ] } , state , env }
134- end
135- end
171+ defp do_expand ( { :__aliases__ , _ , _ } = alias , state , env ) do
172+ expand_aliases ( alias , state , env , true )
136173 end
137174
138175 # require, alias, import
@@ -161,13 +198,13 @@ defmodule ElixirSense.Core.Compiler do
161198 |> State . add_first_alias_positions ( env , meta )
162199 |> State . add_current_env_to_line ( meta , env )
163200
164- # no need to call expand_without_aliases_report - we never report
165- { arg , state , env } = expand ( arg , state , env )
201+ { arg , state , env } = expand_without_aliases_report ( arg , state , env )
166202 { opts , state , env } = expand_opts ( [ :as , :warn ] , no_alias_opts ( opts ) , state , env )
167203
168204 if is_atom ( arg ) do
169- case NormalizedMacroEnv . define_alias ( env , meta , arg , [ trace: false ] ++ opts ) do
205+ case NormalizedMacroEnv . define_alias ( env , meta , arg , [ trace: true ] ++ opts ) do
170206 { :ok , env } ->
207+ state = collect_traces ( state )
171208 { arg , state , env }
172209
173210 { :error , _ } ->
@@ -185,8 +222,7 @@ defmodule ElixirSense.Core.Compiler do
185222 state
186223 |> State . add_current_env_to_line ( meta , env )
187224
188- # no need to call expand_without_aliases_report - we never report
189- { arg , state , env } = expand ( arg , state , env )
225+ { arg , state , env } = expand_without_aliases_report ( arg , state , env )
190226
191227 { opts , state , env } =
192228 expand_opts ( [ :as , :warn ] , no_alias_opts ( opts ) , state , env )
@@ -197,8 +233,9 @@ defmodule ElixirSense.Core.Compiler do
197233 if is_atom ( arg ) do
198234 # elixir calls here :elixir_aliases.ensure_loaded(meta, e_ref, et)
199235 # and optionally waits until required module is compiled
200- case NormalizedMacroEnv . define_require ( env , meta , arg , [ trace: false ] ++ opts ) do
236+ case NormalizedMacroEnv . define_require ( env , meta , arg , [ trace: true ] ++ opts ) do
201237 { :ok , env } ->
238+ state = collect_traces ( state )
202239 { arg , state , env }
203240
204241 { :error , _ } ->
@@ -216,21 +253,21 @@ defmodule ElixirSense.Core.Compiler do
216253 state
217254 |> State . add_current_env_to_line ( meta , env )
218255
219- # no need to call expand_without_aliases_report - we never report
220- { arg , state , env } = expand ( arg , state , env )
256+ { arg , state , env } = expand_without_aliases_report ( arg , state , env )
221257 { opts , state , env } = expand_opts ( [ :only , :except , :warn ] , opts , state , env )
222258
223259 if is_atom ( arg ) do
224260 opts =
225261 opts
226262 |> Keyword . merge (
227- trace: false ,
263+ trace: true ,
228264 emit_warnings: false ,
229265 info_callback: import_info_callback ( arg , state )
230266 )
231267
232268 case NormalizedMacroEnv . define_import ( env , meta , arg , opts ) do
233269 { :ok , env } ->
270+ state = collect_traces ( state )
234271 { arg , state , env }
235272
236273 _ ->
@@ -274,15 +311,15 @@ defmodule ElixirSense.Core.Compiler do
274311 # elixir checks if context is not match
275312 state = State . add_current_env_to_line ( state , meta , env )
276313
277- { escape_map ( escape_env_entries ( meta , state , env ) ) , state , env }
314+ { escape_map ( escape_env_entries ( meta , state , % { env | tracers: [ ] } ) ) , state , env }
278315 end
279316
280317 defp do_expand ( { { :. , dot_meta , [ { :__ENV__ , meta , atom } , field ] } , call_meta , [ ] } , s , e )
281318 when is_atom ( atom ) and is_atom ( field ) do
282319 # elixir checks if context is not match
283320 s = State . add_current_env_to_line ( s , call_meta , e )
284321
285- env = escape_env_entries ( meta , s , e )
322+ env = escape_env_entries ( meta , s , % { e | tracers: [ ] } )
286323
287324 case Map . fetch ( env , field ) do
288325 { :ok , value } -> { value , s , e }
@@ -1527,6 +1564,8 @@ defmodule ElixirSense.Core.Compiler do
15271564 function: { :__impl__ , 1 }
15281565 } )
15291566
1567+ state = collect_traces ( state )
1568+
15301569 { for , state } =
15311570 if is_atom ( for ) or ( is_list ( for ) and Enum . all? ( for , & is_atom / 1 ) ) do
15321571 { for , state }
@@ -1602,6 +1641,8 @@ defmodule ElixirSense.Core.Compiler do
16021641 { :"Elixir.__Unknown__" , env }
16031642 end
16041643
1644+ state = collect_traces ( state )
1645+
16051646 # elixir emits a special require directive with :defined key set in meta
16061647 # require expand does alias, updates context_modules and runtime_modules
16071648 # we do it here instead
@@ -2088,7 +2129,7 @@ defmodule ElixirSense.Core.Compiler do
20882129 # see https://github.com/elixir-lang/elixir/pull/12451#issuecomment-1461393633
20892130 defp alias_defmodule ( { :__aliases__ , meta , [ :"Elixir" , t ] = x } , module , env ) do
20902131 alias = String . to_atom ( "Elixir." <> Atom . to_string ( t ) )
2091- { :ok , env } = NormalizedMacroEnv . define_alias ( env , meta , alias , as: alias , trace: false )
2132+ { :ok , env } = NormalizedMacroEnv . define_alias ( env , meta , alias , as: alias , trace: true )
20922133 { module , env }
20932134 end
20942135 end
@@ -2103,7 +2144,7 @@ defmodule ElixirSense.Core.Compiler do
21032144 defp alias_defmodule ( { :__aliases__ , meta , [ h | t ] } , _module , env ) when is_atom ( h ) do
21042145 module = Module . concat ( [ env . module , h ] )
21052146 alias = String . to_atom ( "Elixir." <> Atom . to_string ( h ) )
2106- { :ok , env } = NormalizedMacroEnv . define_alias ( env , meta , module , as: alias , trace: false )
2147+ { :ok , env } = NormalizedMacroEnv . define_alias ( env , meta , module , as: alias , trace: true )
21072148
21082149 case t do
21092150 [ ] -> { module , env }
@@ -2334,7 +2375,7 @@ defmodule ElixirSense.Core.Compiler do
23342375 # end
23352376
23362377 defp expand_multi_alias_call ( kind , meta , base , refs , opts , state , env ) do
2337- { base_ref , state , env } = expand ( base , state , env )
2378+ { base_ref , state , env } = expand_without_aliases_report ( base , state , env )
23382379
23392380 fun = fn
23402381 { :__aliases__ , _ , ref } , state , env ->
@@ -2730,6 +2771,51 @@ defmodule ElixirSense.Core.Compiler do
27302771 @ internals [ { :module_info , 1 } , { :module_info , 0 } ]
27312772 end
27322773
2774+ defp expand_without_aliases_report ( { :__aliases__ , _ , _ } = alias , state , env ) do
2775+ expand_aliases ( alias , state , env , false )
2776+ end
2777+
2778+ defp expand_without_aliases_report ( other , state , env ) do
2779+ expand ( other , state , env )
2780+ end
2781+
2782+ defp expand_aliases ( { :__aliases__ , meta , [ head | tail ] = list } , state , env , report ) do
2783+ case NormalizedMacroEnv . expand_alias ( env , meta , list , trace: false ) do
2784+ { :alias , alias } ->
2785+ state =
2786+ if report do
2787+ state
2788+ |> State . add_call_to_line ( { alias , nil , nil } , meta )
2789+ |> State . add_current_env_to_line ( meta , env )
2790+ else
2791+ state
2792+ end
2793+
2794+ { alias , state , env }
2795+
2796+ :error ->
2797+ { head , state , env } = expand ( head , state , env )
2798+
2799+ if is_atom ( head ) do
2800+ alias = Module . concat ( [ head | tail ] )
2801+
2802+ state =
2803+ if report do
2804+ state
2805+ |> State . add_call_to_line ( { alias , nil , nil } , meta )
2806+ |> State . add_current_env_to_line ( meta , env )
2807+ else
2808+ state
2809+ end
2810+
2811+ { alias , state , env }
2812+ else
2813+ # elixir raises here invalid_alias
2814+ { { :__aliases__ , meta , [ head | tail ] } , state , env }
2815+ end
2816+ end
2817+ end
2818+
27332819 defp import_info_callback ( module , state ) do
27342820 fn kind ->
27352821 if Map . has_key? ( state . mods_funs_to_positions , { module , nil , nil } ) do
0 commit comments