Remove file committed by mistake
This commit is contained in:
parent
34920eb467
commit
3ea11105b4
@ -1,214 +0,0 @@
|
|||||||
-module(aeso_code_analysis).
|
|
||||||
|
|
||||||
-export([analyze/1]).
|
|
||||||
|
|
||||||
%-record(env, {vars = [] :: list()}).
|
|
||||||
%
|
|
||||||
%-type env() :: #env{}.
|
|
||||||
|
|
||||||
-record(analysis,
|
|
||||||
{ defined_types = sets:new() :: sets:set()
|
|
||||||
, defined_funs = sets:new() :: sets:set()
|
|
||||||
, used_types = sets:new() :: sets:set()
|
|
||||||
, used_funs = sets:new() :: sets:set()
|
|
||||||
, used_includes = sets:new() :: sets:set()
|
|
||||||
, unused_stateful = sets:new() :: sets:set()
|
|
||||||
%, used_vars = [] :: list()
|
|
||||||
%, defined_vars = [] :: list()
|
|
||||||
%, used_consts = [] :: list()
|
|
||||||
%, shadowing_pairs = [] :: list()
|
|
||||||
%, unused_retval = [] :: list()
|
|
||||||
}).
|
|
||||||
|
|
||||||
%-type analysis() :: #analysis{}.
|
|
||||||
|
|
||||||
-define(P(X), io:format(??X ++ ":\n~p\n", [X])).
|
|
||||||
|
|
||||||
-record(alg,
|
|
||||||
{ zero :: A
|
|
||||||
, plus :: fun((A, A) -> A)
|
|
||||||
, scoped :: fun((A, A) -> A) }).
|
|
||||||
|
|
||||||
work(expr, X = {qid, Ann, Fun}) ->
|
|
||||||
?P(X),
|
|
||||||
?P(aeso_syntax:get_ann(stateful, Ann, none)),
|
|
||||||
?P(""),
|
|
||||||
#analysis{used_funs = sets:from_list([Fun])};
|
|
||||||
work(type, {qid, _, Type}) ->
|
|
||||||
#analysis{used_types = sets:from_list([Type])};
|
|
||||||
work(bind_type, {id, _, Type}) ->
|
|
||||||
#analysis{defined_types = sets:from_list([Type])};
|
|
||||||
work(_, _) ->
|
|
||||||
#analysis{}.
|
|
||||||
|
|
||||||
-spec analyze(aeso_syntax:ast()) -> ok.
|
|
||||||
analyze([{Contract, _Ann, {con, _, _ConName}, _Impls, Decls} | Rest])
|
|
||||||
when Contract == contract_main;
|
|
||||||
Contract == contract_child ->
|
|
||||||
analyze_contract(Decls),
|
|
||||||
analyze(Rest);
|
|
||||||
analyze([{namespace, _Ann, {con, _, _NSName}, Decls} | Rest]) ->
|
|
||||||
analyze_contract(Decls),
|
|
||||||
analyze(Rest);
|
|
||||||
analyze([]) ->
|
|
||||||
error("End of code analysis").
|
|
||||||
|
|
||||||
analyze_contract(Decls) ->
|
|
||||||
Funs = [ Fun || Fun = {letfun, _, _, _, _, _} <- Decls],
|
|
||||||
_Types = [ Def || Def = {type_def, _, _, _, _} <- Decls ],
|
|
||||||
_Consts = [ Const || Const = {letval, _, _, _} <- Decls ],
|
|
||||||
|
|
||||||
Alg =
|
|
||||||
#alg{ zero = #analysis{}
|
|
||||||
, plus = fun merge/2
|
|
||||||
, scoped = fun merge/2 },
|
|
||||||
Res0 = aeso_syntax_utils:fold(
|
|
||||||
Alg,
|
|
||||||
fun work/2,
|
|
||||||
decl,
|
|
||||||
Decls),
|
|
||||||
Res = merge(Res0, #analysis{defined_funs = Funs}),
|
|
||||||
UsedTypes = sets:to_list(Res#analysis.used_types),
|
|
||||||
UsedFuns = sets:to_list(Res#analysis.used_funs),
|
|
||||||
?P(UsedFuns),
|
|
||||||
?P(UsedTypes),
|
|
||||||
|
|
||||||
%Res = [ {Name, analyze_fun(Fun)} || Fun = {letfun, _, {id, _, Name}, _, _, _} <- Funs ],
|
|
||||||
|
|
||||||
?P(Res).
|
|
||||||
%
|
|
||||||
%analyze_fun({letfun, _, _FunId, _Args, _, GuardedBodies}) ->
|
|
||||||
% lists:foldl(fun merge/2, #analysis{}, [(analyze_expr(#env{}, Body)) || {guarded, _, _, Body} <- GuardedBodies ]).
|
|
||||||
%
|
|
||||||
%-spec analyze_expr(env(), aeso_syntax:expr()) -> analysis().
|
|
||||||
%analyze_expr(Env, {lam, _, Args, Expr}) ->
|
|
||||||
% NewVars = [ Id || {arg, _, Id, _} <- Args ],
|
|
||||||
% Env1 = lists:foldl(fun bind_var/2, Env, NewVars),
|
|
||||||
% Analysis = analyze_expr(Env1, Expr),
|
|
||||||
% Analysis#analysis{defined_vars = Analysis#analysis.defined_vars ++ NewVars};
|
|
||||||
%%analyze_expr(Env, {'if', ann(), expr(), expr(), expr()}) ->
|
|
||||||
%% ok;
|
|
||||||
%%analyze_expr(Env, {switch, ann(), expr(), [alt()]}) ->
|
|
||||||
%% ok;
|
|
||||||
%analyze_expr(Env, {app, _, Expr, _Args}) ->
|
|
||||||
% analyze_expr(Env, Expr);
|
|
||||||
%%analyze_expr(Env, {proj, ann(), expr(), id()}) ->
|
|
||||||
%% ok;
|
|
||||||
%analyze_expr(Env, {tuple, _, Exprs}) ->
|
|
||||||
% lists:foldl(fun merge/2, #analysis{}, [ analyze_expr(Env, Expr) || Expr <- Exprs ]);
|
|
||||||
%%analyze_expr(Env, {list, ann(), [expr()]}) ->
|
|
||||||
%% ok;
|
|
||||||
%%analyze_expr(Env, {list_comp, ann(), expr(), [comprehension_exp()]}) ->
|
|
||||||
%% ok;
|
|
||||||
%analyze_expr(Env, {typed, _, Expr, Type}) ->
|
|
||||||
% merge(analyze_expr(Env, Expr), analyze_type(Env, Type));
|
|
||||||
%%analyze_expr(Env, {record_or_map(), ann(), [field(expr())]}) ->
|
|
||||||
%% ok;
|
|
||||||
%%analyze_expr(Env, {record_or_map(), ann(), expr(), [field(expr())]}) ->
|
|
||||||
%% ok;
|
|
||||||
%%analyze_expr(Env, {map, ann(), [{expr(), expr()}]}) ->
|
|
||||||
%% ok;
|
|
||||||
%%analyze_expr(Env, {map_get, ann(), expr(), expr()}) ->
|
|
||||||
%% ok;
|
|
||||||
%%analyze_expr(Env, {map_get, ann(), expr(), expr(), expr()}) ->
|
|
||||||
%% ok;
|
|
||||||
%analyze_expr(Env, {block, _, Stmts}) ->
|
|
||||||
% analyze_block(Env, Stmts);
|
|
||||||
%%analyze_expr(Env, {op(), ann()}) ->
|
|
||||||
%% ok;
|
|
||||||
%analyze_expr(_Env, {int, _, _}) ->
|
|
||||||
% #analysis{};
|
|
||||||
%analyze_expr(Env, Id = {id, _, _}) ->
|
|
||||||
% #analysis{used_vars = [lookup_var(Id, Env)]};
|
|
||||||
%analyze_expr(_Env, {qcon, _, _}) ->
|
|
||||||
% #analysis{}.
|
|
||||||
%%analyze_expr(Env, QId = {qid, _, _}) ->
|
|
||||||
%% #analysis{used_funs = lookup_fun(QId, Env)}.
|
|
||||||
%%analyze_expr(Env, qid() | con() | qcon()) ->
|
|
||||||
%% ok;
|
|
||||||
%%analyze_expr(Env, constant()) ->
|
|
||||||
%% ok;
|
|
||||||
%%analyze_expr(Env, letpat()) ->
|
|
||||||
%% ok.
|
|
||||||
%
|
|
||||||
%analyze_block(_Env, []) ->
|
|
||||||
% #analysis{};
|
|
||||||
%analyze_block(Env, [E]) ->
|
|
||||||
% analyze_expr(Env, E);
|
|
||||||
%analyze_block(Env, [{letval, _, {typed, _, Id = {id, _, _}, _}, Expr} | Stmts]) ->
|
|
||||||
% Env1 = bind_var(Id, Env),
|
|
||||||
% Analysis = analyze_block(Env1, Stmts),
|
|
||||||
% Analysis2 = merge(Analysis, analyze_expr(Env1, Expr)),
|
|
||||||
% Analysis2#analysis{defined_vars = Analysis2#analysis.defined_vars ++ [Id]}.
|
|
||||||
%
|
|
||||||
%analyze_type(_Env, {id, _, Id}) ->
|
|
||||||
% #analysis{used_types = [Id]};
|
|
||||||
%analyze_type(_Env, {qid, _, QId}) ->
|
|
||||||
% #analysis{used_types = [QId]};
|
|
||||||
%analyze_type(Env, {fun_t, _, _, Types, Type}) ->
|
|
||||||
% merge(lists:foldl(fun merge/2, #analysis{}, [analyze_type(Env, T) || T <- Types]), analyze_type(Env, Type));
|
|
||||||
%analyze_type(_Env, {tuple_t, _, _}) ->
|
|
||||||
% #analysis{}.
|
|
||||||
%
|
|
||||||
%bind_var(VarId, Env = #env{vars = Vars}) ->
|
|
||||||
% check_shadowing(VarId, Vars),
|
|
||||||
% Env#env{vars = [VarId | Vars]}.
|
|
||||||
%
|
|
||||||
%check_shadowing(Var = {id, _, VarName}, Ids) ->
|
|
||||||
% Shadowed =
|
|
||||||
% lists:search(fun({id, _, Name}) when Name == VarName -> true;
|
|
||||||
% (_) -> false
|
|
||||||
% end, Ids),
|
|
||||||
% case Shadowed of
|
|
||||||
% false ->
|
|
||||||
% #analysis{};
|
|
||||||
% {value, ShadowedVar} ->
|
|
||||||
% #analysis{shadowing_pairs = [{Var, ShadowedVar}]}
|
|
||||||
% end.
|
|
||||||
%
|
|
||||||
%lookup_var({id, _, VarName}, Env) ->
|
|
||||||
% {value, Var}=
|
|
||||||
% lists:search(
|
|
||||||
% fun({id, _, Name}) when Name == VarName -> true;
|
|
||||||
% (_) -> false
|
|
||||||
% end, Env#env.vars),
|
|
||||||
% Var.
|
|
||||||
|
|
||||||
|
|
||||||
merge(A1, A2) ->
|
|
||||||
#analysis{ used_types = sets:union(A1#analysis.used_types, A2#analysis.used_types)
|
|
||||||
, used_funs = sets:union(A1#analysis.used_funs, A2#analysis.used_funs) }.
|
|
||||||
|
|
||||||
|
|
||||||
%% the set of unused functions is the different between the 2 sets:
|
|
||||||
%% - In a contract:
|
|
||||||
%% * all user-defined functions
|
|
||||||
%% * all function calls
|
|
||||||
%% - In a namespace:
|
|
||||||
%% * all user-defined private functions
|
|
||||||
%% * all function calls
|
|
||||||
%% Note: this only applies to functions, not entrypoints
|
|
||||||
|
|
||||||
%% Unused variables:
|
|
||||||
%% -----------------
|
|
||||||
%% Scope: function
|
|
||||||
%% Algo: if a variable is not used in its current scope, then it's reported.
|
|
||||||
%% Functions that are declared in one scope but not used, and then declared
|
|
||||||
%% in a different scope and used, should be considered.
|
|
||||||
%%
|
|
||||||
%% Unused stateful:
|
|
||||||
%% ----------------
|
|
||||||
%% Scope: function
|
|
||||||
%% Algo: check all function calls in the function, if none of them requires
|
|
||||||
%% stateful, then we say that it's unused.
|
|
||||||
%%
|
|
||||||
%% Unused constants:
|
|
||||||
%% -----------------
|
|
||||||
%% Scope: contract or namespace
|
|
||||||
%% Algo: same as variables, but the scope is fixed to the contract or the namespace.
|
|
||||||
%%
|
|
||||||
%% Unused typedefs:
|
|
||||||
%% ----------------
|
|
||||||
%% Scope: contract or namespace
|
|
||||||
%% Algo: check the types of all expressions in the contract or namespace, if the type
|
|
||||||
%% doesn't show up anywhere, then the typedef is not used.
|
|
Loading…
x
Reference in New Issue
Block a user