Remove file committed by mistake

This commit is contained in:
Gaith Hallak 2023-06-09 13:38:51 +03:00
parent 34920eb467
commit 3ea11105b4

View File

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