rebar_xref: regression fixes and updates for a5be40c96

- restore support for "rebar help xref"
- update rebar.config.sample
- update 'help xref' string
- simplify new/changed functions by breaking out code or
  using simpler syntax where applicable
This commit is contained in:
Tuncer Ayaz 2013-06-18 11:30:32 +02:00
parent bdf957b201
commit 09cd4e9be2
2 changed files with 80 additions and 58 deletions

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

@ -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