eproxus / meck

A mocking library for Erlang
http://eproxus.github.io/meck
Apache License 2.0
811 stars 231 forks source link

Module references in typespecs are not included when renaming modules #206

Closed jesperes closed 3 years ago

jesperes commented 4 years ago

Module references in typespecs are not included when renaming modules. This causes problems with OTP 22, as specs referencing functions in other modules are no longer permitted. See e.g. OTP-15563 in http://erlang.org/download/otp_src_22.0.readme:

OTP-15563    Application(s): compiler, stdlib
               Related Id(s): ERL-845, OTP-15562

               Do not allow function specifications for functions
               residing in other modules.

Reproduction Steps

  1. Given the following module:

    -module(foo).
    -export([bar/0]).
    -spec ?MODULE:bar() -> ok.
    bar() -> ok.
  2. Compile foo.erl with erlc +debug_info foo.erl

  3. Start an Erlang shell and call mock:new(foo, [passthrough])

Expected behavior

mock:new/2 should return ok.

Observed behavior

mock:new/2 throws an exception:

** exception error: {compile_forms,{error,[{"foo.erl",
                                            [{4,erl_lint,{bad_module,{foo,main,0}}}]}],
                                          []}}
     in function  meck_proc:start/2
        called as meck_proc:start(foo,[passthrough])

Versions

jesperes commented 4 years ago

The problem is in meck_code:rename_module/2 which only modifieds the module attribute, and ignores any typespecs found in the file:

-spec rename_module(erlang_form(), module()) -> erlang_form().
rename_module([{attribute, Line, module, OldAttribute}|T], NewName) ->
    case OldAttribute of
        {_OldName, Variables} ->
            [{attribute, Line, module, {NewName, Variables}}|T];
        _OldName ->
            [{attribute, Line, module, NewName}|T]
    end;
rename_module([H|T], NewName) ->
    [H|rename_module(T, NewName)].
eproxus commented 4 years ago

Thanks for the pointer! I'll take a look at as soon as I can.