diff --git a/lib/mix/lib/mix/compilers/elixir.ex b/lib/mix/lib/mix/compilers/elixir.ex index 4616d1c3481..3d620b76591 100644 --- a/lib/mix/lib/mix/compilers/elixir.ex +++ b/lib/mix/lib/mix/compilers/elixir.ex @@ -324,6 +324,14 @@ defmodule Mix.Compilers.Elixir do end end + @doc """ + Retrieves all diagnostics from the given manifest. + """ + def diagnostics(manifest, dest) do + {_, all_sources, _, _, _, _, _, _} = parse_manifest(manifest, dest) + previous_warnings(all_sources, false) + end + defp compiler_info_from_force(manifest, all_paths, all_modules, dest) do # A config, path dependency or manifest has changed, let's just compile everything for {module, _} <- all_modules, diff --git a/lib/mix/lib/mix/compilers/erlang.ex b/lib/mix/lib/mix/compilers/erlang.ex index 70e0ad9a166..14e22940df5 100644 --- a/lib/mix/lib/mix/compilers/erlang.ex +++ b/lib/mix/lib/mix/compilers/erlang.ex @@ -207,6 +207,14 @@ defmodule Mix.Compilers.Erlang do manifest |> read_manifest() |> Enum.map(&elem(&1, 0)) end + @doc """ + Retrieves all diagnostics from the given manifest. + """ + def diagnostics(manifest) do + entries = read_manifest(manifest) + manifest_warnings(entries) + end + defp extract_entries(src_dir, src_ext, dest_dir, dest_ext, force) do files = Mix.Utils.extract_files(List.wrap(src_dir), List.wrap(src_ext)) diff --git a/lib/mix/lib/mix/task.compiler.ex b/lib/mix/lib/mix/task.compiler.ex index 5ad6b97dd8e..ebb0647fb5a 100644 --- a/lib/mix/lib/mix/task.compiler.ex +++ b/lib/mix/lib/mix/task.compiler.ex @@ -147,12 +147,17 @@ defmodule Mix.Task.Compiler do """ @callback manifests() :: [Path.t()] + @doc """ + Lists persisted diagnostics from the compiler. + """ + @callback diagnostics() :: [Diagnostic.t()] + @doc """ Removes build artifacts and manifests. """ @callback clean() :: any - @optional_callbacks clean: 0, manifests: 0 + @optional_callbacks clean: 0, manifests: 0, diagnostics: 0 @doc """ Adds a callback that runs after a given compiler. @@ -184,6 +189,63 @@ defmodule Mix.Task.Compiler do end end + @doc """ + Returns all compilers for the current project. + """ + def compilers(config \\ Mix.Project.config()) do + compilers = config[:compilers] || Mix.compilers() + + if :xref in compilers do + IO.warn( + "the :xref compiler is deprecated, please remove it from your mix.exs :compilers options" + ) + + List.delete(compilers, :xref) + else + compilers + end + |> maybe_prepend(:leex) + |> maybe_prepend(:yecc) + end + + defp maybe_prepend(compilers, compiler) do + if compiler in compilers do + compilers + else + [compiler | compilers] + end + end + + @doc """ + Lists manifest files for all compilers in the current project. + """ + def manifests(config \\ Mix.Project.config()) do + Enum.flat_map(compilers(config), fn compiler -> + module = Mix.Task.get("compile.#{compiler}") + + if module && function_exported?(module, :manifests, 0) do + module.manifests() + else + [] + end + end) + end + + @doc """ + Lists persisted diagnostics from all compilers in the current project. + """ + def diagnostics(config \\ Mix.Project.config()) do + Enum.flat_map(compilers(config), fn compiler -> + module = Mix.Task.get("compile.#{compiler}") + + if module && function_exported?(module, :diagnostics, 0) do + module.diagnostics() + else + [] + end + end) + end + # Normalize the compiler result to a diagnostic tuple. @doc false def normalize(result, name) do diff --git a/lib/mix/lib/mix/tasks/clean.ex b/lib/mix/lib/mix/tasks/clean.ex index 18c01dd1685..7c0964f97d7 100644 --- a/lib/mix/lib/mix/tasks/clean.ex +++ b/lib/mix/lib/mix/tasks/clean.ex @@ -39,7 +39,7 @@ defmodule Mix.Tasks.Clean do # First, we get the tasks. After that, we clean them. # This is to avoid a task cleaning a compiler module. tasks = - for compiler <- [:protocols] ++ Mix.Tasks.Compile.compilers(), + for compiler <- [:protocols] ++ Mix.Task.Compiler.compilers(), module = Mix.Task.get("compile.#{compiler}"), function_exported?(module, :clean, 0), do: module diff --git a/lib/mix/lib/mix/tasks/compile.all.ex b/lib/mix/lib/mix/tasks/compile.all.ex index c4b73477bda..115bc8a115f 100644 --- a/lib/mix/lib/mix/tasks/compile.all.ex +++ b/lib/mix/lib/mix/tasks/compile.all.ex @@ -67,7 +67,7 @@ defmodule Mix.Tasks.Compile.All do Mix.Project.build_structure(config) config - |> Mix.Tasks.Compile.compilers() + |> Mix.Task.Compiler.compilers() |> compile(args, :noop, []) end diff --git a/lib/mix/lib/mix/tasks/compile.elixir.ex b/lib/mix/lib/mix/tasks/compile.elixir.ex index 7ae75848361..0f4ce2fdb42 100644 --- a/lib/mix/lib/mix/tasks/compile.elixir.ex +++ b/lib/mix/lib/mix/tasks/compile.elixir.ex @@ -144,6 +144,12 @@ defmodule Mix.Tasks.Compile.Elixir do def manifests, do: [manifest()] defp manifest, do: Path.join(Mix.Project.manifest_path(), @manifest) + @impl true + def diagnostics do + dest = Mix.Project.compile_path() + Mix.Compilers.Elixir.diagnostics(manifest(), dest) + end + @impl true def clean do dest = Mix.Project.compile_path() diff --git a/lib/mix/lib/mix/tasks/compile.erlang.ex b/lib/mix/lib/mix/tasks/compile.erlang.ex index 40d21e598c4..09608ebba74 100644 --- a/lib/mix/lib/mix/tasks/compile.erlang.ex +++ b/lib/mix/lib/mix/tasks/compile.erlang.ex @@ -111,6 +111,11 @@ defmodule Mix.Tasks.Compile.Erlang do def manifests, do: [manifest()] defp manifest, do: Path.join(Mix.Project.manifest_path(), @manifest) + @impl true + def diagnostics do + Mix.Compilers.Erlang.diagnostics(manifest()) + end + @impl true def clean do Mix.Compilers.Erlang.clean(manifest()) diff --git a/lib/mix/lib/mix/tasks/compile.ex b/lib/mix/lib/mix/tasks/compile.ex index 19378f2bffd..b007653b4d1 100644 --- a/lib/mix/lib/mix/tasks/compile.ex +++ b/lib/mix/lib/mix/tasks/compile.ex @@ -1,5 +1,5 @@ defmodule Mix.Tasks.Compile do - use Mix.Task.Compiler + use Mix.Task @shortdoc "Compiles source files" @@ -42,6 +42,7 @@ defmodule Mix.Tasks.Compile do the paths set by the code loader from the `ERL_LIBS` environment as well as explicitly listed by providing `-pa` and `-pz` options to Erlang. + ## Compilers To see documentation for each specific compiler, you must @@ -79,32 +80,8 @@ defmodule Mix.Tasks.Compile do """ - @doc """ - Returns all compilers for the current project. - """ - def compilers(config \\ Mix.Project.config()) do - compilers = config[:compilers] || Mix.compilers() - - if :xref in compilers do - IO.warn( - "the :xref compiler is deprecated, please remove it from your mix.exs :compilers options" - ) - - List.delete(compilers, :xref) - else - compilers - end - |> maybe_prepend(:leex) - |> maybe_prepend(:yecc) - end - - defp maybe_prepend(compilers, compiler) do - if compiler in compilers do - compilers - else - [compiler | compilers] - end - end + @deprecated "Use Mix.Task.Compiler.compilers/1 instead" + defdelegate compilers(config \\ Mix.Project.config()), to: Mix.Task.Compiler @impl true def run(["--list"]) do @@ -228,18 +205,8 @@ defmodule Mix.Tasks.Compile do end end - @impl true - def manifests do - Enum.flat_map(compilers(), fn compiler -> - module = Mix.Task.get("compile.#{compiler}") - - if module && function_exported?(module, :manifests, 0) do - module.manifests() - else - [] - end - end) - end + @deprecated "Use Mix.Task.Compiler.manifests/0 instead" + defdelegate manifests, to: Mix.Task.Compiler ## Consolidation handling diff --git a/lib/mix/test/mix/tasks/compile.elixir_test.exs b/lib/mix/test/mix/tasks/compile.elixir_test.exs index bc8ee4f2a5a..32f2afa5aa1 100644 --- a/lib/mix/test/mix/tasks/compile.elixir_test.exs +++ b/lib/mix/test/mix/tasks/compile.elixir_test.exs @@ -1469,6 +1469,9 @@ defmodule Mix.Tasks.Compile.ElixirTest do compiler_name: "Elixir", message: ^message } = diagnostic + + assert [^diagnostic] = Mix.Tasks.Compile.Elixir.diagnostics() + assert [^diagnostic] = Mix.Task.Compiler.diagnostics() end) end) end diff --git a/lib/mix/test/mix/tasks/compile.erlang_test.exs b/lib/mix/test/mix/tasks/compile.erlang_test.exs index a3440ea6384..c0086f914f1 100644 --- a/lib/mix/test/mix/tasks/compile.erlang_test.exs +++ b/lib/mix/test/mix/tasks/compile.erlang_test.exs @@ -132,6 +132,9 @@ defmodule Mix.Tasks.Compile.ErlangTest do assert {:noop, [^diagnostic]} = Mix.Tasks.Compile.Erlang.run(["--verbose"]) refute_received {:mix_shell, :info, ["Compiled src/has_warning.erl"]} + assert [^diagnostic] = Mix.Tasks.Compile.Erlang.diagnostics() + assert [^diagnostic] = Mix.Task.Compiler.diagnostics() + # Should not return warning after changing file File.write!(file, """ -module(has_warning). diff --git a/lib/mix/test/mix/tasks/compile_test.exs b/lib/mix/test/mix/tasks/compile_test.exs index 4696196227e..132c5231f2f 100644 --- a/lib/mix/test/mix/tasks/compile_test.exs +++ b/lib/mix/test/mix/tasks/compile_test.exs @@ -42,7 +42,7 @@ defmodule Mix.Tasks.CompileTest do @tag project: [compilers: [:elixir, :app, :custom]] test "compiles does not require all compilers available on manifest" do - assert Mix.Tasks.Compile.manifests() |> Enum.map(&Path.basename/1) == + assert Mix.Task.Compiler.manifests() |> Enum.map(&Path.basename/1) == ["compile.yecc", "compile.leex", "compile.elixir"] end