From 09498c5191d5c1d2df52e35679a0cede9289a185 Mon Sep 17 00:00:00 2001 From: Anton Thomasson Date: Fri, 3 Nov 2023 16:48:30 +0100 Subject: [PATCH] Add wildcard support in no_call_functions --- doc_rules/elvis_style/no_call.md | 4 +++- src/elvis_style.erl | 22 ++++++++++++++-------- test/style_SUITE.erl | 4 +++- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/doc_rules/elvis_style/no_call.md b/doc_rules/elvis_style/no_call.md index f7ef14f2..4fc4d593 100644 --- a/doc_rules/elvis_style/no_call.md +++ b/doc_rules/elvis_style/no_call.md @@ -15,9 +15,11 @@ functions). ## Options -- `no_call_functions :: [{module(), function(), arity()} | {module(), function()}]`. +- `no_call_functions :: [{module() | '_', function() | '_', arity() | '_'} | {module() | '_', function() | '_'}]`. - default: `[]`. +`'_'` wildcards supported since [3.2.0](https://github.com/inaka/elvis_core/releases/tag/3.2.0) + ## Example ```erlang diff --git a/src/elvis_style.erl b/src/elvis_style.erl index 11fbcf1d..23b0eb02 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -1935,20 +1935,20 @@ no_call_common(Config, Target, NoCallFuns, Msg, RuleConfig) -> -spec check_no_call([ktn_code:tree_node()], string(), [function_spec()]) -> [elvis_result:item()]. check_no_call(Calls, Msg, NoCallFuns) -> - DebugCalls = [Call || Call <- Calls, is_in_call_list(Call, NoCallFuns)], + BadCalls = [Call || Call <- Calls, is_in_call_list(Call, NoCallFuns)], ResultFun = fun(Call) -> {M, F, A} = call_mfa(Call), {Line, _} = ktn_code:attr(location, Call), elvis_result:new(item, Msg, [M, F, A, Line], Line) end, - lists:map(ResultFun, DebugCalls). + lists:map(ResultFun, BadCalls). %% @private -is_in_call_list(Call, DebugFuns) -> +is_in_call_list(Call, DisallowedFuns) -> MFA = call_mfa(Call), MatchFun = fun(Spec) -> fun_spec_match(Spec, MFA) end, - lists:any(MatchFun, DebugFuns). + lists:any(MatchFun, DisallowedFuns). %% @private call_mfa(Call) -> @@ -1971,13 +1971,19 @@ is_call(Node) -> ktn_code:type(Node) =:= call. %% @private -fun_spec_match({M, F}, {M, F, _}) -> - true; -fun_spec_match({M, F, A}, {M, F, A}) -> - true; +fun_spec_match({M, F}, MFA) -> + fun_spec_match({M, F, '_'}, MFA); +fun_spec_match({M1, F1, A1}, {M2, F2, A2}) -> + wildcard_match(M1, M2) andalso wildcard_match(F1, F2) andalso wildcard_match(A1, A2); fun_spec_match(_, _) -> false. +%% @private +wildcard_match('_', _) -> + true; +wildcard_match(X, Y) -> + X =:= Y. + %% @private %% @doc No nested try...catch blocks check_nested_try_catchs(ResultFun, TryExp) -> diff --git a/test/style_SUITE.erl b/test/style_SUITE.erl index fbfb73cf..8d5148e5 100644 --- a/test/style_SUITE.erl +++ b/test/style_SUITE.erl @@ -1198,7 +1198,9 @@ verify_no_call_flavours(Config, {{timer, send_interval, 2}, 1}, {{timer, send_interval, 3}, 1}, {{erlang, size, 1}, 2}, - {{timer, send_after}, 2}], + {{timer, send_after}, 2}, + {{timer, '_', '_'}, 4}, + {{'_', tuple_size, 1}, 1}], lists:foreach(fun({FunSpec, ExpectedCount}) -> ThisRuleConfig = maps:from_list([{RuleConfigMapKey, [FunSpec]}]),