Skip to content

Commit 5f07a74

Browse files
sabiwaraaxelson
andauthored
Use line from missing terminator hint (#588)
* Use line from missing terminator hint * Fix formatter error * Remove mix files Co-authored-by: Jason Axelson <jason.axelson@gmail.com>
1 parent be70553 commit 5f07a74

File tree

7 files changed

+106
-7
lines changed

7 files changed

+106
-7
lines changed

apps/language_server/.formatter.exs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1+
impossible_to_format = ["test/fixtures/token_missing_error/lib/has_error.ex"]
2+
13
[
2-
inputs: [
3-
"*.exs",
4-
"{lib,test,config}/**/*.{ex,exs}"
5-
]
4+
inputs:
5+
Enum.flat_map(
6+
[
7+
"*.exs",
8+
"{lib,test,config}/**/*.{ex,exs}"
9+
],
10+
&Path.wildcard(&1, match_dot: true)
11+
) -- impossible_to_format
612
]

apps/language_server/lib/language_server/diagnostics.ex

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ defmodule ElixirLS.LanguageServer.Diagnostics do
99
diagnostic
1010
|> update_message(type, description, stacktrace)
1111
|> maybe_update_file(file)
12-
|> maybe_update_position(line, stacktrace)
12+
|> maybe_update_position(type, line, stacktrace)
1313
end
1414
end
1515

@@ -67,7 +67,21 @@ defmodule ElixirLS.LanguageServer.Diagnostics do
6767
end
6868
end
6969

70-
defp maybe_update_position(diagnostic, line, stacktrace) do
70+
defp maybe_update_position(diagnostic, "TokenMissingError", line, stacktrace) do
71+
case extract_line_from_missing_hint(diagnostic.message) do
72+
line when is_integer(line) ->
73+
%{diagnostic | position: line}
74+
75+
_ ->
76+
do_maybe_update_position(diagnostic, line, stacktrace)
77+
end
78+
end
79+
80+
defp maybe_update_position(diagnostic, _type, line, stacktrace) do
81+
do_maybe_update_position(diagnostic, line, stacktrace)
82+
end
83+
84+
defp do_maybe_update_position(diagnostic, line, stacktrace) do
7185
cond do
7286
line ->
7387
%{diagnostic | position: line}
@@ -142,6 +156,16 @@ defmodule ElixirLS.LanguageServer.Diagnostics do
142156
false
143157
end
144158

159+
defp extract_line_from_missing_hint(message) do
160+
case Regex.run(
161+
~r/HINT: it looks like the .+ on line (\d+) does not have a matching /,
162+
message
163+
) do
164+
[_, line] -> String.to_integer(line)
165+
_ -> nil
166+
end
167+
end
168+
145169
defp extract_line_from_stacktrace(file, stacktrace) do
146170
Enum.find_value(stacktrace, fn stack_item ->
147171
with [_, _, file_relative, line] <-

apps/language_server/test/diagnostics_test.exs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,26 @@ defmodule ElixirLS.LanguageServer.DiagnosticsTest do
133133
assert diagnostic.position == 13
134134
end
135135

136+
test "if position is nil and error is TokenMissingError, try to retrieve from the hint" do
137+
root_path = Path.join(__DIR__, "fixtures/token_missing_error")
138+
file = Path.join(root_path, "lib/has_error.ex")
139+
position = nil
140+
141+
message = """
142+
** (TokenMissingError) lib/has_error.ex:16:1: missing terminator: end (for "do" starting at line 1)
143+
144+
HINT: it looks like the "do" on line 6 does not have a matching "end"
145+
146+
(elixir 1.12.1) lib/kernel/parallel_compiler.ex:319: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/7
147+
"""
148+
149+
[diagnostic | _] =
150+
[build_diagnostic(message, file, position)]
151+
|> Diagnostics.normalize(root_path)
152+
153+
assert diagnostic.position == 6
154+
end
155+
136156
defp build_diagnostic(message, file, position) do
137157
%Mix.Task.Compiler.Diagnostic{
138158
compiler_name: "Elixir",

apps/language_server/test/fixtures/build_errors/lib/has_error.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
defmodule ElixirLS.LanguageServer.Fixtures.BuildErrors.HasWarning do
1+
defmodule ElixirLS.LanguageServer.Fixtures.BuildErrors.HasError do
22
def my_fn2 do
33
# Should cause build error
44
does_not_exist()
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
defmodule ElixirLS.LanguageServer.Fixtures.TokenMissingError.HasError do
2+
def my_fn1 do
3+
"no problem here"
4+
end
5+
6+
def my_fn2 do
7+
for i <- 1..100 do
8+
i + 1
9+
# missing terminator: end
10+
end
11+
12+
def my_fn3 do
13+
:ok_too
14+
end
15+
end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
defmodule ElixirLS.LanguageServer.Fixtures.TokenMissingError.Mixfile do
2+
use Mix.Project
3+
4+
def project do
5+
[app: :els_token_missing_error_test, version: "0.1.0"]
6+
end
7+
8+
def application do
9+
[]
10+
end
11+
end

apps/language_server/test/server_test.exs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,29 @@ defmodule ElixirLS.LanguageServer.ServerTest do
10251025
end)
10261026
end
10271027

1028+
@tag :fixture
1029+
test "reports token missing error diagnostics", %{server: server} do
1030+
in_fixture(__DIR__, "token_missing_error", fn ->
1031+
error_file = SourceFile.path_to_uri("lib/has_error.ex")
1032+
1033+
initialize(server)
1034+
1035+
assert_receive notification("textDocument/publishDiagnostics", %{
1036+
"uri" => ^error_file,
1037+
"diagnostics" => [
1038+
%{
1039+
"message" => "(TokenMissingError) missing terminator: end" <> _,
1040+
"range" => %{"end" => %{"line" => 5}, "start" => %{"line" => 5}},
1041+
"severity" => 1
1042+
}
1043+
]
1044+
}),
1045+
1000
1046+
1047+
wait_until_compiled(server)
1048+
end)
1049+
end
1050+
10281051
@tag :fixture
10291052
test "reports build diagnostics on external resources", %{server: server} do
10301053
in_fixture(__DIR__, "build_errors_on_external_resource", fn ->

0 commit comments

Comments
 (0)