Skip to content

Commit 0a3ba8f

Browse files
authored
Merge pull request #1220 from elixir-lsp/codex/add-declaration-handling-in-references-provider
Support includeDeclaration in references
2 parents 56139d7 + f6a2fc2 commit 0a3ba8f

File tree

2 files changed

+64
-13
lines changed

2 files changed

+64
-13
lines changed

apps/language_server/lib/language_server/providers/references.ex

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ defmodule ElixirLS.LanguageServer.Providers.References do
33
This module provides textDocument/references support. Currently its able to find references to
44
functions, macros, variables and module attributes
55
6-
Does not support configuring "includeDeclaration" and assumes it is always
7-
`true`
6+
Supports configuring "includeDeclaration" as defined by the LSP.
87
98
https://microsoft.github.io//language-server-protocol/specifications/specification-3-14/#textDocument_references
109
"""
@@ -13,29 +12,59 @@ defmodule ElixirLS.LanguageServer.Providers.References do
1312
alias ElixirLS.LanguageServer.Providers.References.Locator
1413
require Logger
1514

15+
alias ElixirLS.LanguageServer.Providers.{Definition, Declaration}
16+
1617
def references(
17-
%Parser.Context{source_file: source_file, metadata: metadata},
18+
parser_context = %Parser.Context{source_file: source_file, metadata: metadata},
1819
uri,
1920
line,
2021
character,
21-
_include_declaration,
22+
include_declaration,
2223
project_dir
2324
) do
2425
Build.with_build_lock(fn ->
2526
trace = ElixirLS.LanguageServer.Tracer.get_trace()
2627

27-
Locator.references(source_file.text, line, character, trace, metadata: metadata)
28-
|> Enum.map(fn elixir_sense_reference ->
29-
elixir_sense_reference
30-
|> build_reference(uri, source_file.text, project_dir)
31-
end)
32-
|> Enum.filter(&(not is_nil(&1)))
33-
# Returned references come from both compile tracer and current buffer
34-
# There may be duplicates
35-
|> Enum.uniq()
28+
base_refs =
29+
Locator.references(source_file.text, line, character, trace, metadata: metadata)
30+
|> Enum.map(fn elixir_sense_reference ->
31+
elixir_sense_reference
32+
|> build_reference(uri, source_file.text, project_dir)
33+
end)
34+
|> Enum.filter(&(not is_nil(&1)))
35+
36+
{definition_locations, declaration_locations} =
37+
definition_and_declaration_locations(uri, parser_context, line, character, project_dir)
38+
39+
references =
40+
if include_declaration do
41+
base_refs ++ definition_locations ++ declaration_locations
42+
else
43+
locations_to_exclude = MapSet.new(definition_locations ++ declaration_locations)
44+
Enum.reject(base_refs, fn ref -> ref in locations_to_exclude end)
45+
end
46+
|> Enum.uniq()
47+
48+
references
3649
end)
3750
end
3851

52+
defp definition_and_declaration_locations(uri, parser_context, line, character, project_dir) do
53+
definition_locations =
54+
case Definition.definition(uri, parser_context, line, character, project_dir) do
55+
{:ok, def_loc} -> List.wrap(def_loc || [])
56+
_ -> []
57+
end
58+
59+
declaration_locations =
60+
case Declaration.declaration(uri, parser_context, line, character, project_dir) do
61+
{:ok, decl_loc} -> List.wrap(decl_loc || [])
62+
_ -> []
63+
end
64+
65+
{definition_locations, declaration_locations}
66+
end
67+
3968
defp build_reference(ref, current_file_uri, current_file_text, project_dir) do
4069
case get_text(ref, current_file_text) do
4170
{:ok, text} ->

apps/language_server/test/providers/references_test.exs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,28 @@ defmodule ElixirLS.LanguageServer.Providers.ReferencesTest do
156156
]
157157
end
158158

159+
test "respects includeDeclaration flag for variables" do
160+
file_path = FixtureHelpers.get_path("references_referenced.ex")
161+
parser_context = ParserContextBuilder.from_path(file_path)
162+
uri = SourceFile.Path.to_uri(file_path)
163+
{line, char} = {4, 14}
164+
165+
ElixirLS.Test.TextLoc.annotate_assert(file_path, line, char, """
166+
IO.puts(referenced_variable + 1)
167+
^
168+
""")
169+
170+
{line, char} =
171+
SourceFile.lsp_position_to_elixir(parser_context.source_file.text, {line, char})
172+
173+
assert References.references(parser_context, uri, line, char, false, File.cwd!()) == [
174+
%GenLSP.Structures.Location{
175+
range: range(4, 12, 4, 31),
176+
uri: uri
177+
}
178+
]
179+
end
180+
159181
test "finds references to an attribute" do
160182
file_path = FixtureHelpers.get_path("references_referenced.ex")
161183
parser_context = ParserContextBuilder.from_path(file_path)

0 commit comments

Comments
 (0)