diff options
author | Fred Hebert <mononcqc@ferd.ca> | 2017-06-13 15:16:55 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-13 15:16:55 -0400 |
commit | 21a121fa669efb1463ad9160375e715557d83749 (patch) | |
tree | 16908378472fc97530593b0e6b63bc4807b2a5ea | |
parent | 9b1aa9191027647eb370eb6b0d5fa9cbfacc21d4 (diff) | |
parent | 7f1301f635b8c07fd22ffdf1c9dcf6f5cbba8655 (diff) |
Merge pull request #1572 from ferd/fix-xref-undef-behaviour
Prevent xref crashes with undef behaviours
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | src/rebar_prv_xref.erl | 11 | ||||
-rw-r--r-- | test/rebar_xref_SUITE.erl | 46 |
3 files changed, 54 insertions, 4 deletions
@@ -1,6 +1,7 @@ _checkouts .rebar3 rebar3 +rebar3.cmd _build .depsolver_plt *.beam diff --git a/src/rebar_prv_xref.erl b/src/rebar_prv_xref.erl index 51154b5..e6a074f 100644 --- a/src/rebar_prv_xref.erl +++ b/src/rebar_prv_xref.erl @@ -168,8 +168,15 @@ keyall(Key, List) -> lists:flatmap(fun({K, L}) when Key =:= K -> L; (_) -> [] end, List). get_behaviour_callbacks(exports_not_used, Attributes) -> - [B:behaviour_info(callbacks) || B <- keyall(behaviour, Attributes) ++ - keyall(behavior, Attributes)]; + lists:map(fun(Mod) -> + try + Mod:behaviour_info(callbacks) + catch + error:undef -> + ?WARN("Behaviour ~p is used but cannot be found.", [Mod]), + [] + end + end, keyall(behaviour, Attributes) ++ keyall(behavior, Attributes)); get_behaviour_callbacks(_XrefCheck, _Attributes) -> []. diff --git a/test/rebar_xref_SUITE.erl b/test/rebar_xref_SUITE.erl index d1c071b..f052fa4 100644 --- a/test/rebar_xref_SUITE.erl +++ b/test/rebar_xref_SUITE.erl @@ -10,7 +10,8 @@ all/0, xref_test/1, xref_ignore_test/1, - xref_dep_hook/1]). + xref_dep_hook/1, + xref_undef_behaviour/1]). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -58,7 +59,7 @@ end_per_testcase(_, _Config) -> ok. all() -> - [xref_test, xref_ignore_test, xref_dep_hook]. + [xref_test, xref_ignore_test, xref_dep_hook, xref_undef_behaviour]. %% =================================================================== %% Test cases @@ -83,6 +84,18 @@ xref_ignore_test(Config) -> xref_dep_hook(Config) -> rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, []}). +xref_undef_behaviour(Config) -> + AppDir = ?config(apps, Config), + State = ?config(state, Config), + Name = ?config(app_name, Config), + RebarConfig = ?config(rebar_config, Config), + %% delete one of the behaviours, which should create new warnings + delete_src_file(AppDir, Name, behaviour1), + %% just ensure this does not crash + Result = rebar3:run(rebar_state:new(State, RebarConfig, AppDir), ["xref"]), + verify_results(xref_undef_behaviour, Name, Result). + + %% =================================================================== %% Helper functions %% =================================================================== @@ -123,6 +136,31 @@ verify_test_results(xref_test, AppName, XrefResults, _QueryResults) -> ?assertNot(lists:member({MyMod, bh2_a, 1}, ExportsNotUsed)), ?assertNot(lists:member({MyMod, bh2_b, 1}, ExportsNotUsed)), ok; +verify_test_results(xref_undef_behaviour, AppName, XrefResults, _QueryResults) -> + AppModules = ["behaviour2", "mymod", "othermod", "somemod"], + [Behaviour2Mod, MyMod, OtherMod, SomeMod] = + [list_to_atom(AppName ++ "_" ++ Mod) || Mod <- AppModules], + UndefFuns = proplists:get_value(undefined_functions, XrefResults), + UndefFunCalls = proplists:get_value(undefined_function_calls, XrefResults), + LocalsNotUsed = proplists:get_value(locals_not_used, XrefResults), + ExportsNotUsed = proplists:get_value(exports_not_used, XrefResults), + DeprecatedFuns = proplists:get_value(deprecated_functions, XrefResults), + DeprecatedFunCalls = proplists:get_value(deprecated_function_calls, XrefResults), + ?assert(lists:member({SomeMod, notavailable, 1}, UndefFuns)), + ?assert(lists:member({{OtherMod, somefunc, 0}, {SomeMod, notavailable, 1}}, + UndefFunCalls)), + ?assert(lists:member({MyMod, fdeprecated, 0}, DeprecatedFuns)), + ?assert(lists:member({{OtherMod, somefunc, 0}, {MyMod, fdeprecated, 0}}, + DeprecatedFunCalls)), + ?assert(lists:member({MyMod, localfunc2, 0}, LocalsNotUsed)), + ?assert(lists:member({Behaviour2Mod, behaviour_info, 1}, ExportsNotUsed)), + ?assert(lists:member({MyMod, other2, 1}, ExportsNotUsed)), + ?assert(lists:member({OtherMod, somefunc, 0}, ExportsNotUsed)), + ?assert(lists:member({MyMod, bh1_a, 1}, ExportsNotUsed)), + ?assert(lists:member({MyMod, bh1_b, 1}, ExportsNotUsed)), + ?assertNot(lists:member({MyMod, bh2_a, 1}, ExportsNotUsed)), + ?assertNot(lists:member({MyMod, bh2_b, 1}, ExportsNotUsed)), + ok; verify_test_results(xref_ignore_test, AppName, XrefResults, _QueryResults) -> AppModules = ["behaviour1", "behaviour2", "mymod", "othermod", "somemod"], [_Behaviour1Mod, _Behaviour2Mod, _MyMod, _OtherMod, SomeMod] = @@ -141,6 +179,10 @@ write_src_file(Dir, AppName, Module, IgnoreXref) -> ok = filelib:ensure_dir(Erl), ok = ec_file:write(Erl, get_module_body(Module, AppName, IgnoreXref)). +delete_src_file(Dir, AppName, Module) -> + Erl = filename:join([Dir, "src", module_name(AppName, Module)]), + ok = file:delete(Erl). + module_name(AppName, Module) -> lists:flatten([AppName, "_", atom_to_list(Module), ".erl"]). |