From 61a901d28eef1b1bb10b6395856ec355eca1dcb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Sun, 6 Oct 2024 19:06:06 +0200 Subject: [PATCH 01/29] add new rule: no_init_lists --- src/elvis_rulesets.erl | 1 + src/elvis_style.erl | 36 ++++++++++++++++++++- test/examples/fail_verify_no_init_lists.erl | 9 ++++++ test/examples/pass_verify_no_init_lists.erl | 9 ++++++ test/style_SUITE.erl | 14 +++++++- 5 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 test/examples/fail_verify_no_init_lists.erl create mode 100644 test/examples/pass_verify_no_init_lists.erl diff --git a/src/elvis_rulesets.erl b/src/elvis_rulesets.erl index 7d73ff20..1c9ca63e 100644 --- a/src/elvis_rulesets.erl +++ b/src/elvis_rulesets.erl @@ -93,6 +93,7 @@ rules(erl_files_strict) -> max_function_length, max_module_length, no_call, + no_init_lists, no_common_caveats_call, no_macros, state_record_and_type]]); diff --git a/src/elvis_style.erl b/src/elvis_style.erl index 14311707..919ff81b 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -12,7 +12,8 @@ atom_naming_convention/3, no_throw/3, no_dollar_space/3, no_author/3, no_import/3, no_catch_expressions/3, no_single_clause_case/3, numeric_format/3, behaviour_spelling/3, always_shortcircuit/3, consistent_generic_type/3, export_used_types/3, - no_match_in_condition/3, param_pattern_matching/3, private_data_types/3, option/3]). + no_match_in_condition/3, param_pattern_matching/3, private_data_types/3, option/3, + no_init_lists/3]). -export_type([empty_rule_config/0]). -export_type([ignorable/0]). @@ -30,6 +31,7 @@ no_match_in_condition_config/0, behaviour_spelling_config/0, param_pattern_matching_config/0, private_data_type_config/0]). +-define(NO_INIT_LISTS_MSG, "TODO"). -define(INVALID_MACRO_NAME_REGEX_MSG, "The macro named ~p on line ~p does not respect the format " "defined by the regular expression '~p'."). @@ -146,6 +148,8 @@ -spec default(Rule :: atom()) -> DefaultRuleConfig :: term(). default(macro_names) -> #{regex => "^([A-Z][A-Z_0-9]+)$"}; +default(no_init_lists) -> + #{}; default(operator_spaces) -> #{rules => [{right, "++"}, {left, "++"}, {right, "="}, {left, "="}, {right, "+"}, {left, "+"}, @@ -1015,6 +1019,36 @@ atom_naming_convention(Config, Target, RuleConfig) -> AtomNodes = elvis_code:find(fun is_atom_node/1, Root, #{traverse => all, mode => node}), check_atom_names(Regex, RegexEnclosed, AtomNodes, []). +-spec no_init_lists(elvis_config:config(), elvis_file:file(), empty_rule_config()) -> + [elvis_result:item()]. +no_init_lists(Config, Target, RuleConfig) -> + Root = get_root(Config, Target, RuleConfig), + + IsFunction = fun(Node) -> ktn_code:type(Node) == function end, + FunctionNodes = elvis_code:find(IsFunction, Root), + + PairFun = + fun(FunctionNode) -> + Name = ktn_code:attr(name, FunctionNode), + Location = ktn_code:attr(location, FunctionNode), + [Content] = ktn_code:content(FunctionNode), + Attributes = ktn_code:node_attr(pattern, Content), + {Name, Location, [Attr || #{type := Type} = Attr <- Attributes, Type == cons]} + end, + + FunListAttributeInfos = lists:map(PairFun, FunctionNodes), + + FilterFun = fun({Name, _, C}) -> length(C) > 0 andalso Name =:= init end, + FunListAttributes = lists:filter(FilterFun, FunListAttributeInfos), + + ResultFun = + fun({Name, Location, ConsList}) -> + Info = [Name, length(ConsList)], + Msg = ?NO_INIT_LISTS_MSG, + elvis_result:new(item, Msg, Info, Location) + end, + lists:map(ResultFun, FunListAttributes). + -spec no_throw(elvis_config:config(), elvis_file:file(), empty_rule_config()) -> [elvis_result:item()]. no_throw(Config, Target, RuleConfig) -> diff --git a/test/examples/fail_verify_no_init_lists.erl b/test/examples/fail_verify_no_init_lists.erl new file mode 100644 index 00000000..70f5431e --- /dev/null +++ b/test/examples/fail_verify_no_init_lists.erl @@ -0,0 +1,9 @@ +-module(fail_verify_no_init_lists). + +-export([start_link/1, init/1]). + +start_link(AParam) -> + gen_server:start_link(?MODULE, [AParam], []). + +init([_AParam]) -> + ok. diff --git a/test/examples/pass_verify_no_init_lists.erl b/test/examples/pass_verify_no_init_lists.erl new file mode 100644 index 00000000..23f846da --- /dev/null +++ b/test/examples/pass_verify_no_init_lists.erl @@ -0,0 +1,9 @@ +-module(pass_verify_no_init_lists). + +-export([start_link/0, init/1]). + +start_link() -> + gen_server:start_link(?MODULE, undefined, []). + +init(_) -> + ok. diff --git a/test/style_SUITE.erl b/test/style_SUITE.erl index c59f94e7..7fb35775 100644 --- a/test/style_SUITE.erl +++ b/test/style_SUITE.erl @@ -25,7 +25,7 @@ verify_always_shortcircuit/1, verify_consistent_generic_type/1, verify_no_types/1, verify_no_specs/1, verify_export_used_types/1, verify_consistent_variable_casing/1, verify_no_match_in_condition/1, verify_param_pattern_matching/1, - verify_private_data_types/1]). + verify_private_data_types/1, verify_no_init_lists/1]). %% -elvis attribute -export([verify_elvis_attr_atom_naming_convention/1, verify_elvis_attr_numeric_format/1, verify_elvis_attr_dont_repeat_yourself/1, verify_elvis_attr_function_naming_convention/1, @@ -1431,6 +1431,18 @@ verify_atom_naming_convention(Config) -> FailPath) end. +-spec verify_no_init_lists(config()) -> any(). +verify_no_init_lists(Config) -> + Ext = proplists:get_value(test_file_ext, Config, "erl"), + + FailPath = "fail_verify_no_init_lists." ++ Ext, + + [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath), + + PassPath = "pass_verify_no_init_lists." ++ Ext, + + [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath). + -spec verify_no_throw(config()) -> any(). verify_no_throw(Config) -> _Group = proplists:get_value(group, Config, erl_files), From 6e914c098f97370e84014d75852ee92ddcad6889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Sun, 6 Oct 2024 19:16:28 +0200 Subject: [PATCH 02/29] add to RULES.md --- RULES.md | 1 + doc_rules/elvis_style/no_init_lists.md | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 doc_rules/elvis_style/no_init_lists.md diff --git a/RULES.md b/RULES.md index da5561e7..3fa5e5ea 100644 --- a/RULES.md +++ b/RULES.md @@ -61,6 +61,7 @@ identified with `(since ...)` for convenience purposes. - [State Record and Type](doc_rules/elvis_style/state_record_and_type.md) - [Used Ignored Variable](doc_rules/elvis_style/used_ignored_variable.md) - [Variable Naming Convention](doc_rules/elvis_style/variable_naming_convention.md) +- [Not Use List In Init Functions](doc_rules/elvis_style/no_init_lists.md) ## Project rules diff --git a/doc_rules/elvis_style/no_init_lists.md b/doc_rules/elvis_style/no_init_lists.md new file mode 100644 index 00000000..0aaa0e14 --- /dev/null +++ b/doc_rules/elvis_style/no_init_lists.md @@ -0,0 +1,17 @@ +# No Init Lists + +This warns you if you use list as a parameter in an init function in a gen_* module. +[Reasoning](https://erlangforums.com/t/args-in-gen-init-1/3169/4?u=elbrujohalcon) + +> Works on `.beam` file? Not really! (it consumes results Ok, but these might be unexpected, since +the files are pre-processed) + +## Options + +- + +## Example + +```erlang +{elvis_style, no_init_lists} +``` From e471724cfa23f3b097f42303b8d69c438df23414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Mon, 7 Oct 2024 17:41:48 +0200 Subject: [PATCH 03/29] fix rule settings, and message --- src/elvis_style.erl | 18 ++++++++++-------- test/style_SUITE.erl | 7 ++++++- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/elvis_style.erl b/src/elvis_style.erl index 919ff81b..85e7f567 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -31,7 +31,10 @@ no_match_in_condition_config/0, behaviour_spelling_config/0, param_pattern_matching_config/0, private_data_type_config/0]). --define(NO_INIT_LISTS_MSG, "TODO"). +-hank([{unnecessary_function_arguments, [{no_init_lists, 3}]}]). + +-define(NO_INIT_LISTS_MSG, + "Don't use a list as a parameter in 'init' function at position ~p."). -define(INVALID_MACRO_NAME_REGEX_MSG, "The macro named ~p on line ~p does not respect the format " "defined by the regular expression '~p'."). @@ -148,8 +151,6 @@ -spec default(Rule :: atom()) -> DefaultRuleConfig :: term(). default(macro_names) -> #{regex => "^([A-Z][A-Z_0-9]+)$"}; -default(no_init_lists) -> - #{}; default(operator_spaces) -> #{rules => [{right, "++"}, {left, "++"}, {right, "="}, {left, "="}, {right, "+"}, {left, "+"}, @@ -237,7 +238,8 @@ default(RuleWithEmptyDefault) RuleWithEmptyDefault == always_shortcircuit; RuleWithEmptyDefault == no_space_after_pound; RuleWithEmptyDefault == export_used_types; - RuleWithEmptyDefault == consistent_variable_casing -> + RuleWithEmptyDefault == consistent_variable_casing; + RuleWithEmptyDefault == no_init_lists -> #{}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1021,8 +1023,8 @@ atom_naming_convention(Config, Target, RuleConfig) -> -spec no_init_lists(elvis_config:config(), elvis_file:file(), empty_rule_config()) -> [elvis_result:item()]. -no_init_lists(Config, Target, RuleConfig) -> - Root = get_root(Config, Target, RuleConfig), +no_init_lists(_Config, Target, _RuleConfig) -> + Root = get_root(#{}, Target, #{}), IsFunction = fun(Node) -> ktn_code:type(Node) == function end, FunctionNodes = elvis_code:find(IsFunction, Root), @@ -1042,8 +1044,8 @@ no_init_lists(Config, Target, RuleConfig) -> FunListAttributes = lists:filter(FilterFun, FunListAttributeInfos), ResultFun = - fun({Name, Location, ConsList}) -> - Info = [Name, length(ConsList)], + fun({_, Location, _}) -> + Info = [Location], Msg = ?NO_INIT_LISTS_MSG, elvis_result:new(item, Msg, Info, Location) end, diff --git a/test/style_SUITE.erl b/test/style_SUITE.erl index 7fb35775..ebf67d7b 100644 --- a/test/style_SUITE.erl +++ b/test/style_SUITE.erl @@ -1437,7 +1437,12 @@ verify_no_init_lists(Config) -> FailPath = "fail_verify_no_init_lists." ++ Ext, - [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath), + [#{message := M, info := I}] = + elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath), + + io:format(user, "-------------------~n", []), + io:format(user, M, I), + io:format(user, "-------------------~n", []), PassPath = "pass_verify_no_init_lists." ++ Ext, From f8dec952edba66ba21d01181ec8743d99c89bf8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Mon, 7 Oct 2024 17:42:33 +0200 Subject: [PATCH 04/29] delete print --- test/style_SUITE.erl | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/style_SUITE.erl b/test/style_SUITE.erl index ebf67d7b..fa965a21 100644 --- a/test/style_SUITE.erl +++ b/test/style_SUITE.erl @@ -1437,13 +1437,9 @@ verify_no_init_lists(Config) -> FailPath = "fail_verify_no_init_lists." ++ Ext, - [#{message := M, info := I}] = + [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath), - io:format(user, "-------------------~n", []), - io:format(user, M, I), - io:format(user, "-------------------~n", []), - PassPath = "pass_verify_no_init_lists." ++ Ext, [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath). From 6164e12ddaaf16c0b6bd15643047619259a29934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Mon, 7 Oct 2024 17:51:43 +0200 Subject: [PATCH 05/29] fix formatting --- test/style_SUITE.erl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/style_SUITE.erl b/test/style_SUITE.erl index e2c09b98..5808964f 100644 --- a/test/style_SUITE.erl +++ b/test/style_SUITE.erl @@ -26,7 +26,6 @@ verify_no_specs/1, verify_export_used_types/1, verify_consistent_variable_casing/1, verify_no_match_in_condition/1, verify_param_pattern_matching/1, verify_private_data_types/1, verify_unquoted_atoms/1, verify_no_init_lists/1]). - %% -elvis attribute -export([verify_elvis_attr_atom_naming_convention/1, verify_elvis_attr_numeric_format/1, verify_elvis_attr_dont_repeat_yourself/1, verify_elvis_attr_function_naming_convention/1, @@ -1455,8 +1454,7 @@ verify_no_init_lists(Config) -> FailPath = "fail_verify_no_init_lists." ++ Ext, - [_] = - elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath), + [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath), PassPath = "pass_verify_no_init_lists." ++ Ext, From 2d64012932da6cdf7503e90b9c9683bffcb4365b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Mon, 7 Oct 2024 17:54:56 +0200 Subject: [PATCH 06/29] fix deleted section --- RULES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/RULES.md b/RULES.md index 7221b5d0..6c77801d 100644 --- a/RULES.md +++ b/RULES.md @@ -64,6 +64,11 @@ identified with `(since ...)` for convenience purposes. - [Not Use List In Init Functions](doc_rules/elvis_style/no_init_lists.md) - [Prefer Unquoted Atoms](doc_rules/elvis_text_style/prefer_unquoted_atoms.md) +## `.gitignore` rules + +- [`.gitignore` required patterns](doc_rules/elvis_gitignore/required_patterns.md) +- [`.gitignore` forbidden patterns](doc_rules/elvis_gitignore/forbidden_patterns.md) + ## Project rules - [No deps master erlang.mk - *deprecated*](doc_rules/elvis_project/no_deps_master_erlang_mk.md) From fffeed6027de055cd3b63a741db6da21d574da0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Mon, 7 Oct 2024 17:56:41 +0200 Subject: [PATCH 07/29] fix rule markdown --- doc_rules/elvis_style/no_init_lists.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc_rules/elvis_style/no_init_lists.md b/doc_rules/elvis_style/no_init_lists.md index 0aaa0e14..3a98134f 100644 --- a/doc_rules/elvis_style/no_init_lists.md +++ b/doc_rules/elvis_style/no_init_lists.md @@ -8,10 +8,10 @@ the files are pre-processed) ## Options -- +- None. ## Example ```erlang -{elvis_style, no_init_lists} +{elvis_style, no_init_lists, #{}} ``` From b517a0091c3027ec6dbffe38ae50509de29b4970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Mon, 7 Oct 2024 18:00:06 +0200 Subject: [PATCH 08/29] fix rule markdown2 --- doc_rules/elvis_style/no_init_lists.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc_rules/elvis_style/no_init_lists.md b/doc_rules/elvis_style/no_init_lists.md index 3a98134f..bb9218b3 100644 --- a/doc_rules/elvis_style/no_init_lists.md +++ b/doc_rules/elvis_style/no_init_lists.md @@ -1,4 +1,4 @@ -# No Init Lists +# No Init Lists This warns you if you use list as a parameter in an init function in a gen_* module. [Reasoning](https://erlangforums.com/t/args-in-gen-init-1/3169/4?u=elbrujohalcon) From 7972ccbea8b3e63b310292b9ae09a568aa6cadf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=B3r=20Mil=C3=A1n?= <71042542+bormilan@users.noreply.github.com> Date: Thu, 10 Oct 2024 14:44:18 +0200 Subject: [PATCH 09/29] Update RULES.md Co-authored-by: Brujo Benavides --- RULES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RULES.md b/RULES.md index 6c77801d..98cfdc28 100644 --- a/RULES.md +++ b/RULES.md @@ -61,7 +61,7 @@ identified with `(since ...)` for convenience purposes. - [State Record and Type](doc_rules/elvis_style/state_record_and_type.md) - [Used Ignored Variable](doc_rules/elvis_style/used_ignored_variable.md) - [Variable Naming Convention](doc_rules/elvis_style/variable_naming_convention.md) -- [Not Use List In Init Functions](doc_rules/elvis_style/no_init_lists.md) +- [No Init Lists](doc_rules/elvis_style/no_init_lists.md) - [Prefer Unquoted Atoms](doc_rules/elvis_text_style/prefer_unquoted_atoms.md) ## `.gitignore` rules From 6348711663357c81a9ed69f4e21a5ca43600f1d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=B3r=20Mil=C3=A1n?= <71042542+bormilan@users.noreply.github.com> Date: Thu, 10 Oct 2024 14:44:34 +0200 Subject: [PATCH 10/29] Update doc_rules/elvis_style/no_init_lists.md Co-authored-by: Brujo Benavides --- doc_rules/elvis_style/no_init_lists.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc_rules/elvis_style/no_init_lists.md b/doc_rules/elvis_style/no_init_lists.md index bb9218b3..26e54a11 100644 --- a/doc_rules/elvis_style/no_init_lists.md +++ b/doc_rules/elvis_style/no_init_lists.md @@ -3,8 +3,7 @@ This warns you if you use list as a parameter in an init function in a gen_* module. [Reasoning](https://erlangforums.com/t/args-in-gen-init-1/3169/4?u=elbrujohalcon) -> Works on `.beam` file? Not really! (it consumes results Ok, but these might be unexpected, since -the files are pre-processed) +> Works on `.beam` files? Yes! ## Options From 68c8945d260b423609516b4d8389ec39dfabc4fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=B3r=20Mil=C3=A1n?= <71042542+bormilan@users.noreply.github.com> Date: Thu, 10 Oct 2024 14:44:50 +0200 Subject: [PATCH 11/29] Update src/elvis_style.erl Co-authored-by: Brujo Benavides --- src/elvis_style.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/elvis_style.erl b/src/elvis_style.erl index 1c74d8f3..914c1262 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -34,7 +34,7 @@ -hank([{unnecessary_function_arguments, [{no_init_lists, 3}]}]). -define(NO_INIT_LISTS_MSG, - "Don't use a list as a parameter in 'init' function at position ~p."). + "Do not use a list as the parameter for the 'init' callback at position ~p."). -define(INVALID_MACRO_NAME_REGEX_MSG, "The macro named ~p on line ~p does not respect the format " "defined by the regular expression '~p'."). From 70874c31e89c37bb808764225a39183726eb417f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Thu, 10 Oct 2024 14:49:41 +0200 Subject: [PATCH 12/29] fix description and link of no_init_lists rule --- doc_rules/elvis_style/no_init_lists.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc_rules/elvis_style/no_init_lists.md b/doc_rules/elvis_style/no_init_lists.md index bb9218b3..026adac6 100644 --- a/doc_rules/elvis_style/no_init_lists.md +++ b/doc_rules/elvis_style/no_init_lists.md @@ -1,7 +1,6 @@ # No Init Lists -This warns you if you use list as a parameter in an init function in a gen_* module. -[Reasoning](https://erlangforums.com/t/args-in-gen-init-1/3169/4?u=elbrujohalcon) +Do not use a list as the parameter for the `init/1` callback when implementing `gen_*` behaviours. It's semantically clearer to use a tuple or a map. [More info](https://erlangforums.com/t/args-in-gen-init-1/3169/5) > Works on `.beam` file? Not really! (it consumes results Ok, but these might be unexpected, since the files are pre-processed) From 299ed09b7f96ce562a701997d2ee84e75c5c5719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Thu, 10 Oct 2024 14:54:10 +0200 Subject: [PATCH 13/29] fix markdown --- doc_rules/elvis_style/no_init_lists.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc_rules/elvis_style/no_init_lists.md b/doc_rules/elvis_style/no_init_lists.md index 1ff6d7da..d22f0089 100644 --- a/doc_rules/elvis_style/no_init_lists.md +++ b/doc_rules/elvis_style/no_init_lists.md @@ -1,6 +1,8 @@ # No Init Lists -Do not use a list as the parameter for the `init/1` callback when implementing `gen_*` behaviours. It's semantically clearer to use a tuple or a map. [More info](https://erlangforums.com/t/args-in-gen-init-1/3169/5) +Do not use a list as the parameter for the `init/1` callback when implementing `gen_*` behaviours. +It's semantically clearer to use a tuple or a map. +[More info](https://erlangforums.com/t/args-in-gen-init-1/3169/5) > Works on `.beam` files? Yes! From 0653f03b27550cc9d3a9ad387f5a5ccee9c56a84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Fri, 11 Oct 2024 07:26:22 +0200 Subject: [PATCH 14/29] little fixes and change logic --- src/elvis_style.erl | 49 +++++++------------ test/examples/fail_no_init_lists.erl | 15 ++++++ test/examples/pass_no_init_lists.erl | 15 ++++++ ...init_lists.erl => pass_no_init_lists2.erl} | 5 +- test/examples/pass_no_init_lists3.erl | 17 +++++++ test/examples/pass_verify_no_init_lists.erl | 9 ---- test/style_SUITE.erl | 14 ++++-- 7 files changed, 78 insertions(+), 46 deletions(-) create mode 100644 test/examples/fail_no_init_lists.erl create mode 100644 test/examples/pass_no_init_lists.erl rename test/examples/{fail_verify_no_init_lists.erl => pass_no_init_lists2.erl} (63%) create mode 100644 test/examples/pass_no_init_lists3.erl delete mode 100644 test/examples/pass_verify_no_init_lists.erl diff --git a/src/elvis_style.erl b/src/elvis_style.erl index 914c1262..732ae991 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -1,5 +1,7 @@ -module(elvis_style). +-feature(maybe_expr, enable). + -export([default/1, function_naming_convention/3, variable_naming_convention/3, consistent_variable_casing/3, macro_names/3, macro_module_names/3, no_macros/3, no_specs/3, no_types/3, no_block_expressions/3, operator_spaces/3, no_space/3, @@ -31,10 +33,8 @@ no_match_in_condition_config/0, behaviour_spelling_config/0, param_pattern_matching_config/0, private_data_type_config/0]). --hank([{unnecessary_function_arguments, [{no_init_lists, 3}]}]). - --define(NO_INIT_LISTS_MSG, - "Do not use a list as the parameter for the 'init' callback at position ~p."). +% -define(NO_INIT_LISTS_MSG, +% "Do not use a list as the parameter for the 'init' callback at position ~p."). -define(INVALID_MACRO_NAME_REGEX_MSG, "The macro named ~p on line ~p does not respect the format " "defined by the regular expression '~p'."). @@ -149,6 +149,8 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -spec default(Rule :: atom()) -> DefaultRuleConfig :: term(). +default(no_init_lists) -> + #{behaviours => [gen_server, gen_statem]}; default(macro_names) -> #{regex => "^[A-Z](_?[A-Z0-9]+)*$"}; default(operator_spaces) -> @@ -252,8 +254,8 @@ default(RuleWithEmptyDefault) RuleWithEmptyDefault == always_shortcircuit; RuleWithEmptyDefault == no_space_after_pound; RuleWithEmptyDefault == export_used_types; - RuleWithEmptyDefault == consistent_variable_casing; - RuleWithEmptyDefault == no_init_lists -> + RuleWithEmptyDefault == consistent_variable_casing -> + % RuleWithEmptyDefault == no_init_lists -> #{}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1035,35 +1037,20 @@ atom_naming_convention(Config, Target, RuleConfig) -> AtomNodes = elvis_code:find(fun is_atom_node/1, Root, #{traverse => all, mode => node}), check_atom_names(Regex, RegexEnclosed, AtomNodes, []). --spec no_init_lists(elvis_config:config(), elvis_file:file(), empty_rule_config()) -> - [elvis_result:item()]. -no_init_lists(_Config, Target, _RuleConfig) -> - Root = get_root(#{}, Target, #{}), - - IsFunction = fun(Node) -> ktn_code:type(Node) == function end, - FunctionNodes = elvis_code:find(IsFunction, Root), +-type no_init_lists_config() :: #{behaviours => [atom()]}. - PairFun = - fun(FunctionNode) -> - Name = ktn_code:attr(name, FunctionNode), - Location = ktn_code:attr(location, FunctionNode), - [Content] = ktn_code:content(FunctionNode), - Attributes = ktn_code:node_attr(pattern, Content), - {Name, Location, [Attr || #{type := Type} = Attr <- Attributes, Type == cons]} - end, +-spec no_init_lists(elvis_config:config(), elvis_file:file(), no_init_lists_config()) -> + [elvis_result:item()]. +no_init_lists( Config , Target , RuleConfig ) -> Root = get_root( Config , Target , RuleConfig ) , Behaviors = option( behaviours , RuleConfig , no_init_lists ) , IsBehaviour = fun ( Node ) -> ktn_code : type( Node ) == behaviour end , FunListAttributes = maybe [ BehaviourNode ] ?= elvis_code : find( IsBehaviour , Root ) , true ?= lists : member( ktn_code : attr( value , BehaviourNode ) , Behaviors ) , IsFunction = fun ( Node ) -> ktn_code : type( Node ) == function end , FunctionNodes = elvis_code : find( IsFunction , Root ) , PairFun = fun ( FunctionNode ) -> Name = ktn_code : attr( name , FunctionNode ) , Location = ktn_code : attr( location , FunctionNode ) , [ Content ] = ktn_code : content( FunctionNode ) , Attributes = ktn_code : node_attr( pattern , Content ) , { Name , Location , [ Attr || #{ type := Type } = Attr <- Attributes , Type == cons ] } end , FunListAttributeInfos = lists : map( PairFun , FunctionNodes ) , FilterFun = fun ( { Name , _ , Args } ) -> length( Args ) =:= 1 andalso Name =:= init end , lists : filter( FilterFun , FunListAttributeInfos ) else _ -> [ ] end , ResultFun = fun ( { _ , Location , _ } ) -> Info = [ Location ] , Msg = "asd" , elvis_result : new( item , Msg , Info , Location ) end , lists : map( ResultFun , FunListAttributes ) . - FunListAttributeInfos = lists:map(PairFun, FunctionNodes), + % io:format(user, "-----~n", []), + % io:format(user, "~p~n", [ktn_code:attr(value, BehaviourNode)]), + % io:format(user, "~p~n", [lists:member(ktn_code:attr(value, BehaviourNode), Behaviors)]), + % io:format(user, "-----~n", []), - FilterFun = fun({Name, _, C}) -> length(C) > 0 andalso Name =:= init end, - FunListAttributes = lists:filter(FilterFun, FunListAttributeInfos), + % -- - ResultFun = - fun({_, Location, _}) -> - Info = [Location], - Msg = ?NO_INIT_LISTS_MSG, - elvis_result:new(item, Msg, Info, Location) - end, - lists:map(ResultFun, FunListAttributes). + % Msg = ?NO_INIT_LISTS_MSG, -spec no_throw(elvis_config:config(), elvis_file:file(), empty_rule_config()) -> [elvis_result:item()]. diff --git a/test/examples/fail_no_init_lists.erl b/test/examples/fail_no_init_lists.erl new file mode 100644 index 00000000..ce7d5170 --- /dev/null +++ b/test/examples/fail_no_init_lists.erl @@ -0,0 +1,15 @@ +-module(fail_no_init_lists). + +-behaviour(gen_server). + +-export([start_link/1, init/1, handle_cast/2, handle_call/3]). + +start_link(AParam) -> + gen_server:start_link(?MODULE, [AParam], []). + +init([_AParam]) -> + ok. + +handle_cast(_, _) -> ok. + +handle_call(_, _, _) -> ok. diff --git a/test/examples/pass_no_init_lists.erl b/test/examples/pass_no_init_lists.erl new file mode 100644 index 00000000..8513ff39 --- /dev/null +++ b/test/examples/pass_no_init_lists.erl @@ -0,0 +1,15 @@ +-module(pass_no_init_lists). + +-behaviour(gen_server). + +-export([start_link/0, init/1, handle_cast/2, handle_call/3]). + +start_link() -> + gen_server:start_link(?MODULE, undefined, []). + +init(_) -> + ok. + +handle_cast(_, _) -> ok. + +handle_call(_, _, _) -> ok. diff --git a/test/examples/fail_verify_no_init_lists.erl b/test/examples/pass_no_init_lists2.erl similarity index 63% rename from test/examples/fail_verify_no_init_lists.erl rename to test/examples/pass_no_init_lists2.erl index 70f5431e..4950249b 100644 --- a/test/examples/fail_verify_no_init_lists.erl +++ b/test/examples/pass_no_init_lists2.erl @@ -1,9 +1,8 @@ --module(fail_verify_no_init_lists). +-module(pass_no_init_lists2). -export([start_link/1, init/1]). start_link(AParam) -> gen_server:start_link(?MODULE, [AParam], []). -init([_AParam]) -> - ok. +init([_AParam]) -> ok. diff --git a/test/examples/pass_no_init_lists3.erl b/test/examples/pass_no_init_lists3.erl new file mode 100644 index 00000000..1851294f --- /dev/null +++ b/test/examples/pass_no_init_lists3.erl @@ -0,0 +1,17 @@ +-module(pass_no_init_lists3). + +-behaviour(gen_statem). + +-export([start_link/1, init/1, handle_cast/2, handle_call/3, callback_mode/0]). + +start_link(B) -> + gen_server:start_link(?MODULE, [B], []). + +init([_B]) -> + ok. + +handle_cast(_, _) -> ok. + +handle_call(_, _, _) -> ok. + +callback_mode() -> ok. diff --git a/test/examples/pass_verify_no_init_lists.erl b/test/examples/pass_verify_no_init_lists.erl deleted file mode 100644 index 23f846da..00000000 --- a/test/examples/pass_verify_no_init_lists.erl +++ /dev/null @@ -1,9 +0,0 @@ --module(pass_verify_no_init_lists). - --export([start_link/0, init/1]). - -start_link() -> - gen_server:start_link(?MODULE, undefined, []). - -init(_) -> - ok. diff --git a/test/style_SUITE.erl b/test/style_SUITE.erl index 5808964f..0a325b07 100644 --- a/test/style_SUITE.erl +++ b/test/style_SUITE.erl @@ -1452,13 +1452,21 @@ verify_atom_naming_convention(Config) -> verify_no_init_lists(Config) -> Ext = proplists:get_value(test_file_ext, Config, "erl"), - FailPath = "fail_verify_no_init_lists." ++ Ext, + FailPath = "fail_no_init_lists." ++ Ext, [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath), - PassPath = "pass_verify_no_init_lists." ++ Ext, + PassPath = "pass_no_init_lists." ++ Ext, - [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath). + [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath), + + PassPath2 = "pass_no_init_lists2." ++ Ext, + + [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath2), + + FailPath3 = "pass_no_init_lists3." ++ Ext, + + [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath3). -spec verify_no_throw(config()) -> any(). verify_no_throw(Config) -> From 6513368bd2ef44a90a7fab9d436c120e7a4101d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Tue, 15 Oct 2024 21:10:54 +0200 Subject: [PATCH 15/29] change maybe to case, refactor tests, and add to beam section too --- src/elvis_rulesets.erl | 1 + src/elvis_style.erl | 57 +++++++++++++++---- .../fail_no_init_lists.erl | 2 +- .../fail_no_init_lists2.erl | 15 +++++ .../fail_no_init_lists3.erl | 21 +++++++ .../pass_no_init_lists.erl | 8 ++- .../pass_no_init_lists2.erl | 18 ++++++ .../pass_no_init_lists3.erl | 18 ++++++ .../pass_no_init_lists4.erl} | 2 +- test/examples/pass_no_init_lists3.erl | 17 ------ test/style_SUITE.erl | 31 +++++----- 11 files changed, 145 insertions(+), 45 deletions(-) rename test/examples/{ => no_init_lists_examples}/fail_no_init_lists.erl (82%) create mode 100644 test/examples/no_init_lists_examples/fail_no_init_lists2.erl create mode 100644 test/examples/no_init_lists_examples/fail_no_init_lists3.erl rename test/examples/{ => no_init_lists_examples}/pass_no_init_lists.erl (80%) create mode 100644 test/examples/no_init_lists_examples/pass_no_init_lists2.erl create mode 100644 test/examples/no_init_lists_examples/pass_no_init_lists3.erl rename test/examples/{pass_no_init_lists2.erl => no_init_lists_examples/pass_no_init_lists4.erl} (81%) delete mode 100644 test/examples/pass_no_init_lists3.erl diff --git a/src/elvis_rulesets.erl b/src/elvis_rulesets.erl index 2241c266..9fa1a2cc 100644 --- a/src/elvis_rulesets.erl +++ b/src/elvis_rulesets.erl @@ -119,6 +119,7 @@ rules(beam_files) -> no_debug_call, no_if_expression, no_import, + no_init_lists, no_match_in_condition, no_nested_try_catch, no_single_clause_case, diff --git a/src/elvis_style.erl b/src/elvis_style.erl index 732ae991..8f2c42d7 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -255,7 +255,6 @@ default(RuleWithEmptyDefault) RuleWithEmptyDefault == no_space_after_pound; RuleWithEmptyDefault == export_used_types; RuleWithEmptyDefault == consistent_variable_casing -> - % RuleWithEmptyDefault == no_init_lists -> #{}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1041,16 +1040,54 @@ atom_naming_convention(Config, Target, RuleConfig) -> -spec no_init_lists(elvis_config:config(), elvis_file:file(), no_init_lists_config()) -> [elvis_result:item()]. -no_init_lists( Config , Target , RuleConfig ) -> Root = get_root( Config , Target , RuleConfig ) , Behaviors = option( behaviours , RuleConfig , no_init_lists ) , IsBehaviour = fun ( Node ) -> ktn_code : type( Node ) == behaviour end , FunListAttributes = maybe [ BehaviourNode ] ?= elvis_code : find( IsBehaviour , Root ) , true ?= lists : member( ktn_code : attr( value , BehaviourNode ) , Behaviors ) , IsFunction = fun ( Node ) -> ktn_code : type( Node ) == function end , FunctionNodes = elvis_code : find( IsFunction , Root ) , PairFun = fun ( FunctionNode ) -> Name = ktn_code : attr( name , FunctionNode ) , Location = ktn_code : attr( location , FunctionNode ) , [ Content ] = ktn_code : content( FunctionNode ) , Attributes = ktn_code : node_attr( pattern , Content ) , { Name , Location , [ Attr || #{ type := Type } = Attr <- Attributes , Type == cons ] } end , FunListAttributeInfos = lists : map( PairFun , FunctionNodes ) , FilterFun = fun ( { Name , _ , Args } ) -> length( Args ) =:= 1 andalso Name =:= init end , lists : filter( FilterFun , FunListAttributeInfos ) else _ -> [ ] end , ResultFun = fun ( { _ , Location , _ } ) -> Info = [ Location ] , Msg = "asd" , elvis_result : new( item , Msg , Info , Location ) end , lists : map( ResultFun , FunListAttributes ) . - - % io:format(user, "-----~n", []), - % io:format(user, "~p~n", [ktn_code:attr(value, BehaviourNode)]), - % io:format(user, "~p~n", [lists:member(ktn_code:attr(value, BehaviourNode), Behaviors)]), - % io:format(user, "-----~n", []), - - % -- +no_init_lists(Config, Target, RuleConfig) -> + Root = get_root(Config, Target, RuleConfig), + FunListAttributes = + case is_rule_behaviour(Root, RuleConfig) of + true -> + IsFunction = fun(Node) -> ktn_code:type(Node) == function end, + FunctionNodes = elvis_code:find(IsFunction, Root), + PairFun = + fun(FunctionNode) -> + Name = ktn_code:attr(name, FunctionNode), + Location = ktn_code:attr(location, FunctionNode), + [Content] = ktn_code:content(FunctionNode), + Attributes = ktn_code:node_attr(pattern, Content), + {Name, + Location, + [Attr || #{type := Type} = Attr <- Attributes, Type == cons]} + end, + FunListAttributeInfos = lists:map(PairFun, FunctionNodes), + FilterFun = fun({Name, _, Args}) -> length(Args) =:= 1 andalso Name =:= init end, + lists:filter(FilterFun, FunListAttributeInfos); + false -> + [] + end, - % Msg = ?NO_INIT_LISTS_MSG, + ResultFun = + fun({_, Location, _}) -> + Info = [Location], + Msg = "asd", + elvis_result:new(item, Msg, Info, Location) + end, + lists:map(ResultFun, FunListAttributes). + +is_rule_behaviour(Root, RuleConfig) -> + Behaviors = option(behaviours, RuleConfig, no_init_lists), + IsBehaviour = fun(Node) -> ktn_code:type(Node) == behaviour end, + case elvis_code:find(IsBehaviour, Root) of + [BehaviourNode] -> + case lists:member( + ktn_code:attr(value, BehaviourNode), Behaviors) + of + true -> + true; + false -> + false + end; + [] -> + false + end. -spec no_throw(elvis_config:config(), elvis_file:file(), empty_rule_config()) -> [elvis_result:item()]. diff --git a/test/examples/fail_no_init_lists.erl b/test/examples/no_init_lists_examples/fail_no_init_lists.erl similarity index 82% rename from test/examples/fail_no_init_lists.erl rename to test/examples/no_init_lists_examples/fail_no_init_lists.erl index ce7d5170..d08048ff 100644 --- a/test/examples/fail_no_init_lists.erl +++ b/test/examples/no_init_lists_examples/fail_no_init_lists.erl @@ -5,7 +5,7 @@ -export([start_link/1, init/1, handle_cast/2, handle_call/3]). start_link(AParam) -> - gen_server:start_link(?MODULE, [AParam], []). + gen_server:start_link(?MODULE, AParam, []). init([_AParam]) -> ok. diff --git a/test/examples/no_init_lists_examples/fail_no_init_lists2.erl b/test/examples/no_init_lists_examples/fail_no_init_lists2.erl new file mode 100644 index 00000000..6d33a93e --- /dev/null +++ b/test/examples/no_init_lists_examples/fail_no_init_lists2.erl @@ -0,0 +1,15 @@ +-module(fail_no_init_lists2). + +-behaviour(gen_server). + +-export([start_link/1, init/1, handle_cast/2, handle_call/3]). + +start_link(AParam) -> + gen_server:start_link(?MODULE, AParam, []). + +init(_A = [1, 2, 3]) -> + ok. + +handle_cast(_, _) -> ok. + +handle_call(_, _, _) -> ok. diff --git a/test/examples/no_init_lists_examples/fail_no_init_lists3.erl b/test/examples/no_init_lists_examples/fail_no_init_lists3.erl new file mode 100644 index 00000000..e091a1ac --- /dev/null +++ b/test/examples/no_init_lists_examples/fail_no_init_lists3.erl @@ -0,0 +1,21 @@ +-module(fail_no_init_lists3). + +-behaviour(gen_server). + +-export([start_link/1, init/1, handle_cast/2, handle_call/3]). + +start_link(AParam) -> + gen_server:start_link(?MODULE, AParam, []). + +init([_]) -> + ok; + +init(_A = [1, 2, 3]) -> + ok; + +init([undefined]) -> + ok. + +handle_cast(_, _) -> ok. + +handle_call(_, _, _) -> ok. diff --git a/test/examples/pass_no_init_lists.erl b/test/examples/no_init_lists_examples/pass_no_init_lists.erl similarity index 80% rename from test/examples/pass_no_init_lists.erl rename to test/examples/no_init_lists_examples/pass_no_init_lists.erl index 8513ff39..9deb2f07 100644 --- a/test/examples/pass_no_init_lists.erl +++ b/test/examples/no_init_lists_examples/pass_no_init_lists.erl @@ -7,7 +7,13 @@ start_link() -> gen_server:start_link(?MODULE, undefined, []). -init(_) -> +init(1) -> + ok; + +init([undefined]) -> + ok; + +init([_]) -> ok. handle_cast(_, _) -> ok. diff --git a/test/examples/no_init_lists_examples/pass_no_init_lists2.erl b/test/examples/no_init_lists_examples/pass_no_init_lists2.erl new file mode 100644 index 00000000..af3fb8d6 --- /dev/null +++ b/test/examples/no_init_lists_examples/pass_no_init_lists2.erl @@ -0,0 +1,18 @@ +-module(pass_no_init_lists2). + +-behaviour(gen_server). + +-export([start_link/0, init/1, init/2, handle_cast/2, handle_call/3]). + +start_link() -> + gen_server:start_link(?MODULE, undefined, []). + +init(#{}) -> + ok. + +init([_], udnefined) -> + ok. + +handle_cast(_, _) -> ok. + +handle_call(_, _, _) -> ok. diff --git a/test/examples/no_init_lists_examples/pass_no_init_lists3.erl b/test/examples/no_init_lists_examples/pass_no_init_lists3.erl new file mode 100644 index 00000000..fafeba78 --- /dev/null +++ b/test/examples/no_init_lists_examples/pass_no_init_lists3.erl @@ -0,0 +1,18 @@ +-module(pass_no_init_lists3). + +-behaviour(gen_server). + +-export([start_link/0, init/0, init/1, handle_cast/2, handle_call/3]). + +start_link() -> + gen_server:start_link(?MODULE, undefined, []). + +init({1, 2}) -> + ok. + +init() -> + ok. + +handle_cast(_, _) -> ok. + +handle_call(_, _, _) -> ok. diff --git a/test/examples/pass_no_init_lists2.erl b/test/examples/no_init_lists_examples/pass_no_init_lists4.erl similarity index 81% rename from test/examples/pass_no_init_lists2.erl rename to test/examples/no_init_lists_examples/pass_no_init_lists4.erl index 4950249b..288e3e98 100644 --- a/test/examples/pass_no_init_lists2.erl +++ b/test/examples/no_init_lists_examples/pass_no_init_lists4.erl @@ -1,4 +1,4 @@ --module(pass_no_init_lists2). +-module(pass_no_init_lists4). -export([start_link/1, init/1]). diff --git a/test/examples/pass_no_init_lists3.erl b/test/examples/pass_no_init_lists3.erl deleted file mode 100644 index 1851294f..00000000 --- a/test/examples/pass_no_init_lists3.erl +++ /dev/null @@ -1,17 +0,0 @@ --module(pass_no_init_lists3). - --behaviour(gen_statem). - --export([start_link/1, init/1, handle_cast/2, handle_call/3, callback_mode/0]). - -start_link(B) -> - gen_server:start_link(?MODULE, [B], []). - -init([_B]) -> - ok. - -handle_cast(_, _) -> ok. - -handle_call(_, _, _) -> ok. - -callback_mode() -> ok. diff --git a/test/style_SUITE.erl b/test/style_SUITE.erl index 0a325b07..440a7515 100644 --- a/test/style_SUITE.erl +++ b/test/style_SUITE.erl @@ -1452,21 +1452,22 @@ verify_atom_naming_convention(Config) -> verify_no_init_lists(Config) -> Ext = proplists:get_value(test_file_ext, Config, "erl"), - FailPath = "fail_no_init_lists." ++ Ext, - - [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath), - - PassPath = "pass_no_init_lists." ++ Ext, - - [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath), - - PassPath2 = "pass_no_init_lists2." ++ Ext, - - [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath2), - - FailPath3 = "pass_no_init_lists3." ++ Ext, - - [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath3). + ExamplesDir = "no_init_lists_examples/", + FailPath = ExamplesDir ++ "fail_no_init_lists." ++ Ext, + % FailPath2 = ExamplesDir ++ "fail_no_init_lists2." ++ Ext, + % FailPath3 = ExamplesDir ++ "fail_no_init_lists3." ++ Ext, + [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath). + + % [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath2), + % [_, _, _] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath3), + % PassPath = ExamplesDir ++ "pass_no_init_lists." ++ Ext, + % PassPath2 = ExamplesDir ++ "pass_no_init_lists2." ++ Ext, + % PassPath3 = ExamplesDir ++ "pass_no_init_lists3." ++ Ext, + % PassPath4 = ExamplesDir ++ "pass_no_init_lists4." ++ Ext, + % [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath). + % [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath2). + % [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath3), + % [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath4). -spec verify_no_throw(config()) -> any(). verify_no_throw(Config) -> From f956cf95875822b4b6632ad4ccd6e6cc170861cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Fri, 18 Oct 2024 13:16:12 +0200 Subject: [PATCH 16/29] fix maybe and no_init_lists msg --- src/elvis_style.erl | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/elvis_style.erl b/src/elvis_style.erl index 8f2c42d7..d7eab15d 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -1,7 +1,5 @@ -module(elvis_style). --feature(maybe_expr, enable). - -export([default/1, function_naming_convention/3, variable_naming_convention/3, consistent_variable_casing/3, macro_names/3, macro_module_names/3, no_macros/3, no_specs/3, no_types/3, no_block_expressions/3, operator_spaces/3, no_space/3, @@ -33,8 +31,8 @@ no_match_in_condition_config/0, behaviour_spelling_config/0, param_pattern_matching_config/0, private_data_type_config/0]). -% -define(NO_INIT_LISTS_MSG, -% "Do not use a list as the parameter for the 'init' callback at position ~p."). +-define(NO_INIT_LISTS_MSG, + "Do not use a list as the parameter for the 'init' callback at position ~p."). -define(INVALID_MACRO_NAME_REGEX_MSG, "The macro named ~p on line ~p does not respect the format " "defined by the regular expression '~p'."). @@ -1067,7 +1065,7 @@ no_init_lists(Config, Target, RuleConfig) -> ResultFun = fun({_, Location, _}) -> Info = [Location], - Msg = "asd", + Msg = ?NO_INIT_LISTS_MSG, elvis_result:new(item, Msg, Info, Location) end, lists:map(ResultFun, FunListAttributes). From 84ab8d5e8d0b9dbbccdf37802532fe2836f503cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=B3r=20Mil=C3=A1n?= <71042542+bormilan@users.noreply.github.com> Date: Fri, 18 Oct 2024 13:16:52 +0200 Subject: [PATCH 17/29] Update test/examples/no_init_lists_examples/pass_no_init_lists3.erl Co-authored-by: Brujo Benavides --- test/examples/no_init_lists_examples/pass_no_init_lists3.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/examples/no_init_lists_examples/pass_no_init_lists3.erl b/test/examples/no_init_lists_examples/pass_no_init_lists3.erl index fafeba78..dd9fc4f7 100644 --- a/test/examples/no_init_lists_examples/pass_no_init_lists3.erl +++ b/test/examples/no_init_lists_examples/pass_no_init_lists3.erl @@ -5,7 +5,7 @@ -export([start_link/0, init/0, init/1, handle_cast/2, handle_call/3]). start_link() -> - gen_server:start_link(?MODULE, undefined, []). + gen_server:start_link(?MODULE, {1, 2}, []). init({1, 2}) -> ok. From d8316705f068a69ac3f8bb77d770a28ed1ebc7b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=B3r=20Mil=C3=A1n?= <71042542+bormilan@users.noreply.github.com> Date: Fri, 18 Oct 2024 13:16:59 +0200 Subject: [PATCH 18/29] Update test/examples/no_init_lists_examples/pass_no_init_lists.erl Co-authored-by: Brujo Benavides --- test/examples/no_init_lists_examples/pass_no_init_lists.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/examples/no_init_lists_examples/pass_no_init_lists.erl b/test/examples/no_init_lists_examples/pass_no_init_lists.erl index 9deb2f07..c9a0ea69 100644 --- a/test/examples/no_init_lists_examples/pass_no_init_lists.erl +++ b/test/examples/no_init_lists_examples/pass_no_init_lists.erl @@ -5,7 +5,7 @@ -export([start_link/0, init/1, handle_cast/2, handle_call/3]). start_link() -> - gen_server:start_link(?MODULE, undefined, []). + gen_server:start_link(?MODULE, 1, []). init(1) -> ok; From 1c18d105b1d687b38405a3525a86ecf860f17977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=B3r=20Mil=C3=A1n?= <71042542+bormilan@users.noreply.github.com> Date: Fri, 18 Oct 2024 13:17:29 +0200 Subject: [PATCH 19/29] Update test/examples/no_init_lists_examples/pass_no_init_lists2.erl Co-authored-by: Brujo Benavides --- test/examples/no_init_lists_examples/pass_no_init_lists2.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/examples/no_init_lists_examples/pass_no_init_lists2.erl b/test/examples/no_init_lists_examples/pass_no_init_lists2.erl index af3fb8d6..c3c7b126 100644 --- a/test/examples/no_init_lists_examples/pass_no_init_lists2.erl +++ b/test/examples/no_init_lists_examples/pass_no_init_lists2.erl @@ -5,7 +5,7 @@ -export([start_link/0, init/1, init/2, handle_cast/2, handle_call/3]). start_link() -> - gen_server:start_link(?MODULE, undefined, []). + gen_server:start_link(?MODULE, #{a => map}, []). init(#{}) -> ok. From beea14bf4f6be9c6d8c867a6edf4ff86c381fbfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=B3r=20Mil=C3=A1n?= <71042542+bormilan@users.noreply.github.com> Date: Fri, 18 Oct 2024 13:17:49 +0200 Subject: [PATCH 20/29] Update src/elvis_style.erl Co-authored-by: Brujo Benavides --- src/elvis_style.erl | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/elvis_style.erl b/src/elvis_style.erl index d7eab15d..c154e8c4 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -1075,14 +1075,7 @@ is_rule_behaviour(Root, RuleConfig) -> IsBehaviour = fun(Node) -> ktn_code:type(Node) == behaviour end, case elvis_code:find(IsBehaviour, Root) of [BehaviourNode] -> - case lists:member( - ktn_code:attr(value, BehaviourNode), Behaviors) - of - true -> - true; - false -> - false - end; + lists:member(ktn_code:attr(value, BehaviourNode), Behaviors) [] -> false end. From 039939e6e8f7d3b7a9bd33b9bd8e4d1f6f8e7e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Fri, 18 Oct 2024 13:40:05 +0200 Subject: [PATCH 21/29] fix --- src/elvis_style.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/elvis_style.erl b/src/elvis_style.erl index e8d3f2a6..a63d1d03 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -1158,7 +1158,8 @@ is_rule_behaviour(Root, RuleConfig) -> IsBehaviour = fun(Node) -> ktn_code:type(Node) == behaviour end, case elvis_code:find(IsBehaviour, Root) of [BehaviourNode] -> - lists:member(ktn_code:attr(value, BehaviourNode), Behaviors) + lists:member( + ktn_code:attr(value, BehaviourNode), Behaviors); [] -> false end. From 7b85321743033ea618b4df89e72a7b44723cfc08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Fri, 18 Oct 2024 17:23:37 +0200 Subject: [PATCH 22/29] remake rule logic --- src/elvis_style.erl | 68 +++++++++++++------ .../example_behaviour.erl | 3 + .../fail_no_init_lists4.erl | 15 ++++ .../pass_no_init_lists5.erl | 8 +++ test/style_SUITE.erl | 32 +++++---- 5 files changed, 93 insertions(+), 33 deletions(-) create mode 100644 test/examples/no_init_lists_examples/example_behaviour.erl create mode 100644 test/examples/no_init_lists_examples/fail_no_init_lists4.erl create mode 100644 test/examples/no_init_lists_examples/pass_no_init_lists5.erl diff --git a/src/elvis_style.erl b/src/elvis_style.erl index a63d1d03..d4da4df8 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -1123,46 +1123,76 @@ atom_naming_convention(Config, Target, RuleConfig) -> [elvis_result:item()]. no_init_lists(Config, Target, RuleConfig) -> Root = get_root(Config, Target, RuleConfig), - FunListAttributes = + + InitFuns = case is_rule_behaviour(Root, RuleConfig) of true -> IsFunction = fun(Node) -> ktn_code:type(Node) == function end, FunctionNodes = elvis_code:find(IsFunction, Root), - PairFun = + ProcessFun = fun(FunctionNode) -> Name = ktn_code:attr(name, FunctionNode), Location = ktn_code:attr(location, FunctionNode), - [Content] = ktn_code:content(FunctionNode), - Attributes = ktn_code:node_attr(pattern, Content), - {Name, - Location, - [Attr || #{type := Type} = Attr <- Attributes, Type == cons]} + Content = ktn_code:content(FunctionNode), + lists:map(fun(Elem) -> + Attributes = ktn_code:node_attr(pattern, Elem), + {Name, Location, Attributes} + end, + Content) end, - FunListAttributeInfos = lists:map(PairFun, FunctionNodes), - FilterFun = fun({Name, _, Args}) -> length(Args) =:= 1 andalso Name =:= init end, - lists:filter(FilterFun, FunListAttributeInfos); + + lists:append( + lists:filtermap(fun(FunctionNode) -> + Name = ktn_code:attr(name, FunctionNode), + case Name of + init -> + {true, ProcessFun(FunctionNode)}; + _ -> + false + end + end, + FunctionNodes)); false -> [] end, + IsBreakRule = + lists:all(fun({_, _, Attributes}) -> + length(lists:filter(fun(Elem) -> is_list_node(Elem) end, Attributes)) =:= 1 + end, + InitFuns), + ResultFun = fun({_, Location, _}) -> Info = [Location], Msg = ?NO_INIT_LISTS_MSG, elvis_result:new(item, Msg, Info, Location) end, - lists:map(ResultFun, FunListAttributes). + + case IsBreakRule of + true -> + lists:map(ResultFun, InitFuns); + false -> + [] + end. is_rule_behaviour(Root, RuleConfig) -> - Behaviors = option(behaviours, RuleConfig, no_init_lists), + ConfigBehaviors = option(behaviours, RuleConfig, no_init_lists), IsBehaviour = fun(Node) -> ktn_code:type(Node) == behaviour end, - case elvis_code:find(IsBehaviour, Root) of - [BehaviourNode] -> - lists:member( - ktn_code:attr(value, BehaviourNode), Behaviors); - [] -> - false - end. + Behaviours = elvis_code:find(IsBehaviour, Root), + lists:any(fun(Elem) -> Elem =:= true end, + lists:map(fun(BehaviourNode) -> + lists:member( + ktn_code:attr(value, BehaviourNode), ConfigBehaviors) + end, + Behaviours)). + +is_list_node(#{type := cons}) -> + true; +is_list_node(#{type := match, content := Content}) -> + lists:any(fun(Elem) -> is_list_node(Elem) end, Content); +is_list_node(_) -> + false. -spec no_throw(elvis_config:config(), elvis_file:file(), empty_rule_config()) -> [elvis_result:item()]. diff --git a/test/examples/no_init_lists_examples/example_behaviour.erl b/test/examples/no_init_lists_examples/example_behaviour.erl new file mode 100644 index 00000000..e8b5fa63 --- /dev/null +++ b/test/examples/no_init_lists_examples/example_behaviour.erl @@ -0,0 +1,3 @@ +-module(example_behaviour). + +-callback example() -> atom(). diff --git a/test/examples/no_init_lists_examples/fail_no_init_lists4.erl b/test/examples/no_init_lists_examples/fail_no_init_lists4.erl new file mode 100644 index 00000000..df738c39 --- /dev/null +++ b/test/examples/no_init_lists_examples/fail_no_init_lists4.erl @@ -0,0 +1,15 @@ +-module(fail_no_init_lists4). + +-behaviour(gen_server). +-behaviour(example_behaviour). + +-export([init/1, handle_cast/2, handle_cast/3, handle_call/3]). +-export([example/0]). + +init([]) -> {error, "should not be a list"}. + +handle_cast(_, _) -> ok. +handle_cast(_, _, _) -> ok. +handle_call(_, _, _) -> ok. + +example() -> ok. diff --git a/test/examples/no_init_lists_examples/pass_no_init_lists5.erl b/test/examples/no_init_lists_examples/pass_no_init_lists5.erl new file mode 100644 index 00000000..c12e4f1f --- /dev/null +++ b/test/examples/no_init_lists_examples/pass_no_init_lists5.erl @@ -0,0 +1,8 @@ +-module(pass_no_init_lists5). + +-behaviour(example_behaviour). + +-export([init/1, example/0]). + +init([]) -> {error, "can be a list"}. +example() -> ok. diff --git a/test/style_SUITE.erl b/test/style_SUITE.erl index 26c8660a..a3856b31 100644 --- a/test/style_SUITE.erl +++ b/test/style_SUITE.erl @@ -1527,20 +1527,24 @@ verify_no_init_lists(Config) -> ExamplesDir = "no_init_lists_examples/", FailPath = ExamplesDir ++ "fail_no_init_lists." ++ Ext, - % FailPath2 = ExamplesDir ++ "fail_no_init_lists2." ++ Ext, - % FailPath3 = ExamplesDir ++ "fail_no_init_lists3." ++ Ext, - [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath). - - % [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath2), - % [_, _, _] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath3), - % PassPath = ExamplesDir ++ "pass_no_init_lists." ++ Ext, - % PassPath2 = ExamplesDir ++ "pass_no_init_lists2." ++ Ext, - % PassPath3 = ExamplesDir ++ "pass_no_init_lists3." ++ Ext, - % PassPath4 = ExamplesDir ++ "pass_no_init_lists4." ++ Ext, - % [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath). - % [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath2). - % [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath3), - % [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath4). + FailPath2 = ExamplesDir ++ "fail_no_init_lists2." ++ Ext, + FailPath3 = ExamplesDir ++ "fail_no_init_lists3." ++ Ext, + % FailPath4 = ExamplesDir ++ "fail_no_init_lists4." ++ Ext, + [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath), + [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath2), + [_, _, _] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath3), + % [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath4), + PassPath = ExamplesDir ++ "pass_no_init_lists." ++ Ext, + PassPath2 = ExamplesDir ++ "pass_no_init_lists2." ++ Ext, + PassPath3 = ExamplesDir ++ "pass_no_init_lists3." ++ Ext, + PassPath4 = ExamplesDir ++ "pass_no_init_lists4." ++ Ext, + PassPath5 = ExamplesDir ++ "pass_no_init_lists5." ++ Ext, + [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath), + [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath2), + [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath3), + [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath4), + [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath5), + ok. -spec verify_no_throw(config()) -> any(). verify_no_throw(Config) -> From 379a0889532b4d77e7a4e1d869df22b14944b15c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Fri, 18 Oct 2024 17:28:11 +0200 Subject: [PATCH 23/29] simplify node tuple --- src/elvis_style.erl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/elvis_style.erl b/src/elvis_style.erl index d4da4df8..71560f5b 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -1131,12 +1131,11 @@ no_init_lists(Config, Target, RuleConfig) -> FunctionNodes = elvis_code:find(IsFunction, Root), ProcessFun = fun(FunctionNode) -> - Name = ktn_code:attr(name, FunctionNode), Location = ktn_code:attr(location, FunctionNode), Content = ktn_code:content(FunctionNode), lists:map(fun(Elem) -> Attributes = ktn_code:node_attr(pattern, Elem), - {Name, Location, Attributes} + {Location, Attributes} end, Content) end, @@ -1157,13 +1156,13 @@ no_init_lists(Config, Target, RuleConfig) -> end, IsBreakRule = - lists:all(fun({_, _, Attributes}) -> + lists:all(fun({_, Attributes}) -> length(lists:filter(fun(Elem) -> is_list_node(Elem) end, Attributes)) =:= 1 end, InitFuns), ResultFun = - fun({_, Location, _}) -> + fun({Location, _}) -> Info = [Location], Msg = ?NO_INIT_LISTS_MSG, elvis_result:new(item, Msg, Info, Location) From 63aef9b48640a0e06b5765963dadc3c05fb4a1d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Fri, 18 Oct 2024 17:33:04 +0200 Subject: [PATCH 24/29] rename is_rule_behaviour to is_relevant_behaviour --- src/elvis_style.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/elvis_style.erl b/src/elvis_style.erl index 71560f5b..f53d3b2f 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -1125,7 +1125,7 @@ no_init_lists(Config, Target, RuleConfig) -> Root = get_root(Config, Target, RuleConfig), InitFuns = - case is_rule_behaviour(Root, RuleConfig) of + case is_relevant_behaviour(Root, RuleConfig) of true -> IsFunction = fun(Node) -> ktn_code:type(Node) == function end, FunctionNodes = elvis_code:find(IsFunction, Root), @@ -1175,7 +1175,7 @@ no_init_lists(Config, Target, RuleConfig) -> [] end. -is_rule_behaviour(Root, RuleConfig) -> +is_relevant_behaviour(Root, RuleConfig) -> ConfigBehaviors = option(behaviours, RuleConfig, no_init_lists), IsBehaviour = fun(Node) -> ktn_code:type(Node) == behaviour end, Behaviours = elvis_code:find(IsBehaviour, Root), From 02881b8b888279d8df52ffc7b2d36cae958aa61f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Fri, 18 Oct 2024 17:36:36 +0200 Subject: [PATCH 25/29] add no_init_lists_config type --- src/elvis_style.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/elvis_style.erl b/src/elvis_style.erl index f53d3b2f..94d27586 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -29,7 +29,7 @@ no_import_config/0, no_catch_expressions_config/0, numeric_format_config/0, no_single_clause_case_config/0, consistent_variable_casing_config/0, no_match_in_condition_config/0, behaviour_spelling_config/0, - param_pattern_matching_config/0, private_data_type_config/0]). + param_pattern_matching_config/0, private_data_type_config/0, no_init_lists_config/0]). -define(NO_INIT_LISTS_MSG, "Do not use a list as the parameter for the 'init' callback at position ~p."). From 5d32c9ca83dc58e981353dba2b3296bb010ccc73 Mon Sep 17 00:00:00 2001 From: bormilan Date: Thu, 24 Oct 2024 14:38:00 +0200 Subject: [PATCH 26/29] refactor rule logic --- src/elvis_style.erl | 66 +++++++++---------- .../pass_no_init_lists2.erl | 2 +- test/style_SUITE.erl | 7 +- 3 files changed, 36 insertions(+), 39 deletions(-) diff --git a/src/elvis_style.erl b/src/elvis_style.erl index 94d27586..acbd339b 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -1124,56 +1124,48 @@ atom_naming_convention(Config, Target, RuleConfig) -> no_init_lists(Config, Target, RuleConfig) -> Root = get_root(Config, Target, RuleConfig), - InitFuns = + ListInitClauses = case is_relevant_behaviour(Root, RuleConfig) of true -> - IsFunction = fun(Node) -> ktn_code:type(Node) == function end, - FunctionNodes = elvis_code:find(IsFunction, Root), - ProcessFun = - fun(FunctionNode) -> - Location = ktn_code:attr(location, FunctionNode), - Content = ktn_code:content(FunctionNode), - lists:map(fun(Elem) -> - Attributes = ktn_code:node_attr(pattern, Elem), - {Location, Attributes} - end, - Content) + IsInit1Function = + fun(Node) -> + ktn_code:type(Node) == function + andalso ktn_code:attr(name, Node) == init + andalso ktn_code:attr(arity, Node) == 1 + end, + [Init1Fun] = elvis_code:find(IsInit1Function, Root), + + FilterClauses = + fun(Clause) -> + [Attribute] = ktn_code:node_attr(pattern, Clause), + case is_list_node(Attribute) of + true -> + {true, ktn_code:attr(location, Clause)}; + false -> + false + end end, - lists:append( - lists:filtermap(fun(FunctionNode) -> - Name = ktn_code:attr(name, FunctionNode), - case Name of - init -> - {true, ProcessFun(FunctionNode)}; - _ -> - false - end - end, - FunctionNodes)); + Content = ktn_code:content(Init1Fun), + ListAttrClauses = lists:filtermap(FilterClauses, Content), + case length(ListAttrClauses) =:= length(Content) of + true -> + ListAttrClauses; + false -> + [] + end; false -> [] end, - IsBreakRule = - lists:all(fun({_, Attributes}) -> - length(lists:filter(fun(Elem) -> is_list_node(Elem) end, Attributes)) =:= 1 - end, - InitFuns), - ResultFun = - fun({Location, _}) -> + fun(Location) -> Info = [Location], Msg = ?NO_INIT_LISTS_MSG, elvis_result:new(item, Msg, Info, Location) end, - case IsBreakRule of - true -> - lists:map(ResultFun, InitFuns); - false -> - [] - end. + lists:map(ResultFun, ListInitClauses). is_relevant_behaviour(Root, RuleConfig) -> ConfigBehaviors = option(behaviours, RuleConfig, no_init_lists), @@ -1188,6 +1180,8 @@ is_relevant_behaviour(Root, RuleConfig) -> is_list_node(#{type := cons}) -> true; +is_list_node(#{type := nil}) -> + true; is_list_node(#{type := match, content := Content}) -> lists:any(fun(Elem) -> is_list_node(Elem) end, Content); is_list_node(_) -> diff --git a/test/examples/no_init_lists_examples/pass_no_init_lists2.erl b/test/examples/no_init_lists_examples/pass_no_init_lists2.erl index c3c7b126..8ab684b4 100644 --- a/test/examples/no_init_lists_examples/pass_no_init_lists2.erl +++ b/test/examples/no_init_lists_examples/pass_no_init_lists2.erl @@ -10,7 +10,7 @@ start_link() -> init(#{}) -> ok. -init([_], udnefined) -> +init([_], undefined) -> ok. handle_cast(_, _) -> ok. diff --git a/test/style_SUITE.erl b/test/style_SUITE.erl index a3856b31..bb2a1adb 100644 --- a/test/style_SUITE.erl +++ b/test/style_SUITE.erl @@ -1529,16 +1529,19 @@ verify_no_init_lists(Config) -> FailPath = ExamplesDir ++ "fail_no_init_lists." ++ Ext, FailPath2 = ExamplesDir ++ "fail_no_init_lists2." ++ Ext, FailPath3 = ExamplesDir ++ "fail_no_init_lists3." ++ Ext, - % FailPath4 = ExamplesDir ++ "fail_no_init_lists4." ++ Ext, + FailPath4 = ExamplesDir ++ "fail_no_init_lists4." ++ Ext, + [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath), [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath2), [_, _, _] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath3), - % [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath4), + [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath4), + PassPath = ExamplesDir ++ "pass_no_init_lists." ++ Ext, PassPath2 = ExamplesDir ++ "pass_no_init_lists2." ++ Ext, PassPath3 = ExamplesDir ++ "pass_no_init_lists3." ++ Ext, PassPath4 = ExamplesDir ++ "pass_no_init_lists4." ++ Ext, PassPath5 = ExamplesDir ++ "pass_no_init_lists5." ++ Ext, + [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath), [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath2), [] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, PassPath3), From d1f6cfc0ff908a8f3b3f1ca9b0f15dc855a72875 Mon Sep 17 00:00:00 2001 From: bormilan Date: Thu, 24 Oct 2024 18:03:32 +0200 Subject: [PATCH 27/29] add new test, and case --- Untitled | 1 + src/elvis_style.erl | 12 ++++++++++-- .../no_init_lists_examples/fail_no_init_lists5.erl | 12 ++++++++++++ .../no_init_lists_examples/fail_no_init_lists6.erl | 7 +++++++ .../no_init_lists_examples/fail_no_init_lists7.erl | 9 +++++++++ .../no_init_lists_examples/fail_no_init_lists8.erl | 11 +++++++++++ test/style_SUITE.erl | 8 ++++++++ 7 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 Untitled create mode 100644 test/examples/no_init_lists_examples/fail_no_init_lists5.erl create mode 100644 test/examples/no_init_lists_examples/fail_no_init_lists6.erl create mode 100644 test/examples/no_init_lists_examples/fail_no_init_lists7.erl create mode 100644 test/examples/no_init_lists_examples/fail_no_init_lists8.erl diff --git a/Untitled b/Untitled new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/Untitled @@ -0,0 +1 @@ + diff --git a/src/elvis_style.erl b/src/elvis_style.erl index acbd339b..2d757fc2 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -151,7 +151,8 @@ -spec default(Rule :: atom()) -> DefaultRuleConfig :: term(). default(no_init_lists) -> - #{behaviours => [gen_server, gen_statem]}; + #{behaviours => + [gen_server, gen_statem, gen_fsm, supervisor, supervisor_bridge, gen_event]}; default(macro_names) -> #{regex => "^[A-Z](_?[A-Z0-9]+)*$"}; default(operator_spaces) -> @@ -1133,7 +1134,14 @@ no_init_lists(Config, Target, RuleConfig) -> andalso ktn_code:attr(name, Node) == init andalso ktn_code:attr(arity, Node) == 1 end, - [Init1Fun] = elvis_code:find(IsInit1Function, Root), + + Init1Fun = + case elvis_code:find(IsInit1Function, Root) of + [] -> + []; + [Fun] -> + Fun + end, FilterClauses = fun(Clause) -> diff --git a/test/examples/no_init_lists_examples/fail_no_init_lists5.erl b/test/examples/no_init_lists_examples/fail_no_init_lists5.erl new file mode 100644 index 00000000..07f34ca2 --- /dev/null +++ b/test/examples/no_init_lists_examples/fail_no_init_lists5.erl @@ -0,0 +1,12 @@ +-module(fail_no_init_lists5). + +-behaviour(gen_fsm). + +-export([init/1, handle_sync_event/4, handle_event/3]). + +init([]) -> {error, "Don't use list for init/1"}. + +handle_sync_event(_, _, _, _) -> ok. + +handle_event(_, _, _) -> ok. + diff --git a/test/examples/no_init_lists_examples/fail_no_init_lists6.erl b/test/examples/no_init_lists_examples/fail_no_init_lists6.erl new file mode 100644 index 00000000..38cbd9be --- /dev/null +++ b/test/examples/no_init_lists_examples/fail_no_init_lists6.erl @@ -0,0 +1,7 @@ +-module(fail_no_init_lists6). + +-behaviour(supervisor). + +-export([init/1]). + +init([]) -> {error, "Don't use list for init/1"}. diff --git a/test/examples/no_init_lists_examples/fail_no_init_lists7.erl b/test/examples/no_init_lists_examples/fail_no_init_lists7.erl new file mode 100644 index 00000000..6a0e4f33 --- /dev/null +++ b/test/examples/no_init_lists_examples/fail_no_init_lists7.erl @@ -0,0 +1,9 @@ +-module(fail_no_init_lists7). + +-behaviour(supervisor_bridge). + +-export([init/1, terminate/2]). + +init([]) -> {error, "Don't use list for init/1"}. + +terminate(_, _) -> ok. diff --git a/test/examples/no_init_lists_examples/fail_no_init_lists8.erl b/test/examples/no_init_lists_examples/fail_no_init_lists8.erl new file mode 100644 index 00000000..3c48ccfe --- /dev/null +++ b/test/examples/no_init_lists_examples/fail_no_init_lists8.erl @@ -0,0 +1,11 @@ +-module(fail_no_init_lists8). + +-behaviour(gen_event). + +-export([init/1, handle_event/2, handle_call/2]). + +init([]) -> {error, "Don't use list for init/1"}. + +handle_event(_, _) -> ok. + +handle_call(_, _) -> ok. diff --git a/test/style_SUITE.erl b/test/style_SUITE.erl index bb2a1adb..54649661 100644 --- a/test/style_SUITE.erl +++ b/test/style_SUITE.erl @@ -1530,11 +1530,19 @@ verify_no_init_lists(Config) -> FailPath2 = ExamplesDir ++ "fail_no_init_lists2." ++ Ext, FailPath3 = ExamplesDir ++ "fail_no_init_lists3." ++ Ext, FailPath4 = ExamplesDir ++ "fail_no_init_lists4." ++ Ext, + FailPath5 = ExamplesDir ++ "fail_no_init_lists5." ++ Ext, + FailPath6 = ExamplesDir ++ "fail_no_init_lists6." ++ Ext, + FailPath7 = ExamplesDir ++ "fail_no_init_lists7." ++ Ext, + FailPath8 = ExamplesDir ++ "fail_no_init_lists8." ++ Ext, [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath), [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath2), [_, _, _] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath3), [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath4), + [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath5), + [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath6), + [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath7), + [_] = elvis_core_apply_rule(Config, elvis_style, no_init_lists, #{}, FailPath8), PassPath = ExamplesDir ++ "pass_no_init_lists." ++ Ext, PassPath2 = ExamplesDir ++ "pass_no_init_lists2." ++ Ext, From 40d79858eb88fa2b4d5a1a2d21228a31a73e0d18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Sat, 26 Oct 2024 07:14:14 +0200 Subject: [PATCH 28/29] fix cases --- src/elvis_style.erl | 48 +++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/src/elvis_style.erl b/src/elvis_style.erl index 2d757fc2..456c899b 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -1135,32 +1135,19 @@ no_init_lists(Config, Target, RuleConfig) -> andalso ktn_code:attr(arity, Node) == 1 end, - Init1Fun = - case elvis_code:find(IsInit1Function, Root) of - [] -> - []; - [Fun] -> - Fun - end, - - FilterClauses = - fun(Clause) -> - [Attribute] = ktn_code:node_attr(pattern, Clause), - case is_list_node(Attribute) of - true -> - {true, ktn_code:attr(location, Clause)}; - false -> - false - end - end, - - Content = ktn_code:content(Init1Fun), - ListAttrClauses = lists:filtermap(FilterClauses, Content), - case length(ListAttrClauses) =:= length(Content) of - true -> - ListAttrClauses; - false -> - [] + case elvis_code:find(IsInit1Function, Root) of + [] -> + []; + [Init1Fun] -> + Content = ktn_code:content(Init1Fun), + ListAttrClauses = + lists:filtermap(fun(X) -> filter_list_clause_location(X) end, Content), + case length(ListAttrClauses) =:= length(Content) of + true -> + ListAttrClauses; + false -> + [] + end end; false -> [] @@ -1186,6 +1173,15 @@ is_relevant_behaviour(Root, RuleConfig) -> end, Behaviours)). +filter_list_clause_location(Clause) -> + [Attribute] = ktn_code:node_attr(pattern, Clause), + case is_list_node(Attribute) of + true -> + {true, ktn_code:attr(location, Clause)}; + false -> + false + end. + is_list_node(#{type := cons}) -> true; is_list_node(#{type := nil}) -> From ae45c44a277c79ccf3bca17b41a977a199ca8bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mil=C3=A1n=20B=C3=B3r?= Date: Sun, 27 Oct 2024 07:31:22 +0100 Subject: [PATCH 29/29] delete unnecessary file --- Untitled | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Untitled diff --git a/Untitled b/Untitled deleted file mode 100644 index 8b137891..00000000 --- a/Untitled +++ /dev/null @@ -1 +0,0 @@ -