Merge pull request #99 from tuncer/fixes-and-updates

Fixes and updates
This commit is contained in:
Dave Smith 2013-06-25 05:55:26 -07:00
commit 00164b280a
8 changed files with 124 additions and 86 deletions

View file

@ -1,7 +0,0 @@
\.beam
^rebar$
.~
\.orig
\.swp
rt.work/*
^.gitignore$

View file

@ -1 +0,0 @@
e8747041ef63f1b394d3b156c72c5bc12e92ecc4 RELEASE-1

View file

@ -10,6 +10,7 @@ clean:
@rm -rf rebar ebin/*.beam inttest/rt.work rt.work .eunit @rm -rf rebar ebin/*.beam inttest/rt.work rt.work .eunit
distclean: clean distclean: clean
@rm -f dialyzer_warnings
@rm -rf deps @rm -rf deps
debug: debug:

11
THANKS
View file

@ -109,3 +109,14 @@ Daniel White
Martin Schut Martin Schut
Serge Aleynikov Serge Aleynikov
Magnus Henoch Magnus Henoch
Artem Teslenko
Jeremie Lasalle Ratelle
Jose Valim
Krzysztof Rutka
Mats Cronqvist
Matthew Conway
Giacomo Olgeni
Pedram Nimreezi
Sylvain Benner
Oliver Ferrigni
Dave Thomas

View file

@ -209,7 +209,9 @@
{xref_warnings, false}. {xref_warnings, false}.
%% xref checks to run %% xref checks to run
{xref_checks, [exports_not_used, undefined_function_calls]}. {xref_checks, [undefined_function_calls, undefined_functions,
locals_not_used, exports_not_used,
deprecated_function_calls, deprecated_functions]}.
%% Optional custom xref queries (xref manual has details) specified as %% Optional custom xref queries (xref manual has details) specified as
%% {xref_queries, [{query_string(), expected_query_result()},...]} %% {xref_queries, [{query_string(), expected_query_result()},...]}

View file

@ -533,21 +533,7 @@ plugin_modules(Config, PredirsAssoc, FoundModules, MissingModules) ->
load_plugin_modules(Config, PredirsAssoc, Modules) -> load_plugin_modules(Config, PredirsAssoc, Modules) ->
Cwd = rebar_utils:get_cwd(), Cwd = rebar_utils:get_cwd(),
PluginDirs = case rebar_config:get_local(Config, plugin_dir, undefined) of PluginDirs = get_all_plugin_dirs(Config, Cwd, PredirsAssoc),
undefined ->
% Plugin can be in the project's "plugins" folder
[filename:join(Cwd, "plugins")];
Dir ->
[Dir]
end ++
% We also want to include this case:
% Plugin can be in "plugins" directory of the plugin base directory. For
% example, Cwd depends on Plugin, and deps/Plugin/plugins/Plugin.erl is the
% plugin.
[
filename:join(Dir, "plugins") ||
Dir <- get_plugin_base_dirs(Cwd, PredirsAssoc)
],
%% Find relevant sources in base_dir and plugin_dir %% Find relevant sources in base_dir and plugin_dir
Erls = string:join([atom_to_list(M)++"\\.erl" || M <- Modules], "|"), Erls = string:join([atom_to_list(M)++"\\.erl" || M <- Modules], "|"),
@ -562,12 +548,32 @@ load_plugin_modules(Config, PredirsAssoc, Modules) ->
NotLoaded = [V || V <- Modules, FilterMissing(V)], NotLoaded = [V || V <- Modules, FilterMissing(V)],
{Loaded, NotLoaded}. {Loaded, NotLoaded}.
get_all_plugin_dirs(Config, Cwd, PredirsAssoc) ->
get_plugin_dir(Config, Cwd) ++ get_base_plugin_dirs(Cwd, PredirsAssoc).
get_plugin_dir(Config, Cwd) ->
case rebar_config:get_local(Config, plugin_dir, undefined) of
undefined ->
%% Plugin can be in the project's "plugins" folder
[filename:join(Cwd, "plugins")];
Dir ->
[Dir]
end.
%% We also want to include this case:
%% Plugin can be in "plugins" directory of the plugin base directory.
%% For example, Cwd depends on Plugin, and deps/Plugin/plugins/Plugin.erl
%% is the plugin.
get_base_plugin_dirs(Cwd, PredirsAssoc) ->
[filename:join(Dir, "plugins") ||
Dir <- get_plugin_base_dirs(Cwd, PredirsAssoc)].
%% @doc PredirsAssoc is a dictionary of plugindir -> 'parent' pairs %% @doc PredirsAssoc is a dictionary of plugindir -> 'parent' pairs
%% 'parent' in this case depends on plugin; therefore we have to give %% 'parent' in this case depends on plugin; therefore we have to give
%% all plugins that Cwd ('parent' in this case) depends on. %% all plugins that Cwd ('parent' in this case) depends on.
get_plugin_base_dirs(Cwd, PredirsAssoc) -> get_plugin_base_dirs(Cwd, PredirsAssoc) ->
[PluginDir || {PluginDir, Master} <- dict:to_list(PredirsAssoc), [PluginDir || {PluginDir, Master} <- dict:to_list(PredirsAssoc),
Master =:= Cwd]. Master =:= Cwd].
is_missing_plugin(Loaded) -> is_missing_plugin(Loaded) ->
fun(Mod) -> not lists:member(Mod, Loaded) end. fun(Mod) -> not lists:member(Mod, Loaded) end.

View file

@ -108,7 +108,8 @@ run_test(TestDir, LogDir, Config, _File) ->
" 2>&1 | tee -a " ++ RawLog " 2>&1 | tee -a " ++ RawLog
end, end,
case rebar_utils:sh(Cmd ++ Output, [{env,[{"TESTDIR", TestDir}]}, return_on_error]) of ShOpts = [{env,[{"TESTDIR", TestDir}]}, return_on_error],
case rebar_utils:sh(Cmd ++ Output, ShOpts) of
{ok,_} -> {ok,_} ->
%% in older versions of ct_run, this could have been a failure %% in older versions of ct_run, this could have been a failure
%% that returned a non-0 code. Check for that! %% that returned a non-0 code. Check for that!
@ -135,11 +136,16 @@ clear_log(LogDir, RawLog) ->
check_success_log(Config, RawLog) -> check_success_log(Config, RawLog) ->
check_log(Config, RawLog, fun(Msg) -> ?CONSOLE("DONE.\n~s\n", [Msg]) end). check_log(Config, RawLog, fun(Msg) -> ?CONSOLE("DONE.\n~s\n", [Msg]) end).
check_fail_log(Config, RawLog, Command, {Rc, Output}) -> -type err_handler() :: fun((string()) -> no_return()).
check_log(Config, RawLog, fun(_Msg) -> -spec failure_logger(string(), {integer(), string()}) -> err_handler().
failure_logger(Command, {Rc, Output}) ->
fun(_Msg) ->
?ABORT("~s failed with error: ~w and output:~n~s~n", ?ABORT("~s failed with error: ~w and output:~n~s~n",
[Command, Rc, Output]) [Command, Rc, Output])
end). end.
check_fail_log(Config, RawLog, Command, Result) ->
check_log(Config, RawLog, failure_logger(Command, Result)).
check_log(Config,RawLog,Fun) -> check_log(Config,RawLog,Fun) ->
{ok, Msg} = {ok, Msg} =

View file

@ -37,6 +37,9 @@
-export([xref/2]). -export([xref/2]).
%% for internal use only
-export([info/2]).
%% =================================================================== %% ===================================================================
%% Public API %% Public API
%% =================================================================== %% ===================================================================
@ -58,14 +61,15 @@ xref(Config, _) ->
%% Get list of xref checks we want to run %% Get list of xref checks we want to run
ConfXrefChecks = rebar_config:get(Config, xref_checks, ConfXrefChecks = rebar_config:get(Config, xref_checks,
[exports_not_used, [exports_not_used,
undefined_function_calls]), undefined_function_calls]),
SupportedXrefs = [undefined_function_calls, undefined_functions, SupportedXrefs = [undefined_function_calls, undefined_functions,
locals_not_used, exports_not_used, locals_not_used, exports_not_used,
deprecated_function_calls, deprecated_functions], deprecated_function_calls, deprecated_functions],
XrefChecks = sets:to_list(sets:intersection(sets:from_list(SupportedXrefs), XrefChecks = sets:to_list(sets:intersection(
sets:from_list(SupportedXrefs),
sets:from_list(ConfXrefChecks))), sets:from_list(ConfXrefChecks))),
%% Run xref checks %% Run xref checks
@ -92,17 +96,37 @@ xref(Config, _) ->
%% Internal functions %% Internal functions
%% =================================================================== %% ===================================================================
info(help, xref) ->
?CONSOLE(
"Run cross reference analysis.~n"
"~n"
"Valid rebar.config options:~n"
" ~p~n"
" ~p~n"
" ~p~n",
[
{xref_warnings, false},
{xref_checks, [undefined_function_calls, undefined_functions,
locals_not_used, exports_not_used,
deprecated_function_calls, deprecated_functions]},
{xref_queries,
[{"(xc - uc) || (xu - x - b"
" - (\"mod\":\".*foo\"/\"4\"))",[]}]}
]).
xref_checks(XrefChecks) -> xref_checks(XrefChecks) ->
XrefWarnCount = lists:foldl( XrefWarnCount = lists:foldl(fun run_xref_check/2, 0, XrefChecks),
fun(XrefCheck, Acc) ->
{ok, Results} = xref:analyze(xref, XrefCheck),
FilteredResults =filter_xref_results(XrefCheck, Results),
lists:foreach(fun(Res) -> display_xrefresult(XrefCheck, Res) end, FilteredResults),
Acc + length(FilteredResults)
end,
0, XrefChecks),
XrefWarnCount =:= 0. XrefWarnCount =:= 0.
run_xref_check(XrefCheck, Acc) ->
{ok, Results} = xref:analyze(xref, XrefCheck),
FilteredResults =filter_xref_results(XrefCheck, Results),
lists:foreach(fun(Res) ->
display_xref_result(XrefCheck, Res)
end,
FilteredResults),
Acc + length(FilteredResults).
check_query({Query, Value}) -> check_query({Query, Value}) ->
{ok, Answer} = xref:q(xref, Query), {ok, Answer} = xref:q(xref, Query),
case Answer =:= Value of case Answer =:= Value of
@ -141,78 +165,75 @@ get_xref_ignorelist(Mod, XrefCheck) ->
_Class:_Error -> [] _Class:_Error -> []
end, end,
Ignore_xref = keyall(ignore_xref, Attributes), IgnoreXref = keyall(ignore_xref, Attributes),
Behaviour_callbacks = case XrefCheck of BehaviourCallbacks = get_behaviour_callbacks(XrefCheck, Attributes),
exports_not_used -> [B:behaviour_info(callbacks) || B <- keyall(behaviour, Attributes)];
_ -> []
end,
% And create a flat {M,F,A} list %% And create a flat {M,F,A} list
lists:foldl( lists:foldl(
fun(El,Acc) -> fun({F, A}, Acc) -> [{Mod,F,A} | Acc];
case El of ({M, F, A}, Acc) -> [{M,F,A} | Acc]
{F, A} -> [{Mod,F,A} | Acc]; end, [], lists:flatten([IgnoreXref, BehaviourCallbacks])).
{M, F, A} -> [{M,F,A} | Acc]
end
end, [],lists:flatten([Ignore_xref, Behaviour_callbacks])).
keyall(Key, List) -> keyall(Key, List) ->
lists:flatmap(fun({K, L}) when Key =:= K -> L; (_) -> [] end, List). lists:flatmap(fun({K, L}) when Key =:= K -> L; (_) -> [] end, List).
parse_xref_result(XrefResult) -> get_behaviour_callbacks(exports_not_used, Attributes) ->
case XrefResult of [B:behaviour_info(callbacks) || B <- keyall(behaviour, Attributes)];
{_, MFAt} -> MFAt; get_behaviour_callbacks(_XrefCheck, _Attributes) ->
MFAt -> MFAt [].
end.
parse_xref_result({_, MFAt}) -> MFAt;
parse_xref_result(MFAt) -> MFAt.
filter_xref_results(XrefCheck, XrefResults) -> filter_xref_results(XrefCheck, XrefResults) ->
SearchModules = lists:usort(lists:map( SearchModules = lists:usort(
fun(Res) -> lists:map(
case Res of fun({Mt,_Ft,_At}) -> Mt;
{Mt,_Ft,_At} -> Mt; ({{Ms,_Fs,_As},{_Mt,_Ft,_At}}) -> Ms;
{{Ms,_Fs,_As},{_Mt,_Ft,_At}} -> Ms; (_) -> undefined
_ -> undefined end, XrefResults)),
end
end, XrefResults)),
Ignores = lists:flatten([ Ignores = lists:flatmap(fun(Module) ->
get_xref_ignorelist(Module,XrefCheck) || Module <- SearchModules]), get_xref_ignorelist(Module, XrefCheck)
end, SearchModules),
[Result || Result <- XrefResults, [Result || Result <- XrefResults,
not lists:member(parse_xref_result(Result),Ignores)]. not lists:member(parse_xref_result(Result), Ignores)].
display_xrefresult(Type, XrefResult) -> display_xref_result(Type, XrefResult) ->
{ Source, SMFA, TMFA } = case XrefResult of { Source, SMFA, TMFA } = case XrefResult of
{MFASource, MFATarget} -> {MFASource, MFATarget} ->
{format_mfa_source(MFASource), format_mfa(MFASource), {format_mfa_source(MFASource),
format_mfa(MFATarget)}; format_mfa(MFASource),
MFATarget -> format_mfa(MFATarget)};
{format_mfa_source(MFATarget), format_mfa(MFATarget), MFATarget ->
undefined} {format_mfa_source(MFATarget),
end, format_mfa(MFATarget),
undefined}
end,
case Type of case Type of
undefined_function_calls -> undefined_function_calls ->
?CONSOLE("~sWarning: ~s calls undefined function ~s (Xref)\n", ?CONSOLE("~sWarning: ~s calls undefined function ~s (Xref)\n",
[Source, SMFA, TMFA]); [Source, SMFA, TMFA]);
undefined_functions -> undefined_functions ->
?CONSOLE("~sWarning: ~s is undefined function (Xref)\n", ?CONSOLE("~sWarning: ~s is undefined function (Xref)\n",
[Source, SMFA]); [Source, SMFA]);
locals_not_used -> locals_not_used ->
?CONSOLE("~sWarning: ~s is unused local function (Xref)\n", ?CONSOLE("~sWarning: ~s is unused local function (Xref)\n",
[Source, SMFA]); [Source, SMFA]);
exports_not_used -> exports_not_used ->
?CONSOLE("~sWarning: ~s is unused export (Xref)\n", ?CONSOLE("~sWarning: ~s is unused export (Xref)\n",
[Source, SMFA]); [Source, SMFA]);
deprecated_function_calls -> deprecated_function_calls ->
?CONSOLE("~sWarning: ~s calls deprecated function ~s (Xref)\n", ?CONSOLE("~sWarning: ~s calls deprecated function ~s (Xref)\n",
[Source, SMFA, TMFA]); [Source, SMFA, TMFA]);
deprecated_functions -> deprecated_functions ->
?CONSOLE("~sWarning: ~s is deprecated function (Xref)\n", ?CONSOLE("~sWarning: ~s is deprecated function (Xref)\n",
[Source, SMFA]); [Source, SMFA]);
Other -> Other ->
?CONSOLE("~sWarning: ~s - ~s xref check: ~s (Xref)\n", ?CONSOLE("~sWarning: ~s - ~s xref check: ~s (Xref)\n",
[Source, SMFA, TMFA, Other]) [Source, SMFA, TMFA, Other])
end. end.
format_mfa({M, F, A}) -> format_mfa({M, F, A}) ->
@ -236,7 +257,6 @@ safe_element(N, Tuple) ->
Value Value
end. end.
%% %%
%% Given a MFA, find the file and LOC where it's defined. Note that %% Given a MFA, find the file and LOC where it's defined. Note that
%% xref doesn't work if there is no abstract_code, so we can avoid %% xref doesn't work if there is no abstract_code, so we can avoid