From f69c0839681ce2192685b5b2f1c01978aaad429f Mon Sep 17 00:00:00 2001 From: Dennis Palmer Date: Thu, 1 Jun 2023 17:45:30 +0200 Subject: [PATCH 1/4] adds unless_with_else code action --- lib/credo_language_server/check.ex | 21 +++++++++++++++++++ .../code_action/unless_with_else.ex | 16 ++++++++++++++ test/support/project/lib/unless_with_else.ex | 9 ++++++++ 3 files changed, 46 insertions(+) create mode 100644 lib/credo_language_server/code_action/unless_with_else.ex create mode 100644 test/support/project/lib/unless_with_else.ex diff --git a/lib/credo_language_server/check.ex b/lib/credo_language_server/check.ex index 5e9b0d5..5da100f 100644 --- a/lib/credo_language_server/check.ex +++ b/lib/credo_language_server/check.ex @@ -37,6 +37,27 @@ defmodule CredoLanguageServer.Check do ] end + def fetch(%{ + check: Credo.Check.Refactor.UnlessWithElse = check, + diagnostic: diagnostic, + uri: uri, + document: document + }) do + [ + CodeAction.DisableCheck.new( + uri: uri, + diagnostic: diagnostic, + text: document, + check: Macro.to_string(check) + ), + CodeAction.UnlessWithElse.new( + uri: uri, + diagnostic: diagnostic, + text: document + ) + ] + end + def fetch(%{ check: check, diagnostic: diagnostic, diff --git a/lib/credo_language_server/code_action/unless_with_else.ex b/lib/credo_language_server/code_action/unless_with_else.ex new file mode 100644 index 0000000..0c954c3 --- /dev/null +++ b/lib/credo_language_server/code_action/unless_with_else.ex @@ -0,0 +1,16 @@ +defmodule CredoLanguageServer.CodeAction.UnlessWithElse do + @moduledoc false + + alias GenLSP.Structures.{ + CodeAction, + WorkspaceEdit + } + + def new(opts) do + %CodeAction{ + title: "Refactor to use if", + diagnostics: [opts.diagnostic], + edit: %WorkspaceEdit{} + } + end +end diff --git a/test/support/project/lib/unless_with_else.ex b/test/support/project/lib/unless_with_else.ex new file mode 100644 index 0000000..f4cde6d --- /dev/null +++ b/test/support/project/lib/unless_with_else.ex @@ -0,0 +1,9 @@ +defmodule UnlessWithElse do + def foo() do + unless 1 == 2 do + :hello + else + :world + end + end +end From 9028fa482eba4de6db5874eb00f465fbb573f328 Mon Sep 17 00:00:00 2001 From: Dennis Palmer Date: Thu, 1 Jun 2023 17:54:42 +0200 Subject: [PATCH 2/4] removes test support file for now --- test/support/project/lib/unless_with_else.ex | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 test/support/project/lib/unless_with_else.ex diff --git a/test/support/project/lib/unless_with_else.ex b/test/support/project/lib/unless_with_else.ex deleted file mode 100644 index f4cde6d..0000000 --- a/test/support/project/lib/unless_with_else.ex +++ /dev/null @@ -1,9 +0,0 @@ -defmodule UnlessWithElse do - def foo() do - unless 1 == 2 do - :hello - else - :world - end - end -end From 2360e198c18c889f9f7bdf4bef7ecf51ccb8d254 Mon Sep 17 00:00:00 2001 From: Dennis Palmer Date: Fri, 2 Jun 2023 21:24:42 +0200 Subject: [PATCH 3/4] progress on ast transform --- .../code_action/unless_with_else.ex | 49 +++++++++++++++ .../code_action/unless_with_else_test.exs | 63 +++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 test/credo_language_server/code_action/unless_with_else_test.exs diff --git a/lib/credo_language_server/code_action/unless_with_else.ex b/lib/credo_language_server/code_action/unless_with_else.ex index 0c954c3..61bfbcb 100644 --- a/lib/credo_language_server/code_action/unless_with_else.ex +++ b/lib/credo_language_server/code_action/unless_with_else.ex @@ -13,4 +13,53 @@ defmodule CredoLanguageServer.CodeAction.UnlessWithElse do edit: %WorkspaceEdit{} } end + + def refactor(text) do + {:ok, ast, comments} = + Code.string_to_quoted_with_comments(text, + literal_encoder: &{:ok, {:__block__, &2, [&1]}}, + token_metadata: true, + unescape: false + ) + + IO.inspect(comments) + + ast + |> IO.inspect() + |> transform_ast() + |> Code.quoted_to_algebra(comments: comments) + # adjust_comment_lines(comments, 1, 5)) + |> Inspect.Algebra.format(:infinity) + |> IO.iodata_to_binary() + end + + defp transform_ast({:unless, line, [condition, [block1, block2]]}) do + {:if, line, + [condition, [change_block(block2, :do), change_block(block1, :else)]]} + end + + defp change_block({{:__block__, line, _}, rest}, new) do + {{:__block__, line, [new]}, rest} + end + + defp adjust_comment_lines(comments, block_line1, block_line2) do + comments + |> Enum.map(&adjust_comment_line(&1, block_line1, block_line2)) + end + + # defp adjust_comment_line(%{previous_eol_count: 0, line: line} = comment) do + # Map.put(comment, :line, line + 1) + # end + + defp adjust_comment_line(%{line: line} = comment, a, b) when line > b do + diff = b - a + Map.put(comment, :line, line - diff) + end + + defp adjust_comment_line(%{line: line} = comment, a, b) when line < b do + diff = b - a + Map.put(comment, :line, line + diff) + end + + defp adjust_comment_line(comment, _a, _b), do: comment end diff --git a/test/credo_language_server/code_action/unless_with_else_test.exs b/test/credo_language_server/code_action/unless_with_else_test.exs new file mode 100644 index 0000000..f40a448 --- /dev/null +++ b/test/credo_language_server/code_action/unless_with_else_test.exs @@ -0,0 +1,63 @@ +defmodule CredoLanguageServer.CodeAction.UnlessWithElseTest do + use ExUnit.Case, async: true + + alias CredoLanguageServer.CodeAction.UnlessWithElse + + describe "refactor" do + test "replaces unless with if and swaps code blocks" do + source = """ + unless allowed? do + raise "Not allowed!" + else + proceed_as_planned() + end + """ + + expected_result = + """ + if allowed? do + proceed_as_planned() + else + raise "Not allowed!" + end + """ + |> String.trim_trailing() + + result = UnlessWithElse.refactor(source) + + assert result == expected_result + end + + test "preserves comments" do + source = """ + unless allowed? do + # one + raise "Not allowed!" # two + # three + else + # four + proceed_as_planned() # five + # six + end + """ + + expected_result = + """ + if allowed? do + # four + proceed_as_planned() # five + # six + else + # one + raise "Not allowed!" # two + # three + end + """ + |> String.trim_trailing() + + result = UnlessWithElse.refactor(source) + + assert result == expected_result + end + end +end From 656b7f410d169e44cc3d8c21a791634670898390 Mon Sep 17 00:00:00 2001 From: Dennis Palmer Date: Fri, 2 Jun 2023 22:03:39 +0200 Subject: [PATCH 4/4] removes commented code --- lib/credo_language_server/code_action/unless_with_else.ex | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/credo_language_server/code_action/unless_with_else.ex b/lib/credo_language_server/code_action/unless_with_else.ex index 61bfbcb..c0b0a76 100644 --- a/lib/credo_language_server/code_action/unless_with_else.ex +++ b/lib/credo_language_server/code_action/unless_with_else.ex @@ -28,7 +28,6 @@ defmodule CredoLanguageServer.CodeAction.UnlessWithElse do |> IO.inspect() |> transform_ast() |> Code.quoted_to_algebra(comments: comments) - # adjust_comment_lines(comments, 1, 5)) |> Inspect.Algebra.format(:infinity) |> IO.iodata_to_binary() end @@ -47,10 +46,6 @@ defmodule CredoLanguageServer.CodeAction.UnlessWithElse do |> Enum.map(&adjust_comment_line(&1, block_line1, block_line2)) end - # defp adjust_comment_line(%{previous_eol_count: 0, line: line} = comment) do - # Map.put(comment, :line, line + 1) - # end - defp adjust_comment_line(%{line: line} = comment, a, b) when line > b do diff = b - a Map.put(comment, :line, line - diff)