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
distclean: clean
@rm -f dialyzer_warnings
@rm -rf deps
debug:

11
THANKS
View file

@ -109,3 +109,14 @@ Daniel White
Martin Schut
Serge Aleynikov
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 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
%% {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) ->
Cwd = rebar_utils:get_cwd(),
PluginDirs = 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.
[
filename:join(Dir, "plugins") ||
Dir <- get_plugin_base_dirs(Cwd, PredirsAssoc)
],
PluginDirs = get_all_plugin_dirs(Config, Cwd, PredirsAssoc),
%% Find relevant sources in base_dir and plugin_dir
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)],
{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
%% 'parent' in this case depends on plugin; therefore we have to give
%% all plugins that Cwd ('parent' in this case) depends on.
get_plugin_base_dirs(Cwd, PredirsAssoc) ->
[PluginDir || {PluginDir, Master} <- dict:to_list(PredirsAssoc),
Master =:= Cwd].
Master =:= Cwd].
is_missing_plugin(Loaded) ->
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
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,_} ->
%% in older versions of ct_run, this could have been a failure
%% that returned a non-0 code. Check for that!
@ -135,11 +136,16 @@ clear_log(LogDir, RawLog) ->
check_success_log(Config, RawLog) ->
check_log(Config, RawLog, fun(Msg) -> ?CONSOLE("DONE.\n~s\n", [Msg]) end).
check_fail_log(Config, RawLog, Command, {Rc, Output}) ->
check_log(Config, RawLog, fun(_Msg) ->
-type err_handler() :: fun((string()) -> no_return()).
-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",
[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) ->
{ok, Msg} =

View file

@ -37,6 +37,9 @@
-export([xref/2]).
%% for internal use only
-export([info/2]).
%% ===================================================================
%% Public API
%% ===================================================================
@ -58,14 +61,15 @@ xref(Config, _) ->
%% Get list of xref checks we want to run
ConfXrefChecks = rebar_config:get(Config, xref_checks,
[exports_not_used,
undefined_function_calls]),
[exports_not_used,
undefined_function_calls]),
SupportedXrefs = [undefined_function_calls, undefined_functions,
locals_not_used, exports_not_used,
deprecated_function_calls, deprecated_functions],
locals_not_used, exports_not_used,
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))),
%% Run xref checks
@ -92,17 +96,37 @@ xref(Config, _) ->
%% 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) ->
XrefWarnCount = lists:foldl(
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 = lists:foldl(fun run_xref_check/2, 0, XrefChecks),
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}) ->
{ok, Answer} = xref:q(xref, Query),
case Answer =:= Value of
@ -141,78 +165,75 @@ get_xref_ignorelist(Mod, XrefCheck) ->
_Class:_Error -> []
end,
Ignore_xref = keyall(ignore_xref, Attributes),
IgnoreXref = keyall(ignore_xref, Attributes),
Behaviour_callbacks = case XrefCheck of
exports_not_used -> [B:behaviour_info(callbacks) || B <- keyall(behaviour, Attributes)];
_ -> []
end,
BehaviourCallbacks = get_behaviour_callbacks(XrefCheck, Attributes),
% And create a flat {M,F,A} list
%% And create a flat {M,F,A} list
lists:foldl(
fun(El,Acc) ->
case El of
{F, A} -> [{Mod,F,A} | Acc];
{M, F, A} -> [{M,F,A} | Acc]
end
end, [],lists:flatten([Ignore_xref, Behaviour_callbacks])).
fun({F, A}, Acc) -> [{Mod,F,A} | Acc];
({M, F, A}, Acc) -> [{M,F,A} | Acc]
end, [], lists:flatten([IgnoreXref, BehaviourCallbacks])).
keyall(Key, List) ->
lists:flatmap(fun({K, L}) when Key =:= K -> L; (_) -> [] end, List).
parse_xref_result(XrefResult) ->
case XrefResult of
{_, MFAt} -> MFAt;
MFAt -> MFAt
end.
get_behaviour_callbacks(exports_not_used, Attributes) ->
[B:behaviour_info(callbacks) || B <- keyall(behaviour, Attributes)];
get_behaviour_callbacks(_XrefCheck, _Attributes) ->
[].
parse_xref_result({_, MFAt}) -> MFAt;
parse_xref_result(MFAt) -> MFAt.
filter_xref_results(XrefCheck, XrefResults) ->
SearchModules = lists:usort(lists:map(
fun(Res) ->
case Res of
{Mt,_Ft,_At} -> Mt;
{{Ms,_Fs,_As},{_Mt,_Ft,_At}} -> Ms;
_ -> undefined
end
end, XrefResults)),
SearchModules = lists:usort(
lists:map(
fun({Mt,_Ft,_At}) -> Mt;
({{Ms,_Fs,_As},{_Mt,_Ft,_At}}) -> Ms;
(_) -> undefined
end, XrefResults)),
Ignores = lists:flatten([
get_xref_ignorelist(Module,XrefCheck) || Module <- SearchModules]),
Ignores = lists:flatmap(fun(Module) ->
get_xref_ignorelist(Module, XrefCheck)
end, SearchModules),
[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
{MFASource, MFATarget} ->
{format_mfa_source(MFASource), format_mfa(MFASource),
format_mfa(MFATarget)};
MFATarget ->
{format_mfa_source(MFATarget), format_mfa(MFATarget),
undefined}
end,
{MFASource, MFATarget} ->
{format_mfa_source(MFASource),
format_mfa(MFASource),
format_mfa(MFATarget)};
MFATarget ->
{format_mfa_source(MFATarget),
format_mfa(MFATarget),
undefined}
end,
case Type of
undefined_function_calls ->
?CONSOLE("~sWarning: ~s calls undefined function ~s (Xref)\n",
[Source, SMFA, TMFA]);
[Source, SMFA, TMFA]);
undefined_functions ->
?CONSOLE("~sWarning: ~s is undefined function (Xref)\n",
[Source, SMFA]);
[Source, SMFA]);
locals_not_used ->
?CONSOLE("~sWarning: ~s is unused local function (Xref)\n",
[Source, SMFA]);
[Source, SMFA]);
exports_not_used ->
?CONSOLE("~sWarning: ~s is unused export (Xref)\n",
[Source, SMFA]);
[Source, SMFA]);
deprecated_function_calls ->
?CONSOLE("~sWarning: ~s calls deprecated function ~s (Xref)\n",
[Source, SMFA, TMFA]);
[Source, SMFA, TMFA]);
deprecated_functions ->
?CONSOLE("~sWarning: ~s is deprecated function (Xref)\n",
[Source, SMFA]);
[Source, SMFA]);
Other ->
?CONSOLE("~sWarning: ~s - ~s xref check: ~s (Xref)\n",
[Source, SMFA, TMFA, Other])
[Source, SMFA, TMFA, Other])
end.
format_mfa({M, F, A}) ->
@ -236,7 +257,6 @@ safe_element(N, Tuple) ->
Value
end.
%%
%% 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