@@ -8,8 +8,60 @@ defmodule ElixirSense.Core.Compiler do
8
8
alias ElixirSense.Core.Normalized.Macro.Env , as: NormalizedMacroEnv
9
9
alias ElixirSense.Core.State.ModFunInfo
10
10
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
13
65
14
66
def expand ( ast , state , env ) do
15
67
try do
@@ -116,23 +168,8 @@ defmodule ElixirSense.Core.Compiler do
116
168
117
169
# __aliases__
118
170
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 )
136
173
end
137
174
138
175
# require, alias, import
@@ -161,13 +198,13 @@ defmodule ElixirSense.Core.Compiler do
161
198
|> State . add_first_alias_positions ( env , meta )
162
199
|> State . add_current_env_to_line ( meta , env )
163
200
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 )
166
202
{ opts , state , env } = expand_opts ( [ :as , :warn ] , no_alias_opts ( opts ) , state , env )
167
203
168
204
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
170
206
{ :ok , env } ->
207
+ state = collect_traces ( state )
171
208
{ arg , state , env }
172
209
173
210
{ :error , _ } ->
@@ -185,8 +222,7 @@ defmodule ElixirSense.Core.Compiler do
185
222
state
186
223
|> State . add_current_env_to_line ( meta , env )
187
224
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 )
190
226
191
227
{ opts , state , env } =
192
228
expand_opts ( [ :as , :warn ] , no_alias_opts ( opts ) , state , env )
@@ -197,8 +233,9 @@ defmodule ElixirSense.Core.Compiler do
197
233
if is_atom ( arg ) do
198
234
# elixir calls here :elixir_aliases.ensure_loaded(meta, e_ref, et)
199
235
# 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
201
237
{ :ok , env } ->
238
+ state = collect_traces ( state )
202
239
{ arg , state , env }
203
240
204
241
{ :error , _ } ->
@@ -216,21 +253,21 @@ defmodule ElixirSense.Core.Compiler do
216
253
state
217
254
|> State . add_current_env_to_line ( meta , env )
218
255
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 )
221
257
{ opts , state , env } = expand_opts ( [ :only , :except , :warn ] , opts , state , env )
222
258
223
259
if is_atom ( arg ) do
224
260
opts =
225
261
opts
226
262
|> Keyword . merge (
227
- trace: false ,
263
+ trace: true ,
228
264
emit_warnings: false ,
229
265
info_callback: import_info_callback ( arg , state )
230
266
)
231
267
232
268
case NormalizedMacroEnv . define_import ( env , meta , arg , opts ) do
233
269
{ :ok , env } ->
270
+ state = collect_traces ( state )
234
271
{ arg , state , env }
235
272
236
273
_ ->
@@ -274,15 +311,15 @@ defmodule ElixirSense.Core.Compiler do
274
311
# elixir checks if context is not match
275
312
state = State . add_current_env_to_line ( state , meta , env )
276
313
277
- { escape_map ( escape_env_entries ( meta , state , env ) ) , state , env }
314
+ { escape_map ( escape_env_entries ( meta , state , % { env | tracers: [ ] } ) ) , state , env }
278
315
end
279
316
280
317
defp do_expand ( { { :. , dot_meta , [ { :__ENV__ , meta , atom } , field ] } , call_meta , [ ] } , s , e )
281
318
when is_atom ( atom ) and is_atom ( field ) do
282
319
# elixir checks if context is not match
283
320
s = State . add_current_env_to_line ( s , call_meta , e )
284
321
285
- env = escape_env_entries ( meta , s , e )
322
+ env = escape_env_entries ( meta , s , % { e | tracers: [ ] } )
286
323
287
324
case Map . fetch ( env , field ) do
288
325
{ :ok , value } -> { value , s , e }
@@ -1527,6 +1564,8 @@ defmodule ElixirSense.Core.Compiler do
1527
1564
function: { :__impl__ , 1 }
1528
1565
} )
1529
1566
1567
+ state = collect_traces ( state )
1568
+
1530
1569
{ for , state } =
1531
1570
if is_atom ( for ) or ( is_list ( for ) and Enum . all? ( for , & is_atom / 1 ) ) do
1532
1571
{ for , state }
@@ -1602,6 +1641,8 @@ defmodule ElixirSense.Core.Compiler do
1602
1641
{ :"Elixir.__Unknown__" , env }
1603
1642
end
1604
1643
1644
+ state = collect_traces ( state )
1645
+
1605
1646
# elixir emits a special require directive with :defined key set in meta
1606
1647
# require expand does alias, updates context_modules and runtime_modules
1607
1648
# we do it here instead
@@ -2088,7 +2129,7 @@ defmodule ElixirSense.Core.Compiler do
2088
2129
# see https://github.com/elixir-lang/elixir/pull/12451#issuecomment-1461393633
2089
2130
defp alias_defmodule ( { :__aliases__ , meta , [ :"Elixir" , t ] = x } , module , env ) do
2090
2131
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 )
2092
2133
{ module , env }
2093
2134
end
2094
2135
end
@@ -2103,7 +2144,7 @@ defmodule ElixirSense.Core.Compiler do
2103
2144
defp alias_defmodule ( { :__aliases__ , meta , [ h | t ] } , _module , env ) when is_atom ( h ) do
2104
2145
module = Module . concat ( [ env . module , h ] )
2105
2146
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 )
2107
2148
2108
2149
case t do
2109
2150
[ ] -> { module , env }
@@ -2334,7 +2375,7 @@ defmodule ElixirSense.Core.Compiler do
2334
2375
# end
2335
2376
2336
2377
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 )
2338
2379
2339
2380
fun = fn
2340
2381
{ :__aliases__ , _ , ref } , state , env ->
@@ -2730,6 +2771,51 @@ defmodule ElixirSense.Core.Compiler do
2730
2771
@ internals [ { :module_info , 1 } , { :module_info , 0 } ]
2731
2772
end
2732
2773
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
+
2733
2819
defp import_info_callback ( module , state ) do
2734
2820
fn kind ->
2735
2821
if Map . has_key? ( state . mods_funs_to_positions , { module , nil , nil } ) do
0 commit comments