elixir-lang / elixir

Elixir is a dynamic, functional language for building scalable and maintainable applications

Home Page:https://elixir-lang.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

False positive alias warning on main

josevalim opened this issue · comments

Elixir and Erlang/OTP versions

Elixir main, any OTP.

Operating system

macOS

Current behavior

This is emitting a unused alias warning, but the warning is used:

defmodule Explorer.DataFrameTest do
  alias Explorer.Series

  def mod do
    alias Explorer.Series
    Series.__info__(:module)
  end

  def foo do
    Series.__info__(:module)
  end
end

Expected behavior

No warnings. :)

@sabiwara I am not sure if there is a trivial fix for this one. Perhaps we could track the scope of the alias in such cases (for example, only consider it overridden if outside of a function?).

@josevalim seems to be working #13564.

I think there may be another problem with aliases outside of functions, e.g. in ExUnit tests, but please correct me if this is correct (it does not warn on 1.16):

ExUnit.start()

defmodule MyApp.Data do
  defmodule Item do
    defstruct id: nil
  end

  defmodule OtherItem do
    defstruct id: nil
  end

  def list_items do
    [%Item{id: 1}]
  end

  def list_other_items do
    [%OtherItem{id: 1}]
  end
end

defmodule MyApp.DataTest do
  use ExUnit.Case

  alias MyApp.Data
  alias MyApp.Data.Item

  describe "Item" do
    test "list_item/0 returns all Items" do
      assert [%Item{id: 1}] = Data.list_items()
    end
  end

  describe "OtherItem" do
    alias MyApp.Data
    alias MyApp.Data.OtherItem

    test "list_other_item/0 returns all OtherItems" do
      assert [%OtherItem{id: 1}] = Data.list_other_items()
    end
  end
end
elixir xyz.exs
    warning: unused alias Data
    │
 24 │   alias MyApp.Data
    │   ~
    │
    └─ xyz.exs:24:3

Running ExUnit with seed: 15636, max_cases: 20

..
Finished in 0.06 seconds (0.06s on load, 0.00s async, 0.00s sync)
2 tests, 0 failures

The list_item/0 uses the alias, but the compiler says it is unused. I thought the aliases are scoped by the describe blocks, but maybe this is wrong?

Another example that fails:

defmodule MyApp.Data do
  def foo do
    :ok
  end
end

defmodule MyAppWeb.FormComponent do
  alias MyApp.Data

  defmodule OtherComponent do
    @moduledoc false

    alias MyApp.Data

    def fun do
      Data.foo()
    end
  end

  def render do
    Data.foo()
    OtherComponent.fun()
  end
end

MyAppWeb.FormComponent.render()

Even a simpler case:

 defmodule Sample do
   alias Foo.Baz
   def foo, do: Baz

   alias Bar.Baz
   def bar, do: Baz
 end

Will revert, and see if we can detect shadowing a different way somehow.