Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions lib/elixir/src/elixir_bitstring.erl
Original file line number Diff line number Diff line change
Expand Up @@ -403,10 +403,13 @@ format_error({undefined_bittype, Expr}) ->
io_lib:format("unknown bitstring specifier: ~ts", ['Elixir.Macro':to_string(Expr)]);
format_error({unknown_bittype, Name}) ->
io_lib:format("bitstring specifier \"~ts\" does not exist and is being expanded to \"~ts()\","
" please use parentheses to remove the ambiguity", [Name, Name]);
" please use parentheses to remove the ambiguity.\n"
"You may run \"mix format --migrate\" to fix this warning automatically.", [Name, Name]);
format_error({parens_bittype, Name}) ->
io_lib:format("extra parentheses on a bitstring specifier \"~ts()\" have been deprecated. "
"Please remove the parentheses: \"~ts\"",
"Please remove the parentheses: \"~ts\".\n"
"You may run \"mix format --migrate\" to fix this warning automatically."
,
[Name, Name]);
format_error({bittype_mismatch, Val1, Val2, Where}) ->
io_lib:format("conflicting ~ts specification for bit field: \"~p\" and \"~p\"", [Where, Val1, Val2]);
Expand Down
5 changes: 4 additions & 1 deletion lib/elixir/src/elixir_tokenizer.erl
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,10 @@ tokenize([$" | T], Line, Column, Scope, Tokens) ->

%% TODO: Remove me in Elixir v2.0
tokenize([$' | T], Line, Column, Scope, Tokens) ->
NewScope = prepend_warning(Line, Column, "single-quoted strings represent charlists. Use ~c\"\" if you indeed want a charlist or use \"\" instead", Scope),
Message = "single-quoted strings represent charlists. "
"Use ~c\"\" if you indeed want a charlist or use \"\" instead.\n"
"You may run \"mix format --migrate\" to fix this warning automatically.",
NewScope = prepend_warning(Line, Column, Message, Scope),
handle_strings(T, Line, Column + 1, $', NewScope, Tokens);

% Operator atoms
Expand Down
33 changes: 23 additions & 10 deletions lib/mix/lib/mix/tasks/format.ex
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ defmodule Mix.Tasks.Format do
as `.heex`. Without passing this flag, it is assumed that the code being
passed via stdin is valid Elixir code. Defaults to "stdin.exs".

* `--migrate` - enables the `:migrate` option, which should be able to
automatically fix some deprecation warnings but is changing the AST.
This should be safe in typical projects, but there is a non-zero risk
of breaking code for meta-programming heavy projects that relied on a
specific AST, or projects that are re-defining functions from the `Kernel`.
See the "Migration formatting" section in `Code.format_string!/2` for
more information.

## When to format code

We recommend developers to format code directly in their editors, either
Expand Down Expand Up @@ -184,7 +192,8 @@ defmodule Mix.Tasks.Format do
dot_formatter: :string,
dry_run: :boolean,
stdin_filename: :string,
force: :boolean
force: :boolean,
migrate: :boolean
]

@manifest_timestamp "format_timestamp"
Expand Down Expand Up @@ -362,17 +371,21 @@ defmodule Mix.Tasks.Format do
end

defp eval_dot_formatter(cwd, opts) do
cond do
dot_formatter = opts[:dot_formatter] ->
{dot_formatter, eval_file_with_keyword_list(dot_formatter)}
{dot_formatter, format_opts} =
cond do
dot_formatter = opts[:dot_formatter] ->
{dot_formatter, eval_file_with_keyword_list(dot_formatter)}

File.regular?(Path.join(cwd, ".formatter.exs")) ->
dot_formatter = Path.join(cwd, ".formatter.exs")
{".formatter.exs", eval_file_with_keyword_list(dot_formatter)}
File.regular?(Path.join(cwd, ".formatter.exs")) ->
dot_formatter = Path.join(cwd, ".formatter.exs")
{".formatter.exs", eval_file_with_keyword_list(dot_formatter)}

true ->
{".formatter.exs", []}
end
true ->
{".formatter.exs", []}
end

# the --migrate flag overrides settings from the dot formatter
{dot_formatter, Keyword.take(opts, [:migrate]) ++ format_opts}
end

# This function reads exported configuration from the imported
Expand Down
12 changes: 12 additions & 0 deletions lib/mix/test/mix/tasks/format_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,18 @@ defmodule Mix.Tasks.FormatTest do
end)
end

test "respects the --migrate flag", context do
in_tmp(context.test, fn ->
File.write!("a.ex", "unless foo, do: 'bar'\n")

Mix.Tasks.Format.run(["a.ex"])
assert File.read!("a.ex") == "unless foo, do: 'bar'\n"

Mix.Tasks.Format.run(["a.ex", "--migrate"])
assert File.read!("a.ex") == "if !foo, do: ~c\"bar\"\n"
end)
end

test "uses inputs and configuration from --dot-formatter", context do
in_tmp(context.test, fn ->
File.write!("custom_formatter.exs", """
Expand Down
Loading