diff --git a/apps/language_server/lib/language_server/diagnostics.ex b/apps/language_server/lib/language_server/diagnostics.ex index becc752f5..908f96155 100644 --- a/apps/language_server/lib/language_server/diagnostics.ex +++ b/apps/language_server/lib/language_server/diagnostics.ex @@ -57,6 +57,22 @@ defmodule ElixirLS.LanguageServer.Diagnostics do %__MODULE__{normalized | message: message, file: file, position: position} end + # Third-party Mix compilers sometimes return plain strings (or other terms) + # instead of `Mix.Task.Compiler.Diagnostic` structs. Attach them to the mixfile. + def from_mix_task_compiler_diagnostic(message, mixfile, _root_path) when is_binary(message) do + %__MODULE__{ + compiler_name: "Mix", + file: mixfile, + position: 0, + message: message, + severity: :error + } + end + + def from_mix_task_compiler_diagnostic(other, mixfile, root_path) do + from_mix_task_compiler_diagnostic(inspect(other), mixfile, root_path) + end + def from_kernel_parallel_compiler_tuple({file, position, message}, severity, fallback_file) do %__MODULE__{ compiler_name: "Elixir", diff --git a/apps/language_server/test/diagnostics_test.exs b/apps/language_server/test/diagnostics_test.exs index ca4e10fa6..77d9cedf4 100644 --- a/apps/language_server/test/diagnostics_test.exs +++ b/apps/language_server/test/diagnostics_test.exs @@ -36,6 +36,42 @@ defmodule ElixirLS.LanguageServer.DiagnosticsTest do } end + test "binary diagnostic from a third-party Mix compiler is attached to mix.exs" do + normalized = + Diagnostics.from_mix_task_compiler_diagnostic( + "Make failed with exit code 2", + "/somedir/mix.exs", + "/somedir" + ) + + assert normalized == %Diagnostics{ + file: "/somedir/mix.exs", + severity: :error, + message: "Make failed with exit code 2", + position: 0, + compiler_name: "Mix", + span: nil, + details: nil, + stacktrace: [] + } + end + + test "non-binary, non-struct diagnostic from a Mix compiler is inspected and attached to mix.exs" do + normalized = + Diagnostics.from_mix_task_compiler_diagnostic( + {:some, :term}, + "/somedir/mix.exs", + "/somedir" + ) + + assert %Diagnostics{ + file: "/somedir/mix.exs", + severity: :error, + message: "{:some, :term}", + position: 0 + } = normalized + end + test "Mix.Task.Compiler.Diagnostic without position - get from stacktrace" do diagnostic = %Mix.Task.Compiler.Diagnostic{ file: Path.join(File.cwd!(), "temp.ex"),