From 929fecff68dca6d5d72281146c59cdfa323f312a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20=C5=9Awi=C4=85tkowski?= Date: Sun, 23 Nov 2025 12:23:09 +0100 Subject: [PATCH] feat(engine): support go to definition when function is called via __MODULE__ This wasn't working, as __MODULE__ is recognized as :var, not as :module in AST. What was needed is to add a special handling of it in `expand_alias` function. Recognizing __MODULE__ as :var, while semantically incorrect, does not seem to be a problem in scope of definition finding. It's not strictly a module either, so to be super-correct, we would need to add a special handling just for it. --- .../lib/engine/code_intelligence/entity.ex | 4 ++ .../code_intelligence/definition_test.exs | 44 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/apps/engine/lib/engine/code_intelligence/entity.ex b/apps/engine/lib/engine/code_intelligence/entity.ex index 5ca52c8f..515836b9 100644 --- a/apps/engine/lib/engine/code_intelligence/entity.ex +++ b/apps/engine/lib/engine/code_intelligence/entity.ex @@ -346,6 +346,10 @@ defmodule Engine.CodeIntelligence.Entity do String.upcase(first_char) == first_char end + defp expand_alias({:var, ~c"__MODULE__"}, analysis, %Position{} = position) do + Engine.Analyzer.current_module(analysis, position) + end + defp expand_alias({:alias, {:local_or_var, prefix}, charlist}, analysis, %Position{} = position) do expand_alias(prefix ++ [?.] ++ charlist, analysis, position) end diff --git a/apps/expert/test/engine/code_intelligence/definition_test.exs b/apps/expert/test/engine/code_intelligence/definition_test.exs index 3b44b964..c42a30dd 100644 --- a/apps/expert/test/engine/code_intelligence/definition_test.exs +++ b/apps/expert/test/engine/code_intelligence/definition_test.exs @@ -336,6 +336,50 @@ defmodule Expert.Engine.CodeIntelligence.DefinitionTest do assert referenced_uri == subject_uri end + test "find the function definition when referenced via __MODULE__", %{ + project: project, + subject_uri: subject_uri + } do + subject_module = ~q[ + defmodule UsesOwnFunction do + def greet do + end + + def uses_greet do + __MODULE__.gree|t() + end + end + ] + + {:ok, referenced_uri, definition_line} = definition(project, subject_module, subject_uri) + + assert definition_line == ~S[ def «greet» do] + assert referenced_uri =~ "navigations/lib/my_module.ex" + end + + test "find the function definition when alias __MODULE__ is used", %{ + project: project, + subject_uri: subject_uri + } do + subject_module = ~q[ + defmodule MyApp.UsesOwnFunction do + alias __MODULE__ + + def greet do + end + + def uses_greet do + UsesOwnFunction.gree|t() + end + end + ] + + {:ok, referenced_uri, definition_line} = definition(project, subject_module, subject_uri) + + assert definition_line == ~S[ def «greet» do] + assert referenced_uri =~ "navigations/lib/my_module.ex" + end + test "find the attribute", %{project: project, subject_uri: subject_uri} do subject_module = ~q[ defmodule UsesAttribute do