diff --git a/src/elvis_style.erl b/src/elvis_style.erl index efa6e197..b83e1586 100644 --- a/src/elvis_style.erl +++ b/src/elvis_style.erl @@ -1460,13 +1460,15 @@ always_shortcircuit(Config, Target, RuleConfig) -> [elvis_result:item()]. export_used_types(Config, Target, RuleConfig) -> TreeRootNode = get_root(Config, Target, RuleConfig), + IgnoredFunctions = get_behaviour_callbacks(TreeRootNode), ExportedFunctions = elvis_code:exported_functions(TreeRootNode), + FilteredExportedFunctions = lists:subtract(ExportedFunctions, IgnoredFunctions), ExportedTypes = elvis_code:exported_types(TreeRootNode), SpecNodes = elvis_code:find(fun is_spec_attribute/1, TreeRootNode, #{traverse => all, mode => node}), ExportedSpecs = lists:filter(fun(#{attrs := #{arity := Arity, name := Name}}) -> - lists:member({Name, Arity}, ExportedFunctions) + lists:member({Name, Arity}, FilteredExportedFunctions) end, SpecNodes), UsedTypes = @@ -1492,6 +1494,20 @@ export_used_types(Config, Target, RuleConfig) -> end, UnexportedUsedTypes). +get_behaviour_callbacks(Root) -> + IsBehaviour = fun(Node) -> ktn_code:type(Node) == behaviour end, + Behaviours = elvis_code:find(IsBehaviour, Root), + BehaviourNames = + lists:map(fun(#{attrs := #{value := Behaviour}}) -> Behaviour end, Behaviours), + + try lists:map(fun(B) -> apply(B, behaviour_info, [callbacks]) end, BehaviourNames) of + DeepList -> + lists:append(DeepList) + catch + _:_ -> + [] + end. + get_type_of_type(#{type := type_attr, node_attrs := #{type := #{attrs := #{name := TypeOfType}}}}) -> TypeOfType; diff --git a/test/examples/pass_export_used_types2.erl b/test/examples/pass_export_used_types2.erl new file mode 100644 index 00000000..cf7afe72 --- /dev/null +++ b/test/examples/pass_export_used_types2.erl @@ -0,0 +1,17 @@ +-module(pass_export_used_types2). + +-behaviour(gen_server). + +-record(state, {a = field}). + +-type state() :: #state{}. + +-export([init/1, handle_cast/2, handle_call/3]). + +-spec init(_) -> {ok, state()}. +init(_) -> {ok, #state{}}. + +handle_call(_, _, State) -> {State, ok, State}. + +-spec handle_cast(_, state()) -> {noreply, state()}. +handle_cast(_, State) -> {noreply, State}. diff --git a/test/style_SUITE.erl b/test/style_SUITE.erl index d6aa6126..1a0ab141 100644 --- a/test/style_SUITE.erl +++ b/test/style_SUITE.erl @@ -753,8 +753,7 @@ verify_state_record_and_type_plus_export_used_types(Config) -> elvis_core_apply_rule(Config, elvis_style, export_used_types, #{}, PathPassGenStateM), PathFail = "fail_state_record_and_type_plus_export_used_types." ++ Ext, - [] = elvis_core_apply_rule(Config, elvis_style, state_record_and_type, #{}, PathFail), - [_] = elvis_core_apply_rule(Config, elvis_style, export_used_types, #{}, PathFail). + [] = elvis_core_apply_rule(Config, elvis_style, state_record_and_type, #{}, PathFail). -spec verify_behaviour_spelling(config()) -> any(). verify_behaviour_spelling(Config) -> @@ -1754,6 +1753,9 @@ verify_export_used_types(Config) -> PathPass = "pass_export_used_types." ++ Ext, [] = elvis_core_apply_rule(Config, elvis_style, export_used_types, #{}, PathPass), + PathPass2 = "pass_export_used_types2." ++ Ext, + [] = elvis_core_apply_rule(Config, elvis_style, export_used_types, #{}, PathPass2), + PathFail = "fail_export_used_types." ++ Ext, [#{line_num := 3}] = elvis_core_apply_rule(Config, elvis_style, export_used_types, #{}, PathFail).