justincjohnson

justincjohnson

Elixir Internals: Return all references to a function on a specific line of a file

I am trying to add rename support to the wonderful Elixir Language Server project in https://github.com/JakeBecker/elixir-ls/issues/22. I’m at a very early stage in this work, making sure I understand the Language Server Protocol spec as well as the capabilities within Elixir itself, and creating a list of all the work I believe will be involved. That said I’ve been able to implement a proof of concept that, within certain constraints, does rename function definitions and references.

I’m facing a challenge currently and am posting here in the hopes that someone can save me some time and point me in the right direction in the Elixir code base.

When I need to rename a function, I first find the function definition and all references to the function throughout the project’s code base. The granularity of this information (in part coming from Mix.Tasks.Xref) currently only includes files and line numbers. I don’t know the function name start and end character numbers on the given line, how many times the function is referenced on that line, or exactly what names are used for those references, be they fully qualified modules and function names, partially qualified modules relying on aliases, module names that rely on aliases with renamed modules via the :as keyword, or just function names via import. This makes it challenging to know what portion of text on the given line needs to be renamed.

It seems to me that I need to tap into the Elixir runtime in order to know exactly what valid ways exist to reference a given function on a given line of a file. Without tapping into the runtime it seems that I would have to reimplement a bunch of logic that would have already been implemented in Elixir itself.

Does that make sense? So what I’m hoping for is a function I can call where I can pass in an MFA tuple, a file path and a line number and get back a list of references to that function on that line along with metadata about those references so I can determine the exact start and end characters that need to be renamed.

From my initial research I’m assuming this at least doesn’t exist today in a public function, but perhaps there are internals I can use, and if so perhaps this is worth a proposal for a new public function to help with Elixir tooling.

Thanks in advance for any tips you can provide.

Most Liked

msaraiva

msaraiva

Broadway Core Team

Hi @justincjohnson!

If you set up ElixirLS to use this branch of ElixirSense, you’ll have everything you need. You can use ElixirSense.references/3 to retrieve the list of all references including function calls from aliased/imported modules. You’ll also get the exact ranges you need to replace in each file. Here’s an example:

iex> ElixirSense.references(code, line, column) |> Enum.take(2)
  [
    %{
      uri: "test/support/modules_with_references.ex",
      range: %{
        start: %{line: 26, column: 60},
        end: %{line: 26, column: 64}
      }
    },
    %{
      uri: "test/support/modules_with_references.ex",
      range: %{
        start: %{line: 42, column: 16},
        end: %{line: 42, column: 20}
      }
    }
  ]
justincjohnson

justincjohnson

Wonderful! I’ll give it a try over the weekend and let you know if I have any feedback.

Where Next?

Popular in Questions Top

srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
Werner
Hi, I’m using Ubuntu 18.04 and after updating to OTP-24.0 yesterday i have this warning when I run “mix local.hex”: 14:57:30.512 [warn] ...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
Kagamiiiii
Student & New to elixir. Nice language. I want to convert a english character, e.g. “a”, which is stored in a variable, to it’s asci...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
Fl4m3Ph03n1x
Background Let’s assume I have a typical GenServer that receives messages as requests, does some operation in a DB and returns responses....
New
gonzofish
I’m currently trying to understand how to join three tables using Ecto. All the examples I’ve seen use 2, so maybe I’m just missing somet...
New
chewm
Hi guys, nice to meet you to the whole forum, I’m new here, I’m trying to configure visual studio code for elixir, right now the intellis...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
wernerlaude
In AR this is so simple @articles = current_user.articles How to do in Ecto? def index(conn, _params) do current_user = conn.assig...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3268 119930 1237
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

We're in Beta

About us Mission Statement