From b063690f99703468299f9989fd47a39b20f95db8 Mon Sep 17 00:00:00 2001 From: Jesse Herrick Date: Wed, 6 May 2026 00:55:04 -0400 Subject: [PATCH] Don't lift require aliases due to our ordering rules --- lib/style/module_directives.ex | 9 ++-- .../module_directives/alias_lifting_test.exs | 41 +++++++++++++++++-- test/style/module_directives_test.exs | 2 +- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/lib/style/module_directives.ex b/lib/style/module_directives.ex index 5e4b4d2..4ee9f4f 100644 --- a/lib/style/module_directives.ex +++ b/lib/style/module_directives.ex @@ -433,11 +433,12 @@ defmodule Styler.Style.ModuleDirectives do defp apply_aliases(acc, inverted_env) when map_size(inverted_env) == 0, do: acc - defp apply_aliases(%{require: requires, nondirectives: nondirectives, alias_env: alias_env} = acc, inverted_env) do - # applying aliases to requires can change their ordering again - requires = requires |> apply_aliases(inverted_env, alias_env) |> sort() + defp apply_aliases(%{nondirectives: nondirectives, alias_env: alias_env} = acc, inverted_env) do + # Requires are intentionally left alone: they sort above aliases in strict layout, + # so shortening `require Foo.Bar` to `require Bar` would reference an alias declared + # below it (broken Elixir). nondirectives = apply_aliases(nondirectives, inverted_env, alias_env) - %{acc | require: requires, nondirectives: nondirectives} + %{acc | nondirectives: nondirectives} end # applies the aliases withi `to_as` across the given ast diff --git a/test/style/module_directives/alias_lifting_test.exs b/test/style/module_directives/alias_lifting_test.exs index e8c277c..ec8c358 100644 --- a/test/style/module_directives/alias_lifting_test.exs +++ b/test/style/module_directives/alias_lifting_test.exs @@ -176,7 +176,7 @@ defmodule Styler.Style.ModuleDirectives.AliasLiftingTest do import A.B.C - require C + require A.B.C alias A.B.C @@ -216,7 +216,9 @@ defmodule Styler.Style.ModuleDirectives.AliasLiftingTest do ) end - test "re-sorts requires after lifting" do + test "lifting does not rewrite require directives" do + # Requires sort above aliases, so a `require A.B.C` cannot be shortened to `require C` - at that point in the file, + # `C` isn't aliased yet. assert_style( """ defmodule A do @@ -224,16 +226,49 @@ defmodule Styler.Style.ModuleDirectives.AliasLiftingTest do require B A.B.C.foo() + A.B.C.foo() end """, """ defmodule A do + require A.B.C require B - require C alias A.B.C C.foo() + C.foo() + end + """ + ) + end + + test "lifting via a require sighting does not rewrite the require itself" do + # Regression test: one require + one nondirective use of the same FQDN used to + # produce a `require Baz` ordered above its `alias Foo.Bar.Baz` (broken Elixir). + assert_style( + """ + defmodule Foo do + @moduledoc false + + require Foo.Bar.Baz + + def go do + Foo.Bar.Baz.go() + end + end + """, + """ + defmodule Foo do + @moduledoc false + + require Foo.Bar.Baz + + alias Foo.Bar.Baz + + def go do + Baz.go() + end end """ ) diff --git a/test/style/module_directives_test.exs b/test/style/module_directives_test.exs index 7255abb..50c9b61 100644 --- a/test/style/module_directives_test.exs +++ b/test/style/module_directives_test.exs @@ -294,7 +294,7 @@ defmodule Styler.Style.ModuleDirectivesTest do alias A.A """, """ - require A + require A.A require A.C alias A.A