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
2 changes: 1 addition & 1 deletion lib/elixir/lib/calendar/datetime.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1913,7 +1913,7 @@ defmodule DateTime do
if Calendar.compatible_calendars?(dt_calendar, calendar) do
result_datetime =
datetime
|> to_iso_days
|> to_iso_days()
|> from_iso_days(datetime, calendar, precision)

{:ok, result_datetime}
Expand Down
2 changes: 1 addition & 1 deletion lib/elixir/lib/calendar/naive_datetime.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1296,7 +1296,7 @@ defmodule NaiveDateTime do
if Calendar.compatible_calendars?(ndt_calendar, calendar) do
result_naive_datetime =
naive_datetime
|> to_iso_days
|> to_iso_days()
|> from_iso_days(calendar, precision)

{:ok, result_naive_datetime}
Expand Down
8 changes: 8 additions & 0 deletions lib/elixir/lib/code.ex
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,14 @@ defmodule Code do
modifiers, where `<<foo::custom_type>>` becomes `<<foo::custom_type()>>`.
Defaults to the value of the `:migrate` option. This option changes the AST.

* `:migrate_call_parens_on_pipe` (since v1.19.0) - when `true`,
formats calls on the right-hand side of the pipe operator to always include
parentheses, for example `foo |> bar` becomes `foo |> bar()` and
`foo |> mod.fun` becomes `foo |> mod.fun()`.
Parentheses are always added for qualified calls like `foo |> Bar.bar` even
when this option is `false`.
Defaults to the value of the `:migrate` option. This option changes the AST.

* `:migrate_charlists_as_sigils` (since v1.18.0) - when `true`,
formats charlists as [`~c`](`Kernel.sigil_c/2`) sigils, for example
`'foo'` becomes `~c"foo"`.
Expand Down
45 changes: 44 additions & 1 deletion lib/elixir/lib/code/formatter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ defmodule Code.Formatter do
sigils = Keyword.get(opts, :sigils, [])
migrate = Keyword.get(opts, :migrate, false)
migrate_bitstring_modifiers = Keyword.get(opts, :migrate_bitstring_modifiers, migrate)
migrate_call_parens_on_pipe = Keyword.get(opts, :migrate_call_parens_on_pipe, migrate)
migrate_charlists_as_sigils = Keyword.get(opts, :migrate_charlists_as_sigils, migrate)
migrate_unless = Keyword.get(opts, :migrate_unless, migrate)
syntax_colors = Keyword.get(opts, :syntax_colors, [])
Expand Down Expand Up @@ -218,6 +219,7 @@ defmodule Code.Formatter do
sigils: sigils,
file: file,
migrate_bitstring_modifiers: migrate_bitstring_modifiers,
migrate_call_parens_on_pipe: migrate_call_parens_on_pipe,
migrate_charlists_as_sigils: migrate_charlists_as_sigils,
migrate_unless: migrate_unless,
inspect_opts: %Inspect.Opts{syntax_colors: syntax_colors}
Expand Down Expand Up @@ -487,7 +489,16 @@ defmodule Code.Formatter do
binary_op_to_algebra(:in, "not in", meta, left, right, context, state)
end

# disable migrate_unless within defmacro
# disable migrate_call_parens_on_pipe within defmacro
defp quoted_to_algebra(
{atom, _, [{:|>, _, _}, _]} = ast,
context,
%{migrate_call_parens_on_pipe: true} = state
)
when atom in [:defmacro, :defmacrop] do
quoted_to_algebra(ast, context, %{state | migrate_call_parens_on_pipe: false})
end

defp quoted_to_algebra(
{atom, _, [{:unless, _, _}, _]} = ast,
context,
Expand Down Expand Up @@ -832,6 +843,38 @@ defmodule Code.Formatter do
{wrap_in_parens(doc), state}
end

# |> var
# |> var()
defp binary_operand_to_algebra(
{var, meta, var_context},
context,
%{migrate_call_parens_on_pipe: true} = state,
:|>,
_parent_info,
:right,
_nesting
)
when is_atom(var) and is_atom(var_context) do
operand = {var, meta, []}
quoted_to_algebra(operand, context, state)
end

# |> var.fun
# |> var.fun()
defp binary_operand_to_algebra(
{{:., _, [_, fun]} = call, meta, []},
context,
%{migrate_call_parens_on_pipe: true} = state,
:|>,
_parent_info,
:right,
_nesting
)
when is_atom(fun) do
meta = Keyword.put_new_lazy(meta, :closing, fn -> [line: meta[:line]] end)
quoted_to_algebra({call, meta, []}, context, state)
end

defp binary_operand_to_algebra(operand, context, state, parent_op, parent_info, side, nesting) do
{parent_assoc, parent_prec} = parent_info

Expand Down
6 changes: 3 additions & 3 deletions lib/elixir/lib/io/ansi/docs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ defmodule IO.ANSI.Docs do
col
|> String.trim()
|> String.replace("\\\|", "|")
|> handle_links
|> handle_links()
|> handle_inline(options)

{col, length_without_escape(col, 0)}
Expand Down Expand Up @@ -610,8 +610,8 @@ defmodule IO.ANSI.Docs do

defp handle_links(text) do
text
|> remove_square_brackets_in_link
|> escape_underlines_in_link
|> remove_square_brackets_in_link()
|> escape_underlines_in_link()
end

defp escape_underlines_in_link(text) do
Expand Down
2 changes: 1 addition & 1 deletion lib/elixir/lib/system.ex
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ defmodule System do
~c"git rev-parse --short=7 HEAD 2> "
|> Kernel.++(null)
|> :os.cmd()
|> strip
|> strip()
end

defp revision, do: get_revision()
Expand Down
29 changes: 29 additions & 0 deletions lib/elixir/test/elixir/code_formatter/migration_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,27 @@ defmodule Code.Formatter.MigrationTest do
end
end

describe "migrate_call_parens_on_pipe: true" do
@opts [migrate_call_parens_on_pipe: true]

test "adds parentheses on the right operand" do
assert_format "x |> y", "x |> y()", @opts
assert_format "x |> y |> z", "x |> y() |> z()", @opts
assert_format "x |> y.z", "x |> y.z()", @opts
assert_format "x |> y.z.t", "x |> y.z.t()", @opts
end

test "does nothing within defmacro" do
assert_same "defmacro left |> right, do: ...", @opts
end

test "does nothing without the migrate_unless option" do
assert_same "x |> y"
assert_same "x |> y |> z"
assert_same "x |> y.z"
end
end

describe "migrate_charlists_as_sigils: true" do
@opts [migrate_charlists_as_sigils: true]

Expand Down Expand Up @@ -281,6 +302,14 @@ defmodule Code.Formatter.MigrationTest do
assert_format "<<foo::binary()>>", "<<foo::binary>>", migrate: true
end

test "enables :migrate_call_parens_on_pipe" do
bad = "x |> y"

good = "x |> y()"

assert_format bad, good, migrate: true
end

test "enables :migrate_charlists_as_sigils" do
assert_format ~S['abc'], ~S[~c"abc"], migrate: true
end
Expand Down
42 changes: 21 additions & 21 deletions lib/elixir/test/elixir/exception_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -894,76 +894,76 @@ defmodule ExceptionTest do
import Exception, only: [message: 1]

test "RuntimeError" do
assert %RuntimeError{} |> message == "runtime error"
assert %RuntimeError{message: "unexpected roquefort"} |> message == "unexpected roquefort"
assert %RuntimeError{} |> message() == "runtime error"
assert %RuntimeError{message: "unexpected roquefort"} |> message() == "unexpected roquefort"
end

test "ArithmeticError" do
assert %ArithmeticError{} |> message == "bad argument in arithmetic expression"
assert %ArithmeticError{} |> message() == "bad argument in arithmetic expression"

assert %ArithmeticError{message: "unexpected camembert"}
|> message == "unexpected camembert"
|> message() == "unexpected camembert"
end

test "ArgumentError" do
assert %ArgumentError{} |> message == "argument error"
assert %ArgumentError{message: "unexpected comté"} |> message == "unexpected comté"
assert %ArgumentError{} |> message() == "argument error"
assert %ArgumentError{message: "unexpected comté"} |> message() == "unexpected comté"
end

test "KeyError" do
assert %KeyError{} |> message == "key nil not found"
assert %KeyError{message: "key missed"} |> message == "key missed"
assert %KeyError{} |> message() == "key nil not found"
assert %KeyError{message: "key missed"} |> message() == "key missed"
end

test "Enum.OutOfBoundsError" do
assert %Enum.OutOfBoundsError{} |> message == "out of bounds error"
assert %Enum.OutOfBoundsError{} |> message() == "out of bounds error"

assert %Enum.OutOfBoundsError{message: "the brie is not on the table"}
|> message == "the brie is not on the table"
|> message() == "the brie is not on the table"
end

test "Enum.EmptyError" do
assert %Enum.EmptyError{} |> message == "empty error"
assert %Enum.EmptyError{} |> message() == "empty error"

assert %Enum.EmptyError{message: "there is no saint-nectaire left!"}
|> message == "there is no saint-nectaire left!"
|> message() == "there is no saint-nectaire left!"
end

test "UndefinedFunctionError" do
assert %UndefinedFunctionError{} |> message == "undefined function"
assert %UndefinedFunctionError{} |> message() == "undefined function"

assert %UndefinedFunctionError{module: Kernel, function: :bar, arity: 1}
|> message == "function Kernel.bar/1 is undefined or private"
|> message() == "function Kernel.bar/1 is undefined or private"

assert %UndefinedFunctionError{module: Foo, function: :bar, arity: 1}
|> message ==
|> message() ==
"function Foo.bar/1 is undefined (module Foo is not available). " <>
"Make sure the module name is correct and has been specified in full (or that an alias has been defined)"

assert %UndefinedFunctionError{module: nil, function: :bar, arity: 3}
|> message == "function nil.bar/3 is undefined"
|> message() == "function nil.bar/3 is undefined"

assert %UndefinedFunctionError{module: nil, function: :bar, arity: 0}
|> message == "function nil.bar/0 is undefined"
|> message() == "function nil.bar/0 is undefined"
end

test "FunctionClauseError" do
assert %FunctionClauseError{} |> message == "no function clause matches"
assert %FunctionClauseError{} |> message() == "no function clause matches"

assert %FunctionClauseError{module: Foo, function: :bar, arity: 1}
|> message == "no function clause matching in Foo.bar/1"
|> message() == "no function clause matching in Foo.bar/1"
end

test "ErlangError" do
assert %ErlangError{original: :sample} |> message == "Erlang error: :sample"
assert %ErlangError{original: :sample} |> message() == "Erlang error: :sample"
end

test "MissingApplicationsError" do
assert %MissingApplicationsError{
apps: [{:logger, "~> 1.18"}, {:ex_unit, Version.parse_requirement!(">= 0.0.0")}],
description: "applications are required"
}
|> message == """
|> message() == """
applications are required

To address this, include these applications as your dependencies:
Expand Down
12 changes: 6 additions & 6 deletions lib/elixir/test/elixir/file_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ defmodule FileTest do

try do
File.touch!(dest)
assert File.cp_r(src, dest) |> io_error?
assert File.cp_r(src, dest) |> io_error?()
after
File.rm_rf(dest)
end
Expand Down Expand Up @@ -686,8 +686,8 @@ defmodule FileTest do
end

test "cp_r with src dir and dest dir using lists" do
src = fixture_path("cp_r") |> to_charlist
dest = tmp_path("tmp") |> to_charlist
src = fixture_path("cp_r") |> to_charlist()
dest = tmp_path("tmp") |> to_charlist()

File.mkdir(dest)

Expand Down Expand Up @@ -1012,7 +1012,7 @@ defmodule FileTest do
end

test "mkdir with list" do
fixture = tmp_path("tmp_test") |> to_charlist
fixture = tmp_path("tmp_test") |> to_charlist()

try do
refute File.exists?(fixture)
Expand Down Expand Up @@ -1083,7 +1083,7 @@ defmodule FileTest do
end

test "mkdir_p with nested directory and list" do
base = tmp_path("tmp_test") |> to_charlist
base = tmp_path("tmp_test") |> to_charlist()
fixture = Path.join(base, "test")
refute File.exists?(base)

Expand Down Expand Up @@ -1287,7 +1287,7 @@ defmodule FileTest do
end

test "rm_rf with charlist" do
fixture = tmp_path("tmp") |> to_charlist
fixture = tmp_path("tmp") |> to_charlist()
File.mkdir(fixture)
File.cp_r!(fixture_path("cp_r"), fixture)

Expand Down
4 changes: 2 additions & 2 deletions lib/elixir/test/elixir/io/ansi/docs_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ defmodule IO.ANSI.DocsTest do

test "multiple entries formatted" do
result = format_headings(["foo", "bar"])
assert :binary.matches(result, "\e[0m\n\e[7m\e[33m") |> length == 2
assert :binary.matches(result, "\e[0m\n\e[7m\e[33m") |> length() == 2
assert String.starts_with?(result, "\e[0m\n\e[7m\e[33m")
assert String.ends_with?(result, "\e[0m\n\e[0m")
assert String.contains?(result, " foo ")
Expand All @@ -36,7 +36,7 @@ defmodule IO.ANSI.DocsTest do

test "is correctly formatted when newline character is present" do
result = format_headings(["foo\nbar"])
assert :binary.matches(result, "\e[0m\n\e[7m\e[33m") |> length == 2
assert :binary.matches(result, "\e[0m\n\e[7m\e[33m") |> length() == 2
assert ["\e[0m", foo_line, bar_line, "\e[0m"] = String.split(result, "\n")
assert Regex.match?(~r/\e\[7m\e\[33m +foo +\e\[0m/, foo_line)
assert Regex.match?(~r/\e\[7m\e\[33m +bar +\e\[0m/, bar_line)
Expand Down
2 changes: 1 addition & 1 deletion lib/elixir/test/elixir/kernel/cli_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ defmodule Kernel.CLI.ExecutableTest do
end

test "parses paths", %{cli_extension: cli_extension} do
root = fixture_path("../../..") |> to_charlist
root = fixture_path("../../..") |> to_charlist()

args =
~c"-pa \"#{root}/*\" -pz \"#{root}/lib/*\" -e \"IO.inspect(:code.get_path(), limit: :infinity)\""
Expand Down
4 changes: 2 additions & 2 deletions lib/elixir/test/elixir/kernel_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -1213,11 +1213,11 @@ defmodule KernelTest do
end

test "local call" do
assert [1, [2], 3] |> List.flatten() |> local == [2, 4, 6]
assert [1, [2], 3] |> List.flatten() |> local() == [2, 4, 6]
end

test "with capture" do
assert Enum.map([1, 2, 3], &(&1 |> twice |> twice)) == [4, 8, 12]
assert Enum.map([1, 2, 3], &(&1 |> twice() |> twice())) == [4, 8, 12]
end

test "with anonymous functions" do
Expand Down
2 changes: 1 addition & 1 deletion lib/elixir/test/elixir/macro_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -1540,7 +1540,7 @@ defmodule MacroTest do
test "generate_arguments/2" do
assert Macro.generate_arguments(0, __MODULE__) == []
assert Macro.generate_arguments(1, __MODULE__) == [{:arg1, [], __MODULE__}]
assert Macro.generate_arguments(4, __MODULE__) |> length == 4
assert Macro.generate_arguments(4, __MODULE__) |> length() == 4
end

defp postwalk(ast) do
Expand Down
2 changes: 1 addition & 1 deletion lib/elixir/test/elixir/module/types/descr_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ defmodule Module.Types.DescrTest do

refute difference(tuple(), empty_tuple())
|> difference(open_tuple([term(), term()]))
|> empty?
|> empty?()

assert difference(open_tuple([term()]), open_tuple([term(), term()]))
|> difference(tuple([term()]))
Expand Down
Loading
Loading