Skip to content

Commit c0ed20e

Browse files
committed
Add delimiter meta to demote calls with quoted identifier
1 parent e54b87c commit c0ed20e

File tree

4 files changed

+38
-21
lines changed

4 files changed

+38
-21
lines changed

lib/elixir/src/elixir_parser.yrl

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -890,8 +890,15 @@ build_dot_container(Dot, Left, Right, Extra) ->
890890

891891
build_dot(Dot, Left, {_, Location, _} = Right) ->
892892
Meta = meta_from_token(Dot),
893-
IdentifierLocation = meta_from_location(Location),
894-
{'.', Meta, IdentifierLocation, [Left, extract_identifier(Right)]}.
893+
IdentifierMeta0 = meta_from_location(Location),
894+
IdentifierMeta1 =
895+
case Location of
896+
{_Line, _Column, {_Unencoded, Delimiter}} when Delimiter =/= nil ->
897+
delimiter(<<Delimiter>>) ++ IdentifierMeta0;
898+
_ ->
899+
IdentifierMeta0
900+
end,
901+
{'.', Meta, IdentifierMeta1, [Left, extract_identifier(Right)]}.
895902

896903
extract_identifier({Kind, _, Identifier}) when
897904
Kind == identifier; Kind == bracket_identifier; Kind == paren_identifier;
@@ -916,17 +923,17 @@ build_no_parens_do_block(Expr, Args, {BlockMeta, Block}) ->
916923
build_no_parens(Expr, Args) ->
917924
build_call(Expr, Args).
918925

919-
build_identifier({'.', Meta, IdentifierLocation, DotArgs}) ->
920-
{{'.', Meta, DotArgs}, [{no_parens, true} | IdentifierLocation], []};
926+
build_identifier({'.', Meta, IdentifierMeta, DotArgs}) ->
927+
{{'.', Meta, DotArgs}, [{no_parens, true} | IdentifierMeta], []};
921928

922929
build_identifier({'.', Meta, _} = Dot) ->
923930
{Dot, [{no_parens, true} | Meta], []};
924931

925932
build_identifier({_, Location, Identifier}) ->
926933
{Identifier, meta_from_location(Location), nil}.
927934

928-
build_call({'.', Meta, IdentifierLocation, DotArgs}, Args) ->
929-
{{'.', Meta, DotArgs}, IdentifierLocation, Args};
935+
build_call({'.', Meta, IdentifierMeta, DotArgs}, Args) ->
936+
{{'.', Meta, DotArgs}, IdentifierMeta, Args};
930937

931938
build_call({'.', Meta, _} = Dot, Args) ->
932939
{Dot, Meta, Args};

lib/elixir/src/elixir_tokenizer.erl

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ tokenize([$: | String] = Original, Line, Column, Scope, Tokens) ->
540540
{_Kind, Unencoded, Atom, Rest, Length, Ascii, _Special} ->
541541
NewScope = maybe_warn_for_ambiguous_bang_before_equals(atom, Unencoded, Rest, Line, Column, Scope),
542542
TrackedScope = track_ascii(Ascii, NewScope),
543-
Token = {atom, {Line, Column, Unencoded}, Atom},
543+
Token = {atom, {Line, Column, {Unencoded, nil}}, Atom},
544544
tokenize(Rest, Line, Column + 1 + Length, TrackedScope, [Token | Tokens]);
545545
empty when Scope#elixir_tokenizer.cursor_completion == false ->
546546
unexpected_token(Original, Line, Column, Scope, Tokens);
@@ -651,7 +651,7 @@ tokenize(String, Line, Column, OriginalScope, Tokens) ->
651651

652652
case Rest of
653653
[$: | T] when ?is_space(hd(T)) ->
654-
Token = {kw_identifier, {Line, Column, Unencoded}, Atom},
654+
Token = {kw_identifier, {Line, Column, {Unencoded, nil}}, Atom},
655655
tokenize(T, Line, Column + Length + 1, Scope, [Token | Tokens]);
656656

657657
[$: | T] when hd(T) =/= $: ->
@@ -671,7 +671,7 @@ tokenize(String, Line, Column, OriginalScope, Tokens) ->
671671

672672
_ when Kind == identifier ->
673673
NewScope = maybe_warn_for_ambiguous_bang_before_equals(identifier, Unencoded, Rest, Line, Column, Scope),
674-
Token = check_call_identifier(Line, Column, Unencoded, Atom, Rest),
674+
Token = check_call_identifier(Line, Column, Unencoded, nil, Atom, Rest),
675675
tokenize(Rest, Line, Column + Length, NewScope, [Token | Tokens]);
676676

677677
_ ->
@@ -918,7 +918,7 @@ handle_dot([$., H | T] = Original, Line, Column, DotInfo, Scope, Tokens) when ?i
918918

919919
case unsafe_to_atom(UnescapedPart, Line, Column, NewScope) of
920920
{ok, Atom} ->
921-
Token = check_call_identifier(Line, Column, Part, Atom, Rest),
921+
Token = check_call_identifier(Line, Column, Part, $", Atom, Rest),
922922
TokensSoFar = add_token_with_eol({'.', DotInfo}, Tokens),
923923
tokenize(Rest, NewLine, NewColumn, NewScope, [Token | TokensSoFar]);
924924

@@ -937,7 +937,7 @@ handle_dot([$. | Rest], Line, Column, DotInfo, Scope, Tokens) ->
937937
tokenize(Rest, Line, Column, Scope, TokensSoFar).
938938

939939
handle_call_identifier(Rest, Line, Column, DotInfo, Length, UnencodedOp, Scope, Tokens) ->
940-
Token = check_call_identifier(Line, Column, UnencodedOp, list_to_atom(UnencodedOp), Rest),
940+
Token = check_call_identifier(Line, Column, UnencodedOp, nil, list_to_atom(UnencodedOp), Rest),
941941
TokensSoFar = add_token_with_eol({'.', DotInfo}, Tokens),
942942
tokenize(Rest, Line, Column + Length, Scope, [Token | TokensSoFar]).
943943

@@ -1324,18 +1324,18 @@ tokenize_alias(Rest, Line, Column, Unencoded, Atom, Length, Ascii, Special, Scop
13241324
error(Reason, Unencoded ++ Rest, Scope, Tokens);
13251325

13261326
true ->
1327-
AliasesToken = {alias, {Line, Column, Unencoded}, Atom},
1327+
AliasesToken = {alias, {Line, Column, {Unencoded, nil}}, Atom},
13281328
tokenize(Rest, Line, Column + Length, Scope, [AliasesToken | Tokens])
13291329
end.
13301330

13311331
%% Check if it is a call identifier (paren | bracket | do)
13321332

1333-
check_call_identifier(Line, Column, Unencoded, Atom, [$( | _]) ->
1334-
{paren_identifier, {Line, Column, Unencoded}, Atom};
1335-
check_call_identifier(Line, Column, Unencoded, Atom, [$[ | _]) ->
1336-
{bracket_identifier, {Line, Column, Unencoded}, Atom};
1337-
check_call_identifier(Line, Column, Unencoded, Atom, _Rest) ->
1338-
{identifier, {Line, Column, Unencoded}, Atom}.
1333+
check_call_identifier(Line, Column, Unencoded, Delimiter, Atom, [$( | _]) ->
1334+
{paren_identifier, {Line, Column, {Unencoded, Delimiter}}, Atom};
1335+
check_call_identifier(Line, Column, Unencoded, Delimiter, Atom, [$[ | _]) ->
1336+
{bracket_identifier, {Line, Column, {Unencoded, Delimiter}}, Atom};
1337+
check_call_identifier(Line, Column, Unencoded, Delimiter, Atom, _Rest) ->
1338+
{identifier, {Line, Column, {Unencoded, Delimiter}}, Atom}.
13391339

13401340
add_token_with_eol({unary_op, _, _} = Left, T) -> [Left | T];
13411341
add_token_with_eol(Left, [{eol, _} | T]) -> [Left | T];

lib/elixir/test/elixir/kernel/parser_test.exs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,17 @@ defmodule Kernel.ParserTest do
128128
end
129129

130130
test "handles graphemes inside quoted identifiers" do
131-
assert {{:., _, [{:foo, _, nil}, :"➡️"]}, _, []} = Code.string_to_quoted!(~s|foo."➡️"|)
131+
assert {
132+
{:., _, [{:foo, _, nil}, :"➡️"]},
133+
[no_parens: true, delimiter: ~S["], line: 1],
134+
[]
135+
} = Code.string_to_quoted!(~S|foo."➡️"|, token_metadata: true)
136+
137+
assert {
138+
{:., _, [{:foo, _, nil}, :"➡️"]},
139+
[closing: [line: 1], delimiter: ~S["], line: 1],
140+
[]
141+
} = Code.string_to_quoted!(~S|foo."➡️"()|, token_metadata: true)
132142
end
133143
end
134144

lib/elixir/unicode/security.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ defmodule String.Tokenizer.Security do
4040
]
4141

4242
defp check_token_for_confusability(
43-
{kind, {_line, _column, [_ | _] = name} = info, _},
43+
{kind, {_line, _column, {[_ | _] = name, _delimiter}} = info, _},
4444
skeletons
4545
)
4646
when kind in @identifiers do
@@ -50,7 +50,7 @@ defmodule String.Tokenizer.Security do
5050
{_, _, ^name} ->
5151
{:ok, skeletons}
5252

53-
{line, _, previous_name} when name != previous_name ->
53+
{line, _, {previous_name, _delimiter}} when name != previous_name ->
5454
{:warn,
5555
"confusable identifier: '#{name}' looks like '#{previous_name}' on line #{line}, " <>
5656
"but they are written using different characters" <> dir_compare(name, previous_name)}

0 commit comments

Comments
 (0)