123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153(* Yoann Padioleau
*
* Copyright (C) 2013 Facebook
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation, with the
* special exception on linking described in file license.txt.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file
* license.txt for more details.
*)openCommonmoduleG=Graph_code(*****************************************************************************)(* Prelude *)(*****************************************************************************)(*
* Module to help visualize dependencies: is an entity an entry-point
* of the program or one of its leaves. It also help visualize
* all the errors in codegraph (lookup failures, unresolved method calls, etc).
*
* For the bottom up layer note that a file can be red and be shown
* as used by a green. It's because This green file maybe use a green
* entity of this red file, but not the very red entity of this red file.
*)(*****************************************************************************)(* Helpers *)(*****************************************************************************)letkind_of_rank~max_totaln=letpercent=ifmax_total=0then0elseCommon2.pourcentnmax_totalinletpercent_round=(percent/10)*10inspf"cover %d%%"percent_round(*****************************************************************************)(* Main entry point *)(*****************************************************************************)letgen_rank_heatmap_layerghentity_to_rank~output=letgroup_by_file=hentity_to_rank|>Common.hash_to_list|>Common.map_filter(fun(node,v)->tryletfile=G.file_of_nodenodegin(* we want to make sure this node has a line, some
* E.File could be there because file_of_node works for them
* but they have no line, so let's filter them here
*)let_line=G.nodeinfonodeginSome(file,(node,v))withNot_found->None)|>Common.group_assoc_bykey_effinletxs=hentity_to_rank|>Common.hash_to_list|>List.mapsndinletmax_total=Common2.maximumxsinletlayer={Layer_code.title=spf"Graph code rank (%s)"(Filename.basenameoutput);description="Associate a rank to each entity according to its depth
in the Use graph";files=group_by_file|>List.map(fun(file,nodes_and_rank)->letmax_file=nodes_and_rank|>List.mapsnd|>Common2.maximuminfile,{Layer_code.micro_level=nodes_and_rank|>List.map(fun(n,v)->letinfo=G.nodeinfonginletline=info.Graph_code.pos.Parse_info.lineinline,kind_of_rankv~max_total);macro_level=[kind_of_rankmax_file~max_total,1.];});kinds=Layer_code.heat_map_properties;}inLayer_code.save_layerlayeroutputletgen_statistics_layer~rootstats~output=(* there is a priority order here, see simple_layer_of_parse_infos
* that leverage this order
*)letkinds=["lookup fail","purple";"unresolved calls","red3";"unresolved class access","orange";"unresolved method calls","yellow";"unresolved field access","blue";"resolved method calls","green";"resolved field access","green3";]inletprebs=ifbthen"resolved "^selse"unresolved "^sinletinfos=(!(stats.G.unresolved_calls)|>List.map(funx->x,"unresolved calls"))@(!(stats.G.unresolved_class_access)|>List.map(funx->x,"unresolved class access"))@(!(stats.G.field_access)|>List.map(fun(x,b)->x,preb"field access"))@(!(stats.G.method_calls)|>List.map(fun(x,b)->x,preb"method calls"))@(!(stats.G.lookup_fail)|>List.map(fun(x,(_str,_kind))->x,"lookup fail"))@[]inletlayer=Layer_code.simple_layer_of_parse_infos~root~title:"Graph code error statistics"~description:""infoskindsinLayer_code.save_layerlayeroutput;()(*****************************************************************************)(* Actions *)(*****************************************************************************)letactions()=["-gen_bottomup_layer"," <graph_file> <output>",Common.mk_action_2_arg(fungraph_file_output->letg=G.loadgraph_fileinlethrank=G.bottom_up_numberingginlet(d,_,_)=Common2.dbe_of_filenamegraph_fileinletoutput=Common2.filename_of_dbe(d,"layer_graph_code","json")ingen_rank_heatmap_layerghrankoutput;);]