Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump erlfmt to upstream 1.3.0 #1469

Merged
merged 8 commits into from
Jan 17, 2024
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
4 changes: 4 additions & 0 deletions apps/els_lsp/src/els_erlfmt_ast.erl
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,10 @@ erlfmt_to_st(Node) ->
{clause, _, _, _, _} = Clause ->
%% clauses of case/if/receive/try
erlfmt_clause_to_st(Clause);
{else_clause, Pos, Clauses} ->
%% The else clause of a maybe expression - in OTP it is just called
%% 'else' but has the same format and content
erlfmt_to_st_1({'else', Pos, Clauses});
%% Lists are represented as a `list` node instead of a chain of `cons`
%% and `nil` nodes, similar to the `tuple` node. The last element of
%% the list can be a `cons` node representing explicit consing syntax.
Expand Down
31 changes: 24 additions & 7 deletions apps/els_lsp/src/els_parser.erl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@
-dialyzer([{nowarn_function, parse_text/1}]).
-dialyzer([{nowarn_function, fix_erlfmt/1}]).

%% Spec of erlfmt_parse:parse_node/1 is wrong,
%% error location can be returned in various formats
%% see https://github.com/WhatsApp/erlfmt/pull/352

-dialyzer([{nowarn_function, loc_to_pos/1}]).

%%==============================================================================
%% API
%%==============================================================================
Expand Down Expand Up @@ -149,25 +155,36 @@ parse_incomplete_tokens(Tokens) ->
{ok, Form} ->
{ok, Form};
{error, {ErrorLoc, erlfmt_parse, _Reason}} ->
TrimmedTokens = tokens_until(Tokens, ErrorLoc),
ErrorPos = loc_to_pos(ErrorLoc),
TrimmedTokens = tokens_until(Tokens, ErrorPos),
parse_incomplete_tokens(TrimmedTokens)
end.

%% Convert location in various formats to a consistent position that can always be compared
-spec loc_to_pos(erlfmt_scan:anno() | erl_anno:location()) -> pos().
loc_to_pos(#{location := Loc}) ->
%% erlfmt_scan:anno()
loc_to_pos(Loc);
loc_to_pos({Line, Col} = Loc) when is_integer(Line), is_integer(Col) ->
Loc;
loc_to_pos(Line) when is_integer(Line) ->
{Line, 0}.

%% @doc Drop tokens after given location but keep final dot, to preserve its
%% location
-spec tokens_until([erlfmt_scan:token()], erl_anno:location()) ->
-spec tokens_until([erlfmt_scan:token()], pos()) ->
[erlfmt_scan:token()].
tokens_until([_Hd, {dot, _} = Dot], _Loc) ->
tokens_until([_Hd, {dot, _} = Dot], _Pos) ->
%% We need to drop at least one token before the dot.
%% Otherwise if error location is at the dot, we cannot just drop the dot and
%% add a dot again, because it would result in an infinite loop.
[Dot];
tokens_until([Hd | Tail], Loc) ->
case erlfmt_scan:get_anno(location, Hd) < Loc of
tokens_until([Hd | Tail], Pos) ->
case erlfmt_scan:get_anno(location, Hd) < Pos of
true ->
[Hd | tokens_until(Tail, Loc)];
[Hd | tokens_until(Tail, Pos)];
false ->
tokens_until(Tail, Loc)
tokens_until(Tail, Pos)
end.

%% `erlfmt_scan' does not support start location other than {1,1}
Expand Down
59 changes: 58 additions & 1 deletion apps/els_lsp/test/els_parser_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
-export([
all/0,
init_per_suite/1,
end_per_suite/1
end_per_suite/1,
init_per_testcase/2
]).

%% Test cases
Expand Down Expand Up @@ -32,6 +33,9 @@
opaque_recursive/1,
record_def_recursive/1,
var_in_application/1,
comprehensions/1,
map_comprehensions/1,
maybe_expr/1,
unicode_clause_pattern/1,
latin1_source_code/1,
record_comment/1,
Expand Down Expand Up @@ -61,6 +65,23 @@ end_per_suite(_Config) -> ok.
-spec all() -> [atom()].
all() -> els_test_utils:all(?MODULE).

init_per_testcase(map_comprehensions, Config) ->
case list_to_integer(erlang:system_info(otp_release)) < 26 of
true ->
{skip, "Map comprehensions are only supported from OTP 26"};
false ->
Config
end;
init_per_testcase(maybe_expr, Config) ->
case list_to_integer(erlang:system_info(otp_release)) < 25 of
true ->
{skip, "Maybe expressions are only supported from OTP 25"};
false ->
Config
end;
init_per_testcase(_, Config) ->
Config.

%%==============================================================================
%% Testcases
%%==============================================================================
Expand Down Expand Up @@ -443,6 +464,42 @@ var_in_application(_Config) ->
),
ok.

comprehensions(_Config) ->
Text1 = "[X || X <- L]",
?assertMatch(
[#{id := 'X'}, #{id := 'X'}, #{id := 'L'}],
parse_find_pois(Text1, variable)
),

Text2 = "<< <<Y, X>> || <<X, Y>> <= B >>",
?assertMatch(
[#{id := 'Y'}, #{id := 'X'}, #{id := 'X'}, #{id := 'Y'}, #{id := 'B'}],
parse_find_pois(Text2, variable)
),
ok.

map_comprehensions(_Config) ->
Text3 = "#{ Y => X || X := Y <- M }",
?assertMatch(
[#{id := 'Y'}, #{id := 'X'}, #{id := 'X'}, #{id := 'Y'}, #{id := 'M'}],
parse_find_pois(Text3, variable)
),
ok.

maybe_expr(_Config) ->
Text1 = "maybe {ok, X} ?= f(), {ok, Y} ?= g() end",
?assertMatch(
[#{id := 'X'}, #{id := 'Y'}],
parse_find_pois(Text1, variable)
),

Text2 = "maybe {ok, X} ?= f() else {error, Err} -> Err end",
?assertMatch(
[#{id := 'X'}, #{id := 'Err'}, #{id := 'Err'}],
parse_find_pois(Text2, variable)
),
ok.

-spec unicode_clause_pattern(config()) -> ok.
unicode_clause_pattern(_Config) ->
%% From OTP compiler's bs_utf_SUITE.erl
Expand Down
28 changes: 27 additions & 1 deletion apps/els_lsp/test/els_parser_macros_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
macro_in_application/1,
record_def_field_macro/1,
module_macro_as_record_name/1,
other_macro_as_record_name/1
other_macro_as_record_name/1,
macro_guards/1,
macro_as_case_clause/1
]).

%%==============================================================================
Expand Down Expand Up @@ -229,6 +231,30 @@ other_macro_as_record_name(_Config) ->
?assertMatch([_], parse_find_pois(Text4, macro, 'M')),
ok.

macro_guards(_Config) ->
Text1 = "?foo(Expr when Guard1)",
?assertMatch([#{id := 'Expr'}, #{id := 'Guard1'}], parse_find_pois(Text1, variable)),

Text2 = "?foo(Expr when Guard1; Guard2)",
?assertMatch(
[#{id := 'Expr'}, #{id := 'Guard1'}, #{id := 'Guard2'}],
parse_find_pois(Text2, variable)
),
ok.

%% Supperted by erlfmt since erlfmt#350
macro_as_case_clause(_Config) ->
Text1 = "case X of ?M1(Y); ?M2(2) end",
?assertMatch(
[#{id := {'M1', 1}}, #{id := {'M2', 1}}],
parse_find_pois(Text1, macro)
),
?assertMatch(
[#{id := 'X'}, #{id := 'Y'}],
parse_find_pois(Text1, variable)
),
ok.

%%==============================================================================
%% Helper functions
%%==============================================================================
Expand Down
6 changes: 1 addition & 5 deletions rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@
{docsh, "0.7.2"},
{elvis_core, "~> 1.3"},
{rebar3_format, "0.8.2"},
%%, {erlfmt, "1.0.0"}

%% Temp until erlfmt PR 325 is merged (commit d4422d1)
{erlfmt,
{git, "https://github.com/gomoripeti/erlfmt.git", {tag, "erlang_ls_parser_error_loc"}}},
{erlfmt, "1.3.0"},
{ephemeral, "2.0.4"},
{tdiff, "0.1.2"},
{uuid, "2.0.1", {pkg, uuid_erl}},
Expand Down
7 changes: 3 additions & 4 deletions rebar.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
{<<"docsh">>,{pkg,<<"docsh">>,<<"0.7.2">>},0},
{<<"elvis_core">>,{pkg,<<"elvis_core">>,<<"1.3.1">>},0},
{<<"ephemeral">>,{pkg,<<"ephemeral">>,<<"2.0.4">>},0},
{<<"erlfmt">>,
{git,"https://github.com/gomoripeti/erlfmt.git",
{ref,"d4422d1fd79a73ef534c2bcbe5b5da4da5338833"}},
0},
{<<"erlfmt">>,{pkg,<<"erlfmt">>,<<"1.3.0">>},0},
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},2},
{<<"gradualizer">>,
{git,"https://github.com/josefs/Gradualizer.git",
Expand All @@ -31,6 +28,7 @@
{<<"docsh">>, <<"F893D5317A0E14269DD7FE79CF95FB6B9BA23513DA0480EC6E77C73221CAE4F2">>},
{<<"elvis_core">>, <<"844C339300DD3E9F929A045932D25DC5C99B4603D47536E995198143169CDF26">>},
{<<"ephemeral">>, <<"B3E57886ADD5D90C82FE3880F5954978222A122CB8BAA123667401BBAAEC51D6">>},
{<<"erlfmt">>, <<"672994B92B1A809C04C46F0B781B447BF9AB7A515F5856A96177BC1962F100A9">>},
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>},
{<<"jsx">>, <<"20A170ABD4335FC6DB24D5FAD1E5D677C55DADF83D1B20A8A33B5FE159892A39">>},
{<<"katana_code">>, <<"B2195859DF57D8BEBF619A9FD3327CD7D01563A98417156D0F4C5FAB435F2630">>},
Expand All @@ -46,6 +44,7 @@
{<<"docsh">>, <<"4E7DB461BB07540D2BC3D366B8513F0197712D0495BB85744F367D3815076134">>},
{<<"elvis_core">>, <<"7A8890BF8185A3252CD4EBD826FE5F8AD6B93024EDF88576EB27AE9E5DC19D69">>},
{<<"ephemeral">>, <<"4B293D80F75F9C4575FF4B9C8E889A56802F40B018BF57E74F19644EFEE6C850">>},
{<<"erlfmt">>, <<"2A84AA1EBA2F4FCD7DD31D5C57E9DE2BC2705DDA18DA4553F27DF7114CFAA052">>},
{<<"getopt">>, <<"53E1AB83B9CEB65C9672D3E7A35B8092E9BDC9B3EE80721471A161C10C59959C">>},
{<<"jsx">>, <<"37BECA0435F5CA8A2F45F76A46211E76418FBEF80C36F0361C249FC75059DC6D">>},
{<<"katana_code">>, <<"8448AD3F56D9814F98A28BE650F7191BDD506575E345CC16D586660B10F6E992">>},
Expand Down
Loading