From 316ef5b65471604fb0f73281af46ae5ef7898cb3 Mon Sep 17 00:00:00 2001 From: vk Date: Sun, 28 Nov 2021 17:21:35 +0200 Subject: [PATCH 1/4] Sheldon diagnostics --- .gitignore | 1 + .../src/diagnostics_sheldon.erl | 4 + apps/els_lsp/src/els_diagnostics.erl | 14 ++- apps/els_lsp/src/els_sheldon_diagnostics.erl | 114 ++++++++++++++++++ apps/els_lsp/test/els_diagnostics_SUITE.erl | 46 +++++++ elvis.config | 1 + rebar.config | 1 + rebar.lock | 9 ++ 8 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 apps/els_lsp/priv/code_navigation/src/diagnostics_sheldon.erl create mode 100644 apps/els_lsp/src/els_sheldon_diagnostics.erl diff --git a/.gitignore b/.gitignore index 9e6171188..6c043ddef 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ doc # Emacs temporary files .#* *# +rebar3 diff --git a/apps/els_lsp/priv/code_navigation/src/diagnostics_sheldon.erl b/apps/els_lsp/priv/code_navigation/src/diagnostics_sheldon.erl new file mode 100644 index 000000000..63daeb846 --- /dev/null +++ b/apps/els_lsp/priv/code_navigation/src/diagnostics_sheldon.erl @@ -0,0 +1,4 @@ +%% Trigger some "somestrange" warnings + +%% Trigger some "sheldon" warnings +-module(diagnostics_sheldon). diff --git a/apps/els_lsp/src/els_diagnostics.erl b/apps/els_lsp/src/els_diagnostics.erl index 9c9b4b303..4c7b5fdeb 100644 --- a/apps/els_lsp/src/els_diagnostics.erl +++ b/apps/els_lsp/src/els_diagnostics.erl @@ -63,6 +63,7 @@ available_diagnostics() -> , <<"dialyzer">> , <<"gradualizer">> , <<"elvis">> + , <<"sheldon">> , <<"unused_includes">> , <<"unused_macros">> , <<"unused_record_fields">> @@ -78,7 +79,9 @@ enabled_diagnostics() -> Default = default_diagnostics(), Enabled = maps:get("enabled", Config, []), Disabled = maps:get("disabled", Config, []), - lists:usort((Default ++ valid(Enabled)) -- valid(Disabled)). + Diagnostics = lists:usort((Default ++ valid(Enabled)) -- valid(Disabled)), + ok = extra(Diagnostics), + Diagnostics. -spec make_diagnostic(range(), binary(), severity(), binary()) -> diagnostic(). make_diagnostic(Range, Message, Severity, Source) -> @@ -146,3 +149,12 @@ valid(Ids0) -> }) end, Valid. + +-spec extra(list()) -> ok. +extra([]) -> + ok; +extra([<<"sheldon">>|_]) -> + {ok, _} = application:ensure_all_started(rebar3_sheldon), + ok; +extra([_|T]) -> + extra(T). diff --git a/apps/els_lsp/src/els_sheldon_diagnostics.erl b/apps/els_lsp/src/els_sheldon_diagnostics.erl new file mode 100644 index 000000000..3e0639433 --- /dev/null +++ b/apps/els_lsp/src/els_sheldon_diagnostics.erl @@ -0,0 +1,114 @@ +%%============================================================================== +%% Compiler diagnostics +%%============================================================================== + +-module(els_sheldon_diagnostics). + +%%============================================================================== +%% Behaviours +%%============================================================================== + +-behaviour(els_diagnostics). + +%%============================================================================== +%% Exports +%%============================================================================== + +-export([ is_default/0 + , run/1 + , source/0 + ]). + +%%============================================================================== +%% Includes +%%============================================================================== + +-include("els_lsp.hrl"). +-include_lib("kernel/include/logger.hrl"). + +%%============================================================================== +%% Callback Functions +%%============================================================================== + +-spec is_default() -> boolean(). +is_default() -> + false. + +-spec run(uri()) -> [els_diagnostics:diagnostic()]. +run(Uri) -> + case els_utils:project_relative(Uri) of + {error, not_relative} -> []; + RelFile -> + try + RegEx = "[_@./#&+-=*]", + Mod = rebar3_sheldon_ast, + Mod:spellcheck([RelFile], RegEx) + of + [] -> []; + Problems -> format_diagnostics(Problems) + catch _:Err -> + ?LOG_WARNING("Sheldon error.[Err=~p] ", [Err]), + [] + end + end. + +-spec source() -> binary(). +source() -> + <<"Sheldon">>. + +%%============================================================================== +%% Internal Functions +%%============================================================================== + +-spec format_diagnostics(any()) -> [map()]. +format_diagnostics(Data) -> + R = format_rules(Data), + lists:flatten(R). + +-spec format_rules([any()]) -> [[map()]]. +format_rules([]) -> + []; +format_rules([#{reason := #{misspelled_words := Miss}} = Data | EItems]) -> + ItemDiags = format_item(Miss, Data), + [lists:flatten(ItemDiags) | format_rules(EItems)]. + +-spec format_item([any()], map()) -> [[map()]]. +format_item([#{candidates := [], word := Word} | Items], Data) -> + #{line := Line, type := Type} = Data, + Msg = format_text("The word ~p in ~p is unknown.", [Word, Type]), + Diagnostic = diagnostic(Msg, Line, ?DIAGNOSTIC_WARNING), + [Diagnostic | format_item(Items, Data)]; +format_item([#{candidates := Candidates, word := Word} | Items], Data) -> + #{line := Line, type := Type} = Data, + FormatCandidates = format_sheldon_candidates(Candidates, []), + Text = "The word ~p in ~p is unknown. Maybe you wanted to use ~ts?", + Msg = format_text(Text, [Word, Type, FormatCandidates]), + Diagnostic = diagnostic(Msg, Line, ?DIAGNOSTIC_WARNING), + [Diagnostic | format_item(Items, Data)]; +format_item([], _) -> + []. + +-spec diagnostic( any(), integer(), els_diagnostics:severity()) -> [map()]. +diagnostic(Msg, Ln, Severity) -> + Range = els_protocol:range(#{from => {Ln, 1}, to => {Ln + 1, 1}}), + Message = els_utils:to_binary(Msg), + [#{ range => Range + , severity => Severity + , code => spellcheck + , source => source() + , message => Message + , relatedInformation => [] + }]. + +-spec format_sheldon_candidates([any()], [[[any()] | char()]]) -> list(). +format_sheldon_candidates([], Acc) -> + Acc; +format_sheldon_candidates([Candidate], Acc) -> + [Acc, format_text("~p", [Candidate])]; +format_sheldon_candidates([Candidate | T], Acc) -> + format_sheldon_candidates(T, [Acc, format_text("~p or ", [Candidate])]). + +-spec format_text(string(), list()) -> string(). +format_text(Text, Args) -> + Formatted = io_lib:format(Text, Args), + unicode:characters_to_list(Formatted). diff --git a/apps/els_lsp/test/els_diagnostics_SUITE.erl b/apps/els_lsp/test/els_diagnostics_SUITE.erl index 928c82205..2642fb926 100644 --- a/apps/els_lsp/test/els_diagnostics_SUITE.erl +++ b/apps/els_lsp/test/els_diagnostics_SUITE.erl @@ -41,6 +41,7 @@ , unused_macros/1 , unused_record_fields/1 , gradualizer/1 + , sheldon/1 ]). %%============================================================================== @@ -123,6 +124,11 @@ init_per_testcase(TestCase, Config) when TestCase =:= gradualizer -> meck:expect(els_gradualizer_diagnostics, is_default, 0, true), els_mock_diagnostics:setup(), els_test_utils:init_per_testcase(TestCase, Config); +init_per_testcase(TestCase, Config) when TestCase =:= sheldon -> + meck:new(els_sheldon_diagnostics, [passthrough, no_link]), + meck:expect(els_sheldon_diagnostics, is_default, 0, true), + els_mock_diagnostics:setup(), + els_test_utils:init_per_testcase(TestCase, Config); init_per_testcase(TestCase, Config) -> els_mock_diagnostics:setup(), els_test_utils:init_per_testcase(TestCase, Config). @@ -164,6 +170,11 @@ end_per_testcase(TestCase, Config) when TestCase =:= gradualizer -> els_test_utils:end_per_testcase(TestCase, Config), els_mock_diagnostics:teardown(), ok; +end_per_testcase(TestCase, Config) when TestCase =:= sheldon -> + meck:unload(els_sheldon_diagnostics), + els_test_utils:end_per_testcase(TestCase, Config), + els_mock_diagnostics:teardown(), + ok; end_per_testcase(TestCase, Config) -> els_test_utils:end_per_testcase(TestCase, Config), els_mock_diagnostics:teardown(), @@ -654,6 +665,41 @@ gradualizer(_Config) -> Hints = [], els_test:run_diagnostics_test(Path, Source, Errors, Warnings, Hints). +-spec sheldon(config()) -> ok. +sheldon(_Config) -> + case list_to_integer(erlang:system_info(otp_release)) >= 23 of + true -> + {ok, Cwd} = file:get_cwd(), + RootPath = els_test_utils:root_path(), + try + file:set_cwd(RootPath), + Path = src_path("diagnostics_sheldon.erl"), + Source = <<"Sheldon">>, + Errors = [], + Warnings = [ #{ code => spellcheck + , message => <<"The word \"sheldon\" in " + "comment is unknown. " + "Maybe you wanted to use \"Sheldon\"?">> + , range => {{2, 0}, {3, 0}} + , relatedInformation => [] + } + , #{ code => spellcheck + , message => <<"The word \"somestrange\" in comment is " + "unknown.">> + , range => {{0, 0}, {1, 0}} + , relatedInformation => [] + } + ], + Hints = [], + els_test:run_diagnostics_test(Path, Source, Errors, Warnings, Hints) + catch _Err -> + file:set_cwd(Cwd) + end, + ok; + false -> + {skipped, "Sheldon diagnostics should run on OTP23+"} + end. + %%============================================================================== %% Internal Functions %%============================================================================== diff --git a/elvis.config b/elvis.config index b7b1f3ffc..6c2b1c8c5 100644 --- a/elvis.config +++ b/elvis.config @@ -34,6 +34,7 @@ , els_tcp , els_dap_test_utils , els_test_utils + , els_sheldon_diagnostics ]}} , {elvis_text_style, line_length, #{limit => 80, skip_comments => false}} , {elvis_style, operator_spaces, #{ rules => [ {right, ","} diff --git a/rebar.config b/rebar.config index aa7377986..657935e45 100644 --- a/rebar.config +++ b/rebar.config @@ -17,6 +17,7 @@ , {tdiff, "0.1.2"} , {uuid, "2.0.1", {pkg, uuid_erl}} , {gradualizer, {git, "https://github.com/josefs/Gradualizer.git", {ref, "e93db1c"}}} + , {rebar3_sheldon, "0.4.1"} ] }. diff --git a/rebar.lock b/rebar.lock index 36a73a456..07c9b0b9e 100644 --- a/rebar.lock +++ b/rebar.lock @@ -14,9 +14,12 @@ {<<"providers">>,{pkg,<<"providers">>,<<"1.8.1">>},1}, {<<"quickrand">>,{pkg,<<"quickrand">>,<<"2.0.1">>},1}, {<<"rebar3_format">>,{pkg,<<"rebar3_format">>,<<"0.8.2">>},0}, + {<<"rebar3_sheldon">>,{pkg,<<"rebar3_sheldon">>,<<"0.4.1">>},0}, {<<"redbug">>,{pkg,<<"redbug">>,<<"2.0.6">>},0}, + {<<"sheldon">>,{pkg,<<"sheldon">>,<<"0.4.1">>},1}, {<<"tdiff">>,{pkg,<<"tdiff">>,<<"0.1.2">>},0}, {<<"uuid">>,{pkg,<<"uuid_erl">>,<<"2.0.1">>},0}, + {<<"worker_pool">>,{pkg,<<"worker_pool">>,<<"5.1.0">>},2}, {<<"yamerl">>,{pkg,<<"yamerl">>,<<"0.8.1">>},0}, {<<"zipper">>,{pkg,<<"zipper">>,<<"1.0.1">>},1}]}. [ @@ -32,9 +35,12 @@ {<<"providers">>, <<"70B4197869514344A8A60E2B2A4EF41CA03DEF43CFB1712ECF076A0F3C62F083">>}, {<<"quickrand">>, <<"6D861FA11E6EB51BB2343A2616EFF704C2681A9997F41ABC78E58FA76DA33981">>}, {<<"rebar3_format">>, <<"2D64DA61E0B87FCA6C4512ADA6D9CBC2B27ADC9AE6844178561147E7121761BD">>}, + {<<"rebar3_sheldon">>, <<"E2F4535929A25A7F8CFCCFC23E3CF93839BCC7F83C0BFFBBDB3446210D8014D4">>}, {<<"redbug">>, <<"A764690B012B67C404562F9C6E1BA47A73892EE17DF5C15F670B1A5BF9D2F25A">>}, + {<<"sheldon">>, <<"1413143F9D96D30C6A18DD6746B5183F048B23AC345FF3BB92B399A5A69EBE93">>}, {<<"tdiff">>, <<"4E1B30321F1B3D600DF65CD60858EDE1235FE4E5EE042110AB5AD90CD6464AC5">>}, {<<"uuid">>, <<"1FD9079C544D521063897887A1C5B3302DCA98F9BB06AADCDC6FB0663F256797">>}, + {<<"worker_pool">>, <<"61BA970F856AF8B2D85232ADC8E4B990FA1719F396FCDAD954702946395ADD80">>}, {<<"yamerl">>, <<"07DA13FFA1D8E13948943789665C62CCD679DFA7B324A4A2ED3149DF17F453A4">>}, {<<"zipper">>, <<"3CCB4F14B97C06B2749B93D8B6C204A1ECB6FAFC6050CACC3B93B9870C05952A">>}]}, {pkg_hash_ext,[ @@ -49,9 +55,12 @@ {<<"providers">>, <<"E45745ADE9C476A9A469EA0840E418AB19360DC44F01A233304E118A44486BA0">>}, {<<"quickrand">>, <<"14DB67D4AEF6B8815810EC9F3CCEF5E324B73B56CAE3687F99D752B85BDD4C96">>}, {<<"rebar3_format">>, <<"CA8FF27638C2169593D1449DACBE8895634193ED3334E906B54FC97F081F5213">>}, + {<<"rebar3_sheldon">>, <<"79DAA99B7B58F590B9DBD2641B0C0E0F116D79E587779E861D4246B1D7CD5737">>}, {<<"redbug">>, <<"AAD9498671F4AB91EACA5099FE85A61618158A636E6286892C4F7CF4AF171D04">>}, + {<<"sheldon">>, <<"15E24EDDCDB42FE07AA7913DA770DBCE4EE052A37AA76E467748D4C977F463C9">>}, {<<"tdiff">>, <<"E0C2E168F99252A5889768D5C8F1E6510A184592D4CFA06B22778A18D33D7875">>}, {<<"uuid">>, <<"AB57CACCD51F170011E5F444CE865F84B41605E483A9EFCC468C1AFAEC87553B">>}, + {<<"worker_pool">>, <<"59A975728E5C2B69A23D1C5EBC3B63251EC4ACBF4E9D25F1C619E3AD4B550813">>}, {<<"yamerl">>, <<"96CB30F9D64344FED0EF8A92E9F16F207DE6C04DFFF4F366752CA79F5BCEB23F">>}, {<<"zipper">>, <<"6A1FD3E1F0CC1D1DF5642C9A0CE2178036411B0A5C9642851D1DA276BD737C2D">>}]} ]. From 630156cd2009d02088ae169c8932136f2f9bf0ac Mon Sep 17 00:00:00 2001 From: vk Date: Thu, 2 Dec 2021 16:00:00 +0200 Subject: [PATCH 2/4] * stop use dinamic call of rebar3_sheldon * return map instead of list in diagnostic sheldon --- apps/els_lsp/src/els_diagnostics.erl | 2 +- apps/els_lsp/src/els_lsp.app.src | 3 ++- apps/els_lsp/src/els_sheldon_diagnostics.erl | 13 ++++++------- elvis.config | 1 - rebar.config | 2 +- rebar.lock | 6 +++--- 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/apps/els_lsp/src/els_diagnostics.erl b/apps/els_lsp/src/els_diagnostics.erl index 4c7b5fdeb..eb4d32f11 100644 --- a/apps/els_lsp/src/els_diagnostics.erl +++ b/apps/els_lsp/src/els_diagnostics.erl @@ -154,7 +154,7 @@ valid(Ids0) -> extra([]) -> ok; extra([<<"sheldon">>|_]) -> - {ok, _} = application:ensure_all_started(rebar3_sheldon), + {ok, _} = application:ensure_all_started(sheldon), ok; extra([_|T]) -> extra(T). diff --git a/apps/els_lsp/src/els_lsp.app.src b/apps/els_lsp/src/els_lsp.app.src index 5e62a74dd..bf9c720c2 100644 --- a/apps/els_lsp/src/els_lsp.app.src +++ b/apps/els_lsp/src/els_lsp.app.src @@ -15,7 +15,8 @@ getopt, erlfmt, els_core, - gradualizer + gradualizer, + rebar3_sheldon ]}, {env, []}, {modules, []}, diff --git a/apps/els_lsp/src/els_sheldon_diagnostics.erl b/apps/els_lsp/src/els_sheldon_diagnostics.erl index 3e0639433..af8422796 100644 --- a/apps/els_lsp/src/els_sheldon_diagnostics.erl +++ b/apps/els_lsp/src/els_sheldon_diagnostics.erl @@ -41,8 +41,7 @@ run(Uri) -> RelFile -> try RegEx = "[_@./#&+-=*]", - Mod = rebar3_sheldon_ast, - Mod:spellcheck([RelFile], RegEx) + rebar3_sheldon_ast:spellcheck([RelFile], RegEx) of [] -> []; Problems -> format_diagnostics(Problems) @@ -70,9 +69,9 @@ format_rules([]) -> []; format_rules([#{reason := #{misspelled_words := Miss}} = Data | EItems]) -> ItemDiags = format_item(Miss, Data), - [lists:flatten(ItemDiags) | format_rules(EItems)]. + [ItemDiags | format_rules(EItems)]. --spec format_item([any()], map()) -> [[map()]]. +-spec format_item([map()], map()) -> [map()]. format_item([#{candidates := [], word := Word} | Items], Data) -> #{line := Line, type := Type} = Data, Msg = format_text("The word ~p in ~p is unknown.", [Word, Type]), @@ -88,17 +87,17 @@ format_item([#{candidates := Candidates, word := Word} | Items], Data) -> format_item([], _) -> []. --spec diagnostic( any(), integer(), els_diagnostics:severity()) -> [map()]. +-spec diagnostic( any(), integer(), els_diagnostics:severity()) -> map(). diagnostic(Msg, Ln, Severity) -> Range = els_protocol:range(#{from => {Ln, 1}, to => {Ln + 1, 1}}), Message = els_utils:to_binary(Msg), - [#{ range => Range + #{ range => Range , severity => Severity , code => spellcheck , source => source() , message => Message , relatedInformation => [] - }]. + }. -spec format_sheldon_candidates([any()], [[[any()] | char()]]) -> list(). format_sheldon_candidates([], Acc) -> diff --git a/elvis.config b/elvis.config index 6c2b1c8c5..b7b1f3ffc 100644 --- a/elvis.config +++ b/elvis.config @@ -34,7 +34,6 @@ , els_tcp , els_dap_test_utils , els_test_utils - , els_sheldon_diagnostics ]}} , {elvis_text_style, line_length, #{limit => 80, skip_comments => false}} , {elvis_style, operator_spaces, #{ rules => [ {right, ","} diff --git a/rebar.config b/rebar.config index 657935e45..363d3b5bb 100644 --- a/rebar.config +++ b/rebar.config @@ -17,7 +17,7 @@ , {tdiff, "0.1.2"} , {uuid, "2.0.1", {pkg, uuid_erl}} , {gradualizer, {git, "https://github.com/josefs/Gradualizer.git", {ref, "e93db1c"}}} - , {rebar3_sheldon, "0.4.1"} + , {rebar3_sheldon, "0.4.2"} ] }. diff --git a/rebar.lock b/rebar.lock index 07c9b0b9e..2db3ef0a8 100644 --- a/rebar.lock +++ b/rebar.lock @@ -14,7 +14,7 @@ {<<"providers">>,{pkg,<<"providers">>,<<"1.8.1">>},1}, {<<"quickrand">>,{pkg,<<"quickrand">>,<<"2.0.1">>},1}, {<<"rebar3_format">>,{pkg,<<"rebar3_format">>,<<"0.8.2">>},0}, - {<<"rebar3_sheldon">>,{pkg,<<"rebar3_sheldon">>,<<"0.4.1">>},0}, + {<<"rebar3_sheldon">>,{pkg,<<"rebar3_sheldon">>,<<"0.4.2">>},0}, {<<"redbug">>,{pkg,<<"redbug">>,<<"2.0.6">>},0}, {<<"sheldon">>,{pkg,<<"sheldon">>,<<"0.4.1">>},1}, {<<"tdiff">>,{pkg,<<"tdiff">>,<<"0.1.2">>},0}, @@ -35,7 +35,7 @@ {<<"providers">>, <<"70B4197869514344A8A60E2B2A4EF41CA03DEF43CFB1712ECF076A0F3C62F083">>}, {<<"quickrand">>, <<"6D861FA11E6EB51BB2343A2616EFF704C2681A9997F41ABC78E58FA76DA33981">>}, {<<"rebar3_format">>, <<"2D64DA61E0B87FCA6C4512ADA6D9CBC2B27ADC9AE6844178561147E7121761BD">>}, - {<<"rebar3_sheldon">>, <<"E2F4535929A25A7F8CFCCFC23E3CF93839BCC7F83C0BFFBBDB3446210D8014D4">>}, + {<<"rebar3_sheldon">>, <<"DC69F6A5BA5B7AD8A547F656DF25DFE41E030DF2787467F5433A3210AE7FDB0C">>}, {<<"redbug">>, <<"A764690B012B67C404562F9C6E1BA47A73892EE17DF5C15F670B1A5BF9D2F25A">>}, {<<"sheldon">>, <<"1413143F9D96D30C6A18DD6746B5183F048B23AC345FF3BB92B399A5A69EBE93">>}, {<<"tdiff">>, <<"4E1B30321F1B3D600DF65CD60858EDE1235FE4E5EE042110AB5AD90CD6464AC5">>}, @@ -55,7 +55,7 @@ {<<"providers">>, <<"E45745ADE9C476A9A469EA0840E418AB19360DC44F01A233304E118A44486BA0">>}, {<<"quickrand">>, <<"14DB67D4AEF6B8815810EC9F3CCEF5E324B73B56CAE3687F99D752B85BDD4C96">>}, {<<"rebar3_format">>, <<"CA8FF27638C2169593D1449DACBE8895634193ED3334E906B54FC97F081F5213">>}, - {<<"rebar3_sheldon">>, <<"79DAA99B7B58F590B9DBD2641B0C0E0F116D79E587779E861D4246B1D7CD5737">>}, + {<<"rebar3_sheldon">>, <<"19120875183E6EE7C11EC21FC99B12347A37F59386DB7A4759DBBA55EA621D4C">>}, {<<"redbug">>, <<"AAD9498671F4AB91EACA5099FE85A61618158A636E6286892C4F7CF4AF171D04">>}, {<<"sheldon">>, <<"15E24EDDCDB42FE07AA7913DA770DBCE4EE052A37AA76E467748D4C977F463C9">>}, {<<"tdiff">>, <<"E0C2E168F99252A5889768D5C8F1E6510A184592D4CFA06B22778A18D33D7875">>}, From 652bc5830d640309aacfa44a723f7043956c1e02 Mon Sep 17 00:00:00 2001 From: vk Date: Thu, 2 Dec 2021 16:24:14 +0200 Subject: [PATCH 3/4] Add init callback to diagnostics behavior --- apps/els_lsp/src/els_diagnostics.erl | 24 ++++++++++---------- apps/els_lsp/src/els_sheldon_diagnostics.erl | 19 ++++++++++++---- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/apps/els_lsp/src/els_diagnostics.erl b/apps/els_lsp/src/els_diagnostics.erl index eb4d32f11..58bd3043f 100644 --- a/apps/els_lsp/src/els_diagnostics.erl +++ b/apps/els_lsp/src/els_diagnostics.erl @@ -39,7 +39,8 @@ -callback run(uri()) -> [diagnostic()]. -callback source() -> binary(). -callback on_complete(uri(), [diagnostic()]) -> ok. --optional_callbacks([ on_complete/2 ]). +-callback init() -> ok. +-optional_callbacks([ on_complete/2, init/0 ]). %%============================================================================== %% API @@ -79,9 +80,7 @@ enabled_diagnostics() -> Default = default_diagnostics(), Enabled = maps:get("enabled", Config, []), Disabled = maps:get("disabled", Config, []), - Diagnostics = lists:usort((Default ++ valid(Enabled)) -- valid(Disabled)), - ok = extra(Diagnostics), - Diagnostics. + lists:usort((Default ++ valid(Enabled)) -- valid(Disabled)). -spec make_diagnostic(range(), binary(), severity(), binary()) -> diagnostic(). make_diagnostic(Range, Message, Severity, Source) -> @@ -119,6 +118,7 @@ run_diagnostic(Uri, Id) -> els_diagnostics_provider:notify(Diagnostics, self()) end }, + ok = init_diagnostic(CbModule), {ok, Pid} = els_background_job:new(Config), Pid. @@ -150,11 +150,11 @@ valid(Ids0) -> end, Valid. --spec extra(list()) -> ok. -extra([]) -> - ok; -extra([<<"sheldon">>|_]) -> - {ok, _} = application:ensure_all_started(sheldon), - ok; -extra([_|T]) -> - extra(T). +-spec init_diagnostic(atom()) -> ok. +init_diagnostic(CbModule) -> + case erlang:function_exported(CbModule, init, 0) of + true -> + CbModule:init(); + false -> + ok + end. diff --git a/apps/els_lsp/src/els_sheldon_diagnostics.erl b/apps/els_lsp/src/els_sheldon_diagnostics.erl index af8422796..84230fa2b 100644 --- a/apps/els_lsp/src/els_sheldon_diagnostics.erl +++ b/apps/els_lsp/src/els_sheldon_diagnostics.erl @@ -1,5 +1,5 @@ %%============================================================================== -%% Compiler diagnostics +%% Sheldon diagnostics %%============================================================================== -module(els_sheldon_diagnostics). @@ -14,7 +14,8 @@ %% Exports %%============================================================================== --export([ is_default/0 +-export([ init/0 + , is_default/0 , run/1 , source/0 ]). @@ -30,6 +31,14 @@ %% Callback Functions %%============================================================================== +-spec init() -> ok. +init() -> + %% By default "sheldon" is not started by reason that he spend few seconds + %% to prepare and load dictionary. The "sheldon" shoulld be load only once + %% when diagnostic is enabled. + application:ensure_all_started(sheldon), + ok. + -spec is_default() -> boolean(). is_default() -> false. @@ -45,8 +54,10 @@ run(Uri) -> of [] -> []; Problems -> format_diagnostics(Problems) - catch _:Err -> - ?LOG_WARNING("Sheldon error.[Err=~p] ", [Err]), + catch Type:Error:Stacktrace -> + ?LOG_WARNING( "Sheldon error: [type=~p] [error=~p] [stacktrace=~p]" + , [Type, Error, Stacktrace] + ), [] end end. From cbf5319b3b252157de599e97b3a4ad56d6c692c9 Mon Sep 17 00:00:00 2001 From: vk Date: Fri, 10 Dec 2021 21:03:06 +0200 Subject: [PATCH 4/4] Move init diagnostics into init of els_diagnostics_provider --- apps/els_lsp/src/els_diagnostics.erl | 23 ++++-- apps/els_lsp/src/els_diagnostics_provider.erl | 1 + apps/els_lsp/test/els_diagnostics_SUITE.erl | 80 ++++++++++--------- 3 files changed, 63 insertions(+), 41 deletions(-) diff --git a/apps/els_lsp/src/els_diagnostics.erl b/apps/els_lsp/src/els_diagnostics.erl index 58bd3043f..d028b737d 100644 --- a/apps/els_lsp/src/els_diagnostics.erl +++ b/apps/els_lsp/src/els_diagnostics.erl @@ -45,7 +45,8 @@ %%============================================================================== %% API %%============================================================================== --export([ available_diagnostics/0 +-export([ init/0 + , available_diagnostics/0 , default_diagnostics/0 , enabled_diagnostics/0 , make_diagnostic/4 @@ -56,6 +57,15 @@ %% API %%============================================================================== +-spec init() -> ok. +init() -> + case els_config:get(diagnostics) of + undefined -> + ok; + _ -> + init_diagnostics(enabled_diagnostics()) + end. + -spec available_diagnostics() -> [diagnostic_id()]. available_diagnostics() -> [ <<"bound_var_in_pattern">> @@ -118,7 +128,6 @@ run_diagnostic(Uri, Id) -> els_diagnostics_provider:notify(Diagnostics, self()) end }, - ok = init_diagnostic(CbModule), {ok, Pid} = els_background_job:new(Config), Pid. @@ -150,11 +159,15 @@ valid(Ids0) -> end, Valid. --spec init_diagnostic(atom()) -> ok. -init_diagnostic(CbModule) -> +-spec init_diagnostics([binary()]) -> ok. +init_diagnostics([]) -> + ok; +init_diagnostics([Id|T]) -> + CbModule = cb_module(Id), case erlang:function_exported(CbModule, init, 0) of true -> CbModule:init(); false -> ok - end. + end, + init_diagnostics(T). diff --git a/apps/els_lsp/src/els_diagnostics_provider.erl b/apps/els_lsp/src/els_diagnostics_provider.erl index 240d9556c..c185d5e90 100644 --- a/apps/els_lsp/src/els_diagnostics_provider.erl +++ b/apps/els_lsp/src/els_diagnostics_provider.erl @@ -42,6 +42,7 @@ options() -> -spec init() -> state(). init() -> + ok = els_diagnostics:init(), #{ in_progress => [] }. %% LSP 3.15 introduce versioning for diagnostics. Until all clients diff --git a/apps/els_lsp/test/els_diagnostics_SUITE.erl b/apps/els_lsp/test/els_diagnostics_SUITE.erl index 2642fb926..e57b1b9d4 100644 --- a/apps/els_lsp/test/els_diagnostics_SUITE.erl +++ b/apps/els_lsp/test/els_diagnostics_SUITE.erl @@ -125,10 +125,23 @@ init_per_testcase(TestCase, Config) when TestCase =:= gradualizer -> els_mock_diagnostics:setup(), els_test_utils:init_per_testcase(TestCase, Config); init_per_testcase(TestCase, Config) when TestCase =:= sheldon -> - meck:new(els_sheldon_diagnostics, [passthrough, no_link]), - meck:expect(els_sheldon_diagnostics, is_default, 0, true), - els_mock_diagnostics:setup(), - els_test_utils:init_per_testcase(TestCase, Config); + case list_to_integer(erlang:system_info(otp_release)) >= 23 of + true -> + meck:new(els_sheldon_diagnostics, [passthrough, no_link]), + meck:expect(els_sheldon_diagnostics, is_default, 0, true), + els_mock_diagnostics:setup(), + meck:expect( els_diagnostics_provider + , init + , fun() -> + DiagnosticsConfig = #{"enabled" => [<<"sheldon">>]}, + els_config:set(diagnostics, DiagnosticsConfig), + meck:passthrough([]) + end + ), + els_test_utils:init_per_testcase(TestCase, Config); + false -> + {skip, "Sheldon diagnostics should run on OTP23+"} + end; init_per_testcase(TestCase, Config) -> els_mock_diagnostics:setup(), els_test_utils:init_per_testcase(TestCase, Config). @@ -667,38 +680,33 @@ gradualizer(_Config) -> -spec sheldon(config()) -> ok. sheldon(_Config) -> - case list_to_integer(erlang:system_info(otp_release)) >= 23 of - true -> - {ok, Cwd} = file:get_cwd(), - RootPath = els_test_utils:root_path(), - try - file:set_cwd(RootPath), - Path = src_path("diagnostics_sheldon.erl"), - Source = <<"Sheldon">>, - Errors = [], - Warnings = [ #{ code => spellcheck - , message => <<"The word \"sheldon\" in " - "comment is unknown. " - "Maybe you wanted to use \"Sheldon\"?">> - , range => {{2, 0}, {3, 0}} - , relatedInformation => [] - } - , #{ code => spellcheck - , message => <<"The word \"somestrange\" in comment is " - "unknown.">> - , range => {{0, 0}, {1, 0}} - , relatedInformation => [] - } - ], - Hints = [], - els_test:run_diagnostics_test(Path, Source, Errors, Warnings, Hints) - catch _Err -> - file:set_cwd(Cwd) - end, - ok; - false -> - {skipped, "Sheldon diagnostics should run on OTP23+"} - end. + {ok, Cwd} = file:get_cwd(), + RootPath = els_test_utils:root_path(), + try + file:set_cwd(RootPath), + Path = src_path("diagnostics_sheldon.erl"), + Source = <<"Sheldon">>, + Errors = [], + Warnings = [ #{ code => spellcheck + , message => <<"The word \"sheldon\" in " + "comment is unknown. " + "Maybe you wanted to use \"Sheldon\"?">> + , range => {{2, 0}, {3, 0}} + , relatedInformation => [] + } + , #{ code => spellcheck + , message => <<"The word \"somestrange\" in comment is " + "unknown.">> + , range => {{0, 0}, {1, 0}} + , relatedInformation => [] + } + ], + Hints = [], + els_test:run_diagnostics_test(Path, Source, Errors, Warnings, Hints) + catch _Err -> + file:set_cwd(Cwd) + end, + ok. %%============================================================================== %% Internal Functions