Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc_rules/elvis_style/no_single_match_maybe.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

Single-match maybe statements should be avoided.

> [!NOTE]
> This rule only works under Erlang/OTP 27+.

## Avoid

```erlang
Expand Down
9 changes: 8 additions & 1 deletion rebar.config
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
%% == Compiler and Profiles ==

{erl_opts, [warn_unused_import, warn_export_vars, warnings_as_errors, verbose, report, debug_info]}.
{erl_opts, [
warn_unused_import,
warn_export_vars,
warnings_as_errors,
verbose,
report,
debug_info
]}.

{minimum_otp_vsn, "25"}.

Expand Down
78 changes: 57 additions & 21 deletions src/elvis_config.erl
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
-module(elvis_config).

-feature(maybe_expr, enable).

-export([
from_rebar/1,
from_file/1,
Expand Down Expand Up @@ -82,28 +84,62 @@ validate(Config) ->
lists:foreach(fun do_validate/1, Config).

do_validate(RuleGroup) ->
case maps:is_key(src_dirs, RuleGroup) orelse maps:is_key(dirs, RuleGroup) of
false ->
throw({invalid_config, {missing_dirs, RuleGroup}});
true ->
ok
end,
case maps:is_key(dirs, RuleGroup) of
true ->
case maps:is_key(filter, RuleGroup) of
false ->
throw({invalid_config, {missing_filter, RuleGroup}});
true ->
ok
end;
false ->
ok
end,
case maps:is_key(rules, RuleGroup) orelse maps:is_key(ruleset, RuleGroup) of
maybe
ok ?= maybe_missing_dirs(RuleGroup),
ok ?= maybe_missing_filter(RuleGroup),
ok ?= maybe_missing_rules(RuleGroup),
ok ?= maybe_invalid_rules(RuleGroup)
else
{error, Error} ->
throw({invalid_config, Error})
end.

maybe_missing_dirs(RuleGroup) ->
maybe_boolean_wrapper(
not (maps:is_key(dirs, RuleGroup) andalso not maps:is_key(filter, RuleGroup)), missing_dir
).

maybe_missing_filter(RuleGroup) ->
maybe_boolean_wrapper(
maps:is_key(src_dirs, RuleGroup) orelse maps:is_key(dirs, RuleGroup), missing_filter
).

maybe_missing_rules(RuleGroup) ->
maybe_boolean_wrapper(
maps:is_key(rules, RuleGroup) orelse maps:is_key(ruleset, RuleGroup), missing_rules
).

maybe_boolean_wrapper(true, _Flag) -> ok;
maybe_boolean_wrapper(false, Flag) -> {error, Flag}.

maybe_invalid_rules(#{rules := Rules}) ->
case invalid_rules(Rules) of
[] -> ok;
InvalidRules -> {error, {invalid_rules, InvalidRules}}
end;
maybe_invalid_rules(_) ->
ok.

invalid_rules(Rules) ->
lists:filtermap(fun is_invalid_rule/1, Rules).

is_invalid_rule({Module, RuleName, _}) ->
is_invalid_rule({Module, RuleName});
is_invalid_rule({Module, RuleName}) ->
maybe
{file, _} ?= code:is_loaded(Module),
ExportedRules = erlang:get_module_info(Module, exports),
case lists:keyfind(RuleName, 1, ExportedRules) of
false -> {true, {invalid_rule, {Module, RuleName}}};
_ -> false
end
else
false ->
throw({invalid_config, {missing_rules, RuleGroup}});
true ->
ok
elvis_utils:warn_prn(
"Invalid module (~p) specified in elvis.config.~n",
[Module]
),
false
end.

-spec normalize(configs()) -> configs().
Expand Down
1 change: 1 addition & 0 deletions src/elvis_core.erl
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ load_file_data(Config, File) ->
-spec main([]) -> true | no_return().
main([]) ->
ok = application:load(elvis_core),
{module, _} = code:ensure_loaded(elvis_style),
R = rock(elvis_config:from_file("elvis.config")),
R =:= ok orelse halt(1).

Expand Down
20 changes: 19 additions & 1 deletion test/elvis_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
invalid_file/1,
to_string/1,
chunk_fold/1,
erl_files_strict_ruleset/1
erl_files_strict_ruleset/1,
rock_with_invalid_rules/1
]).

-define(EXCLUDED_FUNS, [module_info, all, test, init_per_suite, end_per_suite, chunk_fold_task]).
Expand Down Expand Up @@ -424,6 +425,23 @@ rock_with_umbrella_apps(_Config) ->
elvis_core:rock(ElvisConfig),
ok.

-spec rock_with_invalid_rules(config()) -> any().
rock_with_invalid_rules(_Config) ->
ConfigPath = "../../test/examples/invalid_rules.elvis.config",
ElvisConfig = elvis_config:from_file(ConfigPath),
ExpectedErrorMessage =
{invalid_rules, [
{invalid_rule, {elvis_style, not_existing_rule}},
{invalid_rule, {elvis_style, what_is_this_rule}}
]},
try
ok = elvis_core:rock(ElvisConfig),
ct:fail("Elvis should not have rocked with ~p", [ElvisConfig])
catch
{invalid_config, ExpectedErrorMessage} ->
ok
end.

%%%%%%%%%%%%%%%
%%% Utils

Expand Down
47 changes: 47 additions & 0 deletions test/examples/invalid_rules.elvis.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
[
{elvis, [
{config, [
#{
dirs => ["src"],
filter => "*.erl",
rules =>
[
{elvis_style, invalid_dynamic_call, #{ignore => [elvis_core]}},
{elvis_style, dont_repeat_yourself, #{min_complexity => 20}},
{elvis_style, no_debug_call, #{ignore => [elvis_result, elvis_utils]}},
{elvis_style, god_modules, #{ignore => [elvis_style]}},
{elvis_style, no_throw, disable},
{elvis_style, not_existing_rule},
{elvis_style, what_is_this_rule, #{ignore => [elvis_style]}},
{not_existing_module, dont_repeat_yourself},
{not_existing_module, dont_repeat_yourself, #{min_complexity => 20}}
],
ruleset => erl_files
},
#{
dirs => ["_build/default/lib/elvis_core/ebin"],
filter => "*.beam",
rules =>
[
{elvis_style, invalid_dynamic_call, #{ignore => [elvis_core]}},
{elvis_style, dont_repeat_yourself, #{min_complexity => 20}},
{elvis_style, no_debug_call, #{ignore => [elvis_result, elvis_utils]}},
{elvis_style, atom_naming_convention, #{ignore => [elvis_task]}},
{elvis_style, god_modules, #{ignore => [elvis_style]}},
{elvis_style, no_throw, disable}
],
ruleset => beam_files
},
#{
dirs => ["."],
filter => "rebar.config",
ruleset => rebar_config
},
#{
dirs => ["."],
filter => "elvis.config",
ruleset => elvis_config
}
]}
]}
].
45 changes: 45 additions & 0 deletions test/examples/invalid_rules2.elvis.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

[
{elvis, [
{config, [
#{
dirs => ["src"],
filter => "*.erl",
rules =>
[
{elvis_style, invalid_dynamic_call, #{ignore => [elvis_core]}},
{elvis_style, dont_repeat_yourself, #{min_complexity => 20}},
{elvis_style, no_debug_call, #{ignore => [elvis_result, elvis_utils]}},
{elvis_style, god_modules, #{ignore => [elvis_style]}},
{elvis_style, no_throw, disable}
],
ruleset => erl_files
},
#{
dirs => ["_build/default/lib/elvis_core/ebin"],
filter => "*.beam",
rules =>
[
{elvis_style, invalid_dynamic_call, #{ignore => [elvis_core]}},
{elvis_style, dont_repeat_yourself, #{min_complexity => 20}},
{elvis_style, no_debug_call, #{ignore => [elvis_result, elvis_utils]}},
{elvis_style, atom_naming_convention, #{ignore => [elvis_task]}},
{elvis_style, god_modules, #{ignore => [elvis_style]}},
{elvis_style, no_throw, disable},
{not_existing_beam_module, no_throw, disable}
],
ruleset => beam_files
},
#{
dirs => ["."],
filter => "rebar.config",
ruleset => rebar_config
},
#{
dirs => ["."],
filter => "elvis.config",
ruleset => elvis_config
}
]}
]}
].
10 changes: 8 additions & 2 deletions test/style_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
verify_no_import/1,
verify_no_catch_expressions/1,
verify_no_single_clause_case/1,
verify_no_single_match_maybe/1,
verify_numeric_format/1,
verify_behaviour_spelling/1,
verify_always_shortcircuit/1,
Expand Down Expand Up @@ -109,6 +108,12 @@
verify_elvis_attr_param_pattern_matching/1,
verify_elvis_attr_private_data_types/1
]).

-if(?OTP_RELEASE >= 27).
-export([
verify_no_single_match_maybe/1
]).
-endif.
%% Non-rule
-export([results_are_ordered_by_line/1, oddities/1]).

Expand Down Expand Up @@ -172,7 +177,6 @@ groups() ->
verify_always_shortcircuit,
verify_no_catch_expressions,
verify_no_single_clause_case,
verify_no_single_match_maybe,
verify_no_macros,
verify_export_used_types,
verify_max_anonymous_function_arity,
Expand Down Expand Up @@ -2261,6 +2265,7 @@ verify_no_single_clause_case(Config) ->
[#{line_num := 6}, #{line_num := 14}, #{line_num := 16}] = R
end.

-if(?OTP_RELEASE >= 27).
-spec verify_no_single_match_maybe(config()) -> any().
verify_no_single_match_maybe(Config) ->
Group = proplists:get_value(group, Config, erl_files),
Expand All @@ -2279,6 +2284,7 @@ verify_no_single_match_maybe(Config) ->
erl_files ->
[#{line_num := 8}, #{line_num := 16}, #{line_num := 17}] = R
end.
-endif.

-spec verify_no_match_in_condition(config()) -> any().
verify_no_match_in_condition(Config) ->
Expand Down