diff --git a/lib/elixir/src/elixir_parser.yrl b/lib/elixir/src/elixir_parser.yrl index 8b28b2ff91c..8777a44d742 100644 --- a/lib/elixir/src/elixir_parser.yrl +++ b/lib/elixir/src/elixir_parser.yrl @@ -890,8 +890,15 @@ build_dot_container(Dot, Left, Right, Extra) -> build_dot(Dot, Left, {_, Location, _} = Right) -> Meta = meta_from_token(Dot), - IdentifierLocation = meta_from_location(Location), - {'.', Meta, IdentifierLocation, [Left, extract_identifier(Right)]}. + IdentifierMeta0 = meta_from_location(Location), + IdentifierMeta1 = + case Dot of + {'.', {_Line, _Column, Delimiter}} when Delimiter =/= nil -> + delimiter(<>) ++ IdentifierMeta0; + _ -> + IdentifierMeta0 + end, + {'.', Meta, IdentifierMeta1, [Left, extract_identifier(Right)]}. extract_identifier({Kind, _, Identifier}) when Kind == identifier; Kind == bracket_identifier; Kind == paren_identifier; @@ -916,8 +923,8 @@ build_no_parens_do_block(Expr, Args, {BlockMeta, Block}) -> build_no_parens(Expr, Args) -> build_call(Expr, Args). -build_identifier({'.', Meta, IdentifierLocation, DotArgs}) -> - {{'.', Meta, DotArgs}, [{no_parens, true} | IdentifierLocation], []}; +build_identifier({'.', Meta, IdentifierMeta, DotArgs}) -> + {{'.', Meta, DotArgs}, [{no_parens, true} | IdentifierMeta], []}; build_identifier({'.', Meta, _} = Dot) -> {Dot, [{no_parens, true} | Meta], []}; @@ -925,8 +932,8 @@ build_identifier({'.', Meta, _} = Dot) -> build_identifier({_, Location, Identifier}) -> {Identifier, meta_from_location(Location), nil}. -build_call({'.', Meta, IdentifierLocation, DotArgs}, Args) -> - {{'.', Meta, DotArgs}, IdentifierLocation, Args}; +build_call({'.', Meta, IdentifierMeta, DotArgs}, Args) -> + {{'.', Meta, DotArgs}, IdentifierMeta, Args}; build_call({'.', Meta, _} = Dot, Args) -> {Dot, Meta, Args}; diff --git a/lib/elixir/src/elixir_tokenizer.erl b/lib/elixir/src/elixir_tokenizer.erl index 45ee82c244e..ebe290d35cc 100644 --- a/lib/elixir/src/elixir_tokenizer.erl +++ b/lib/elixir/src/elixir_tokenizer.erl @@ -919,7 +919,8 @@ handle_dot([$., H | T] = Original, Line, Column, DotInfo, Scope, Tokens) when ?i case unsafe_to_atom(UnescapedPart, Line, Column, NewScope) of {ok, Atom} -> Token = check_call_identifier(Line, Column, Part, Atom, Rest), - TokensSoFar = add_token_with_eol({'.', DotInfo}, Tokens), + DotInfo1 = setelement(3, DotInfo, $"), + TokensSoFar = add_token_with_eol({'.', DotInfo1}, Tokens), tokenize(Rest, NewLine, NewColumn, NewScope, [Token | TokensSoFar]); {error, Reason} -> diff --git a/lib/elixir/test/elixir/kernel/parser_test.exs b/lib/elixir/test/elixir/kernel/parser_test.exs index 70a9188289e..b18f8a34982 100644 --- a/lib/elixir/test/elixir/kernel/parser_test.exs +++ b/lib/elixir/test/elixir/kernel/parser_test.exs @@ -128,7 +128,17 @@ defmodule Kernel.ParserTest do end test "handles graphemes inside quoted identifiers" do - assert {{:., _, [{:foo, _, nil}, :"➡️"]}, _, []} = Code.string_to_quoted!(~s|foo."➡️"|) + assert { + {:., _, [{:foo, _, nil}, :"➡️"]}, + [no_parens: true, delimiter: ~S["], line: 1], + [] + } = Code.string_to_quoted!(~S|foo."➡️"|, token_metadata: true) + + assert { + {:., _, [{:foo, _, nil}, :"➡️"]}, + [closing: [line: 1], delimiter: ~S["], line: 1], + [] + } = Code.string_to_quoted!(~S|foo."➡️"()|, token_metadata: true) end end