inaka / elvis_core

The core of an Erlang linter
Other
61 stars 56 forks source link

There are instances where not exporting a type is valid, even if it's used in a spec. #308

Open elbrujohalcon opened 1 year ago

elbrujohalcon commented 1 year ago

Bug Description

In the module I'm showing below, Elvis will ask me to export the state/0 type. That's not a good idea.

To Reproduce

Run Elvis on this module:

-module(x).

-behaviour(gen_server).

-record(state, {a = field}).

-type state() :: #state{}.

-export([init/1, handle_cast/2]).

-spec init(_) -> {ok, state()}.
init(_) -> {ok, #state{}}.

-spec handle_cast(_, state()) -> {noreply, state()}.
handle_cast(_, State) -> {noreply, State}.

You'll get…

# src/x.erl [FAIL]
  - export_used_types (https://github.com/inaka/elvis_core/tree/main/doc_rules/elvis_style/export_used_types.md)
    - Type state/0, defined on line 7, is used by an exported function but not exported itself

Expected Behavior

No warnings.

Proposed Solution

We already faced a similar issue in rebar3_hank. Until erlang/otp#4847 is dealt with and we get the ability to specify dynamic callbacks, Elvis should avoid emitting this type of warning for types used in exported functions of modules implementing a behavior. It may be slightly smarter and (just like hank) use the fact that some behaviors (like gen_server) are well-known and they don't have dynamic callbacks.