Skip to content

Commit 5ec63f0

Browse files
authored
Fix charlist formatting issue on '\"' (#13364)
1 parent e6aefcd commit 5ec63f0

File tree

2 files changed

+29
-16
lines changed

2 files changed

+29
-16
lines changed

lib/elixir/lib/code/formatter.ex

+20-14
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ defmodule Code.Formatter do
66
@double_heredoc "\"\"\""
77
@single_quote "'"
88
@single_heredoc "'''"
9-
@sigil_c "~c\""
9+
@sigil_c_double "~c\""
10+
@sigil_c_single "~c'"
1011
@sigil_c_heredoc "~c\"\"\""
1112
@newlines 2
1213
@min_line 0
@@ -300,7 +301,7 @@ defmodule Code.Formatter do
300301
remote_to_algebra(quoted, context, state)
301302

302303
meta[:delimiter] == ~s['''] ->
303-
{opener, quotes} = get_charlist_quotes(true, state)
304+
{opener, quotes} = get_charlist_quotes(:heredoc, state)
304305

305306
{doc, state} =
306307
entries
@@ -310,7 +311,7 @@ defmodule Code.Formatter do
310311
{force_unfit(doc), state}
311312

312313
true ->
313-
{opener, quotes} = get_charlist_quotes(false, state)
314+
{opener, quotes} = get_charlist_quotes({:regular, entries}, state)
314315
list_interpolation_to_algebra(entries, quotes, state, opener, quotes)
315316
end
316317
end
@@ -369,13 +370,14 @@ defmodule Code.Formatter do
369370
defp quoted_to_algebra({:__block__, meta, [list]}, _context, state) when is_list(list) do
370371
case meta[:delimiter] do
371372
~s['''] ->
372-
{opener, quotes} = get_charlist_quotes(true, state)
373+
{opener, quotes} = get_charlist_quotes(:heredoc, state)
373374
string = list |> List.to_string() |> escape_heredoc(quotes)
374375
{opener |> concat(string) |> concat(quotes) |> force_unfit(), state}
375376

376377
~s['] ->
377-
{opener, quotes} = get_charlist_quotes(false, state)
378-
string = list |> List.to_string() |> escape_string(quotes)
378+
string = list |> List.to_string()
379+
{opener, quotes} = get_charlist_quotes({:regular, [string]}, state)
380+
string = escape_string(string, quotes)
379381
{opener |> concat(string) |> concat(quotes), state}
380382

381383
_other ->
@@ -2422,19 +2424,23 @@ defmodule Code.Formatter do
24222424
{left, right}
24232425
end
24242426

2425-
defp get_charlist_quotes(_heredoc = false, state) do
2427+
defp get_charlist_quotes(:heredoc, state) do
24262428
if state.normalize_charlists_as_sigils do
2427-
{@sigil_c, @double_quote}
2429+
{@sigil_c_heredoc, @double_heredoc}
24282430
else
2429-
{@single_quote, @single_quote}
2431+
{@single_heredoc, @single_heredoc}
24302432
end
24312433
end
24322434

2433-
defp get_charlist_quotes(_heredoc = true, state) do
2434-
if state.normalize_charlists_as_sigils do
2435-
{@sigil_c_heredoc, @double_heredoc}
2436-
else
2437-
{@single_heredoc, @single_heredoc}
2435+
defp get_charlist_quotes({:regular, chunks}, state) do
2436+
cond do
2437+
!state.normalize_charlists_as_sigils -> {@single_quote, @single_quote}
2438+
Enum.any?(chunks, &has_double_quote?/1) -> {@sigil_c_single, @single_quote}
2439+
true -> {@sigil_c_double, @double_quote}
24382440
end
24392441
end
2442+
2443+
defp has_double_quote?(chunk) do
2444+
is_binary(chunk) and chunk =~ @double_quote
2445+
end
24402446
end

lib/elixir/test/elixir/code_formatter/literals_test.exs

+9-2
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,15 @@ defmodule Code.Formatter.LiteralsTest do
210210
test "with escapes" do
211211
assert_format ~S['f\a\b\ro'], ~S[~c"f\a\b\ro"]
212212
assert_format ~S['single \' quote'], ~S[~c"single ' quote"]
213-
assert_format ~S['double " quote'], ~S[~c"double \" quote"]
213+
assert_format ~S['double " quote'], ~S[~c'double " quote']
214+
assert_format ~S['escaped \" quote'], ~S[~c'escaped \" quote']
215+
assert_format ~S['\\"'], ~S[~c'\\"']
214216

215217
assert_same ~S['f\a\b\ro'], @keep_charlists
216218
assert_same ~S['single \' quote'], @keep_charlists
219+
assert_same ~S['double " quote'], @keep_charlists
220+
assert_same ~S['escaped \" quote'], @keep_charlists
221+
assert_same ~S['\\"'], @keep_charlists
217222
end
218223

219224
test "keeps literal new lines" do
@@ -235,13 +240,15 @@ defmodule Code.Formatter.LiteralsTest do
235240

236241
test "with interpolation" do
237242
assert_format ~S['one #{2} three'], ~S[~c"one #{2} three"]
243+
assert_format ~S['#{1}\n \\ " \"'], ~S[~c'#{1}\n \\ " \"']
238244

239245
assert_same ~S['one #{2} three'], @keep_charlists
246+
assert_same ~S['#{1}\n \\ " \"'], @keep_charlists
240247
end
241248

242249
test "with escape and interpolation" do
243250
assert_format ~S['one\n\'#{2}\'\nthree'], ~S[~c"one\n'#{2}'\nthree"]
244-
assert_format ~S['one\n"#{2}"\nthree'], ~S[~c"one\n\"#{2}\"\nthree"]
251+
assert_format ~S['one\n"#{2}"\nthree'], ~S[~c'one\n"#{2}"\nthree']
245252

246253
assert_same ~S['one\n\'#{2}\'\nthree'], @keep_charlists
247254
end

0 commit comments

Comments
 (0)