Skip to content

Commit acd96bb

Browse files
committed
Add basics for unused string operation autocorrect
This adds the first bits of an implementation for how we might want to autocorrect an unused String operation. Unfortunately because there's nothing in the AST that represents **nothing**, anything we replace that unused String operation with in the AST will be compiled into something - even if just the literal atom `nil`. That would probably be better than unused String operations since those would just be noops in the runtime, but they would be potentially confusing in the code. If we want to actually do this there's probably a _lot_ more that would need to be done for this check, but what we have offers a glimpse into how this kind of check could be autocorrected as a proof of concept.
1 parent ab77dcd commit acd96bb

2 files changed

Lines changed: 95 additions & 0 deletions

File tree

lib/credo/check/warning/unused_string_operation.ex

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ defmodule Credo.Check.Warning.UnusedStringOperation do
2828
"""
2929
]
3030

31+
alias Credo.Check.Warning.UnusedFunctionReturnHelper
3132
alias Credo.Check.Warning.UnusedOperation
3233

3334
@checked_module :String
@@ -44,4 +45,47 @@ defmodule Credo.Check.Warning.UnusedStringOperation do
4445
&format_issue/2
4546
)
4647
end
48+
49+
def autocorrect(file, _issue) do
50+
{_, quoted} = Credo.Code.ast(file)
51+
source_file = SourceFile.parse(file, "nofile")
52+
53+
unused_calls =
54+
UnusedFunctionReturnHelper.find_unused_calls(
55+
source_file,
56+
[],
57+
[@checked_module],
58+
@funs_with_return_value
59+
)
60+
61+
modified =
62+
quoted
63+
|> Macro.prewalk(&do_autocorrect(&1, unused_calls))
64+
|> Macro.to_string()
65+
|> :"Elixir.Code".format_string!()
66+
|> to_string()
67+
68+
"#{modified}\n"
69+
end
70+
71+
defp do_autocorrect({:__block__, meta, [{:|>, _pipe_meta, pipe_args} | tail] = args}, unused_calls) do
72+
args =
73+
if List.last(pipe_args) in unused_calls do
74+
[hd(pipe_args) | tail]
75+
else
76+
args
77+
end
78+
79+
{:__block__, meta, args}
80+
end
81+
82+
defp do_autocorrect({:__block__, meta, args}, unused_calls) do
83+
{:__block__, meta, Enum.reject(args, & &1 in unused_calls)}
84+
end
85+
86+
defp do_autocorrect({:do, node}, unused_calls) do
87+
{:do, do_autocorrect(node, unused_calls)}
88+
end
89+
90+
defp do_autocorrect(ast, _), do: ast
4791
end

test/credo/check/warning/unused_string_operation_test.exs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,4 +720,55 @@ defmodule Credo.Check.Warning.UnusedStringOperationTest do
720720
assert "String.to_float" == issue.trigger
721721
end)
722722
end
723+
724+
describe "autocorrect/2" do
725+
test "removes the unused String function" do
726+
starting = """
727+
defmodule CredoSampleModule do
728+
def some_function(parameter1, parameter2) do
729+
x = parameter1 + parameter2
730+
731+
String.split(parameter1)
732+
733+
parameter1
734+
end
735+
end
736+
"""
737+
738+
expected = """
739+
defmodule CredoSampleModule do
740+
def some_function(parameter1, parameter2) do
741+
x = parameter1 + parameter2
742+
parameter1
743+
end
744+
end
745+
"""
746+
747+
assert @described_check.autocorrect(starting, nil) == expected
748+
end
749+
750+
test "it should report a violation when end of pipe" do
751+
starting = """
752+
defmodule CredoSampleModule do
753+
def some_function(parameter1, parameter2) do
754+
parameter1 + parameter2
755+
|> String.split(parameter1)
756+
757+
parameter1
758+
end
759+
end
760+
"""
761+
762+
expected = """
763+
defmodule CredoSampleModule do
764+
def some_function(parameter1, parameter2) do
765+
parameter1 + parameter2
766+
parameter1
767+
end
768+
end
769+
"""
770+
771+
assert @described_check.autocorrect(starting, nil) == expected
772+
end
773+
end
723774
end

0 commit comments

Comments
 (0)