@@ -248,16 +248,7 @@ defmodule ElixirLS.LanguageServer.Dialyzer do
248
248
|> Enum . concat ( new_paths )
249
249
|> Enum . uniq ( )
250
250
251
- changed_contents =
252
- Task . async_stream (
253
- changed ,
254
- fn file ->
255
- content = File . read! ( file )
256
- { file , content , module_md5 ( file ) }
257
- end ,
258
- timeout: :infinity
259
- )
260
- |> Enum . into ( [ ] )
251
+ changed_contents = get_changed_files_contents ( changed )
261
252
262
253
{ changed , changed_contents }
263
254
end )
@@ -267,19 +258,52 @@ defmodule ElixirLS.LanguageServer.Dialyzer do
267
258
)
268
259
269
260
file_changes =
270
- Enum . reduce ( changed_contents , file_changes , fn { :ok , { file , content , hash } } , file_changes ->
271
- if is_nil ( hash ) or hash == md5 [ file ] do
272
- Map . delete ( file_changes , file )
273
- else
274
- Map . put ( file_changes , file , { content , hash } )
275
- end
261
+ Enum . reduce ( changed_contents , file_changes , fn
262
+ { :ok , { file , content , hash } } , file_changes ->
263
+ if is_nil ( hash ) or hash == md5 [ file ] do
264
+ Map . delete ( file_changes , file )
265
+ else
266
+ Map . put ( file_changes , file , { content , hash } )
267
+ end
268
+
269
+ { :exit , reason } , file_changes ->
270
+ # on elixir >= 1.14 reason will actually be {beam_path, reason} but
271
+ # it's not easy to pattern match on that
272
+ Logger . error (
273
+ "[ElixirLS Dialyzer] Unable to process one of the beams: #{ inspect ( reason ) } "
274
+ )
275
+
276
+ file_changes
276
277
end )
277
278
278
279
undialyzable = for { :ok , { file , _ , nil } } <- changed_contents , do: file
279
280
removed_files = Enum . uniq ( removed_files ++ removed ++ ( undialyzable -- changed ) )
280
281
{ removed_files , file_changes }
281
282
end
282
283
284
+ defp get_changed_files_contents ( changed ) do
285
+ with_trapping_exits ( fn ->
286
+ # TODO remove if when we require elixir 1.14
287
+ task_options =
288
+ if Version . match? ( System . version ( ) , ">= 1.14.0" ) do
289
+ [ zip_input_on_exit: true ]
290
+ else
291
+ [ ]
292
+ end
293
+ |> Keyword . put ( :timeout , :infinity )
294
+
295
+ Task . async_stream (
296
+ changed ,
297
+ fn file ->
298
+ content = File . read! ( file )
299
+ { file , content , module_md5 ( file ) }
300
+ end ,
301
+ task_options
302
+ )
303
+ |> Enum . into ( [ ] )
304
+ end )
305
+ end
306
+
283
307
defp extract_stale ( sources , timestamp ) do
284
308
for source <- sources ,
285
309
last_modified ( source ) > timestamp do
@@ -322,10 +346,12 @@ defmodule ElixirLS.LanguageServer.Dialyzer do
322
346
323
347
{ us , { active_plt , mod_deps , md5 , warnings } } =
324
348
:timer . tc ( fn ->
325
- Task . async_stream ( file_changes , fn { file , { content , _ } } ->
326
- write_temp_file ( root_path , file , content )
349
+ with_trapping_exits ( fn ->
350
+ Task . async_stream ( file_changes , fn { file , { content , _ } } ->
351
+ write_temp_file ( root_path , file , content )
352
+ end )
353
+ |> Stream . run ( )
327
354
end )
328
- |> Stream . run ( )
329
355
330
356
for file <- removed_files do
331
357
path = temp_file_path ( root_path , file )
@@ -338,7 +364,9 @@ defmodule ElixirLS.LanguageServer.Dialyzer do
338
364
:ok
339
365
340
366
{ :error , reason } ->
341
- Logger . warn ( "Unable to remove temporary file #{ path } : #{ inspect ( reason ) } " )
367
+ Logger . warn (
368
+ "[ElixirLS Dialyzer] Unable to remove temporary file #{ path } : #{ inspect ( reason ) } "
369
+ )
342
370
end
343
371
end
344
372
@@ -464,7 +492,11 @@ defmodule ElixirLS.LanguageServer.Dialyzer do
464
492
core_bin = :erlang . term_to_binary ( core )
465
493
:crypto . hash ( :md5 , core_bin )
466
494
467
- { :error , _ } ->
495
+ { :error , reason } ->
496
+ Logger . warn (
497
+ "[ElixirLS Dialyzer] get_core_from_beam failed for #{ file } : #{ inspect ( reason ) } "
498
+ )
499
+
468
500
nil
469
501
end
470
502
end
@@ -503,7 +535,10 @@ defmodule ElixirLS.LanguageServer.Dialyzer do
503
535
end
504
536
505
537
defp normalize_postion ( position ) do
506
- Logger . warn ( "dialyzer returned warning with invalid position #{ inspect ( position ) } " )
538
+ Logger . warn (
539
+ "[ElixirLS Dialyzer] dialyzer returned warning with invalid position #{ inspect ( position ) } "
540
+ )
541
+
507
542
0
508
543
end
509
544
@@ -556,4 +591,11 @@ defmodule ElixirLS.LanguageServer.Dialyzer do
556
591
Process . unlink ( pid )
557
592
Process . exit ( pid , :kill )
558
593
end
594
+
595
+ defp with_trapping_exits ( fun ) do
596
+ Process . flag ( :trap_exit , true )
597
+ fun . ( )
598
+ after
599
+ Process . flag ( :trap_exit , false )
600
+ end
559
601
end
0 commit comments