From f6ef52827040a6dc1cd9f67c2556972113d19671 Mon Sep 17 00:00:00 2001 From: krishnadas Date: Mon, 15 Dec 2025 11:27:06 +0530 Subject: [PATCH 1/4] Mix: warn when project app name matches a dependency --- lib/mix/lib/mix/project.ex | 23 ++++++++++++++++++++++- lib/mix/test/mix/project_test.exs | 27 +++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/lib/mix/lib/mix/project.ex b/lib/mix/lib/mix/project.ex index 93ff56bed96..c3d314f8ba3 100644 --- a/lib/mix/lib/mix/project.ex +++ b/lib/mix/lib/mix/project.ex @@ -259,7 +259,10 @@ defmodule Mix.Project do true -> "nofile" end - case Mix.ProjectStack.push(module, push_config(module, app), file) do + config = push_config(module, app) + warn_on_duplicate_app_name(config) + + case Mix.ProjectStack.push(module, config, file) do :ok -> :ok @@ -1070,6 +1073,24 @@ defmodule Mix.Project do end end + defp warn_on_duplicate_app_name(config) do + app = config[:app] + deps = Keyword.get(config, :deps, []) + + dep_apps = + Enum.map(deps, fn + {dep_app, _opts} -> dep_app + dep_app -> dep_app + end) + + if app in dep_apps do + # Use Mix.shell().error to print to stderr + Mix.shell().error( + "warning: the application name #{inspect(app)} is the same as one of its dependencies" + ) + end + end + defp default_config do [ aliases: [], diff --git a/lib/mix/test/mix/project_test.exs b/lib/mix/test/mix/project_test.exs index 25cf51874ab..fa13066bc9b 100644 --- a/lib/mix/test/mix/project_test.exs +++ b/lib/mix/test/mix/project_test.exs @@ -160,6 +160,33 @@ defmodule Mix.ProjectTest do end) end + test "warns when project app name matches a dependency" do + in_tmp("duplicate_app_name", fn -> + File.write!("mix.exs", """ + defmodule DuplicateAppName.MixProject do + use Mix.Project + + def project do + [ + app: :foo, + version: "0.1.0", + deps: [{:foo, "~> 0.1.0"}] + ] + end + end + """) + + Mix.Project.in_project(:foo, ".", fn _ -> + :ok + end) + + assert_receive {:mix_shell, :error, + [ + "warning: the application name :foo is the same as one of its dependencies" + ]} + end) + end + test "in_project prints nice error message if fails to load file", context do in_tmp(context.test, fn -> File.write("mix.exs", """ From 5aef655f43b980868f96016003bec2e749d91184 Mon Sep 17 00:00:00 2001 From: krishnadas Date: Tue, 16 Dec 2025 01:43:13 +0530 Subject: [PATCH 2/4] Fix warning when project app name matches a dependency This ensures Mix emits a warning if a project's app name conflicts with one of its dependencies. --- lib/mix/lib/mix/dep/loader.ex | 18 +++++++++++++++- lib/mix/lib/mix/project.ex | 23 +------------------- lib/mix/test/mix/project_test.exs | 35 ++++++++++++------------------- 3 files changed, 31 insertions(+), 45 deletions(-) diff --git a/lib/mix/lib/mix/dep/loader.ex b/lib/mix/lib/mix/dep/loader.ex index 290579a23ea..7cd69166ed1 100644 --- a/lib/mix/lib/mix/dep/loader.ex +++ b/lib/mix/lib/mix/dep/loader.ex @@ -19,7 +19,23 @@ defmodule Mix.Dep.Loader do current environment, behavior can be overridden via options. """ def children(locked?) do - mix_children(Mix.Project.config(), locked?, []) ++ Mix.Dep.Umbrella.unloaded() + deps = mix_children(Mix.Project.config(), locked?, []) ++ Mix.Dep.Umbrella.unloaded() + # warn if project app matches a dep + warn_on_duplicate_app_name(Mix.Project.config()[:app], deps) + + deps + end + + def warn_on_duplicate_app_name(nil, _deps), do: :ok + + def warn_on_duplicate_app_name(app, deps) do + dep_apps = Enum.map(deps, & &1.app) + + if app in dep_apps do + Mix.shell().error( + "warning: the application name #{inspect(app)} is the same as one of its dependencies" + ) + end end @doc """ diff --git a/lib/mix/lib/mix/project.ex b/lib/mix/lib/mix/project.ex index c3d314f8ba3..93ff56bed96 100644 --- a/lib/mix/lib/mix/project.ex +++ b/lib/mix/lib/mix/project.ex @@ -259,10 +259,7 @@ defmodule Mix.Project do true -> "nofile" end - config = push_config(module, app) - warn_on_duplicate_app_name(config) - - case Mix.ProjectStack.push(module, config, file) do + case Mix.ProjectStack.push(module, push_config(module, app), file) do :ok -> :ok @@ -1073,24 +1070,6 @@ defmodule Mix.Project do end end - defp warn_on_duplicate_app_name(config) do - app = config[:app] - deps = Keyword.get(config, :deps, []) - - dep_apps = - Enum.map(deps, fn - {dep_app, _opts} -> dep_app - dep_app -> dep_app - end) - - if app in dep_apps do - # Use Mix.shell().error to print to stderr - Mix.shell().error( - "warning: the application name #{inspect(app)} is the same as one of its dependencies" - ) - end - end - defp default_config do [ aliases: [], diff --git a/lib/mix/test/mix/project_test.exs b/lib/mix/test/mix/project_test.exs index fa13066bc9b..4abcec083b6 100644 --- a/lib/mix/test/mix/project_test.exs +++ b/lib/mix/test/mix/project_test.exs @@ -161,30 +161,21 @@ defmodule Mix.ProjectTest do end test "warns when project app name matches a dependency" do - in_tmp("duplicate_app_name", fn -> - File.write!("mix.exs", """ - defmodule DuplicateAppName.MixProject do - use Mix.Project - - def project do - [ - app: :foo, - version: "0.1.0", - deps: [{:foo, "~> 0.1.0"}] - ] - end - end - """) + Mix.shell(Mix.Shell.Process) - Mix.Project.in_project(:foo, ".", fn _ -> - :ok - end) + app = :clash_app - assert_receive {:mix_shell, :error, - [ - "warning: the application name :foo is the same as one of its dependencies" - ]} - end) + deps = [ + %Mix.Dep{app: :clash_app}, + %Mix.Dep{app: :other_dep} + ] + + Mix.Dep.Loader.warn_on_duplicate_app_name(app, deps) + + assert_received {:mix_shell, :error, + [ + "warning: the application name :clash_app is the same as one of its dependencies" + ]} end test "in_project prints nice error message if fails to load file", context do From fedcac91f22646c03394774bcb06be325fe08727 Mon Sep 17 00:00:00 2001 From: krishnadas Date: Tue, 16 Dec 2025 11:11:27 +0530 Subject: [PATCH 3/4] mix: warn when project app name matches a dependency --- lib/mix/lib/mix/dep/loader.ex | 28 ++++++++++------------------ lib/mix/test/mix/project_test.exs | 29 +++++++++++++++++++---------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/lib/mix/lib/mix/dep/loader.ex b/lib/mix/lib/mix/dep/loader.ex index 7cd69166ed1..057195090ca 100644 --- a/lib/mix/lib/mix/dep/loader.ex +++ b/lib/mix/lib/mix/dep/loader.ex @@ -19,23 +19,7 @@ defmodule Mix.Dep.Loader do current environment, behavior can be overridden via options. """ def children(locked?) do - deps = mix_children(Mix.Project.config(), locked?, []) ++ Mix.Dep.Umbrella.unloaded() - # warn if project app matches a dep - warn_on_duplicate_app_name(Mix.Project.config()[:app], deps) - - deps - end - - def warn_on_duplicate_app_name(nil, _deps), do: :ok - - def warn_on_duplicate_app_name(app, deps) do - dep_apps = Enum.map(deps, & &1.app) - - if app in dep_apps do - Mix.shell().error( - "warning: the application name #{inspect(app)} is the same as one of its dependencies" - ) - end + mix_children(Mix.Project.config(), locked?, []) ++ Mix.Dep.Umbrella.unloaded() end @doc """ @@ -205,7 +189,7 @@ defmodule Mix.Dep.Loader do {scm, opts} = get_scm(app, opts) {scm, opts} = - if is_nil(scm) and Mix.Hex.ensure_installed?(locked?) do + if is_nil(scm) and locked? and Mix.Hex.ensure_installed?(locked?) do _ = Mix.Hex.start() get_scm(app, opts) else @@ -218,6 +202,14 @@ defmodule Mix.Dep.Loader do ) end + project_app = Mix.Project.config()[:app] + + if project_app && project_app == app do + Mix.shell().error( + "warning: the application name #{inspect(app)} is the same as one of its dependencies" + ) + end + %Mix.Dep{ scm: scm, app: app, diff --git a/lib/mix/test/mix/project_test.exs b/lib/mix/test/mix/project_test.exs index 4abcec083b6..75758fdedf2 100644 --- a/lib/mix/test/mix/project_test.exs +++ b/lib/mix/test/mix/project_test.exs @@ -163,19 +163,28 @@ defmodule Mix.ProjectTest do test "warns when project app name matches a dependency" do Mix.shell(Mix.Shell.Process) - app = :clash_app - - deps = [ - %Mix.Dep{app: :clash_app}, - %Mix.Dep{app: :other_dep} - ] + in_tmp("duplicate_app_name", fn -> + File.write!("mix.exs", """ + defmodule DuplicateAppName.MixProject do + use Mix.Project + + def project do + [ + app: :foo, + version: "0.1.0", + deps: [{:foo, "~> 0.1.0"}] + ] + end + end + """) - Mix.Dep.Loader.warn_on_duplicate_app_name(app, deps) + Mix.Project.in_project(:foo, ".", fn _ -> + Mix.Dep.Loader.children(true) + end) + end) assert_received {:mix_shell, :error, - [ - "warning: the application name :clash_app is the same as one of its dependencies" - ]} + ["warning: the application name :foo is the same as one of its dependencies"]} end test "in_project prints nice error message if fails to load file", context do From 666fa26afe252847fb79cc7902135568b072aac2 Mon Sep 17 00:00:00 2001 From: krishnadas Date: Tue, 16 Dec 2025 14:23:54 +0530 Subject: [PATCH 4/4] mix: warn when project app name matches a dependency --- lib/mix/lib/mix/dep/loader.ex | 2 +- lib/mix/test/mix/project_test.exs | 27 --------------------------- lib/mix/test/mix/tasks/deps_test.exs | 25 +++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/lib/mix/lib/mix/dep/loader.ex b/lib/mix/lib/mix/dep/loader.ex index 057195090ca..b2620b92730 100644 --- a/lib/mix/lib/mix/dep/loader.ex +++ b/lib/mix/lib/mix/dep/loader.ex @@ -189,7 +189,7 @@ defmodule Mix.Dep.Loader do {scm, opts} = get_scm(app, opts) {scm, opts} = - if is_nil(scm) and locked? and Mix.Hex.ensure_installed?(locked?) do + if is_nil(scm) and Mix.Hex.ensure_installed?(locked?) do _ = Mix.Hex.start() get_scm(app, opts) else diff --git a/lib/mix/test/mix/project_test.exs b/lib/mix/test/mix/project_test.exs index 75758fdedf2..25cf51874ab 100644 --- a/lib/mix/test/mix/project_test.exs +++ b/lib/mix/test/mix/project_test.exs @@ -160,33 +160,6 @@ defmodule Mix.ProjectTest do end) end - test "warns when project app name matches a dependency" do - Mix.shell(Mix.Shell.Process) - - in_tmp("duplicate_app_name", fn -> - File.write!("mix.exs", """ - defmodule DuplicateAppName.MixProject do - use Mix.Project - - def project do - [ - app: :foo, - version: "0.1.0", - deps: [{:foo, "~> 0.1.0"}] - ] - end - end - """) - - Mix.Project.in_project(:foo, ".", fn _ -> - Mix.Dep.Loader.children(true) - end) - end) - - assert_received {:mix_shell, :error, - ["warning: the application name :foo is the same as one of its dependencies"]} - end - test "in_project prints nice error message if fails to load file", context do in_tmp(context.test, fn -> File.write("mix.exs", """ diff --git a/lib/mix/test/mix/tasks/deps_test.exs b/lib/mix/test/mix/tasks/deps_test.exs index 0aecfbc8219..dd85ee33603 100644 --- a/lib/mix/test/mix/tasks/deps_test.exs +++ b/lib/mix/test/mix/tasks/deps_test.exs @@ -922,6 +922,31 @@ defmodule Mix.Tasks.DepsTest do end) end + defmodule AppNameClashesWithDep do + def project do + [ + app: :ok, + version: "0.1.0", + deps: [ + {:ok, "0.1.0", path: "deps/ok"} + ] + ] + end + end + + test "warns when project app name matches a dependency" do + in_fixture("deps_status", fn -> + Mix.Project.push(AppNameClashesWithDep) + + Mix.Tasks.Deps.Get.run([]) + + msg = + "warning: the application name :ok is the same as one of its dependencies" + + assert_received {:mix_shell, :error, [^msg]} + end) + end + ## deps.clean defmodule CleanDepsApp do