123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285(****************************************************************************)(* *)(* This file is part of MOPSA, a Modular Open Platform for Static Analysis. *)(* *)(* Copyright (C) 2017-2019 The MOPSA Project. *)(* *)(* This program is free software: you can redistribute it and/or modify *)(* it under the terms of the GNU Lesser General Public License as published *)(* by the Free Software Foundation, either version 3 of the License, or *)(* (at your option) any later version. *)(* *)(* This program 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 *)(* GNU Lesser General Public License for more details. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* along with this program. If not, see <http://www.gnu.org/licenses/>. *)(* *)(****************************************************************************)(** Format the results of the analysis in JSON. *)openMopsa_utilsopenYojson.BasicopenArgExtopenCore.AllopenCallstackopenLocationopenCommonmoduleAlarmKindSet=SetExt.Make(structtypet=alarm_kindletcompare=compare_alarm_kindend)letprintoutjson=letchannel=matchoutwith|None->stdout|Somefile->open_out_gen[Open_creat;Open_wronly;Open_creat]0o644fileinYojson.Basic.pretty_to_channelchanneljsonletrender_pospos=letfile=Location.get_pos_fileposinletline=Location.get_pos_lineposinletcolumn=Location.get_pos_columnposin`Assoc["file",`Stringfile;"line",`Intline;"column",`Intcolumn;]letrender_rangerange=ifnot@@is_orig_range@@untag_rangerangethen`Assoc[]else`Assoc["start",render_pos(Location.get_range_startrange);"end",render_pos(Location.get_range_endrange)]letrender_call(c:callsite)=`Assoc["function",`Stringc.call_fun_orig_name;"range",render_rangec.call_range;]letrender_callstackcs=`List(List.maprender_callcs)letaggregate_alarmsreport=RangeCallStackMap.fold(fun(range,cs)checksacc->CheckMap.fold(funcheckdiagacc->matchdiag.diag_kindwith|Safe|Unreachable->acc|Error|Warning->letcsl=AlarmSet.elementsdiag.diag_alarms|>List.mapcallstack_of_alarmin(range,check,csl)::acc)checksacc)report.report_diagnostics[]letrender_checkcheck=lettitle=Format.asprintf"%a"pp_checkcheckin`Stringtitleletrender_alarm_messageskinds=`String(Format.asprintf"%a"(Format.pp_print_list~pp_sep:(funfmt()->Format.fprintffmt"@,")pp_alarm_kind)kinds)letrender_alarmsreport=RangeCallStackMap.fold(fun(range,cs)checksacc->CheckMap.fold(funcheckdiag(safe,total,acc)->matchdiag.diag_kindwith|Safewhennot!opt_show_safe_checks->safe+1,total+1,acc|Safe|Error|Warning->(* Get the set of alarms kinds and callstacks *)letkinds=AlarmSet.fold(funakinds->AlarmKindSet.adda.alarm_kindkinds)diag.diag_alarmsAlarmKindSet.emptyin(* Join alarm kinds *)letreciter=function|[]->[]|hd::tl->lethd',tl'=iter_withhdtlinhd'::itertl'anditer_witha=function|[]->a,[]|hd::tl->matchjoin_alarm_kindahdwith|None->leta',tl'=iter_withatlina',hd::tl'|Someaa->letaa',tl'=iter_withaatlinaa',tl'inletkinds'=iter(AlarmKindSet.elementskinds)inletjson_diag=`Assoc["kind",`String(Format.asprintf"%a"pp_diagnostic_kinddiag.diag_kind);"title",render_checkcheck;"messages",render_alarm_messageskinds';"range",render_rangerange;"callstack",render_callstackdiag.diag_callstack]in(ifdiag.diag_kind=Safethensafe+1elsesafe),total+1,json_diag::acc|_->safe,total,acc)checksacc)report.report_diagnostics(0,0,[])letrender_soudness_assumtionh=letmsg=Format.asprintf"%a"pp_assumption_kindh.assumption_kindinmatchh.assumption_scopewith|A_global->`Assoc["message",`Stringmsg;]|A_localr->`Assoc["range",render_ranger;"message",`Stringmsg;]letrender_varvar=`Stringvar.vnameletrender_valuevalue=`Stringvalueletrender_env(var,value)=`Assoc["var",render_varvar;"val",render_valuevalue;]letreportmanflow~time~files~out:unit=letrep=Flow.get_reportflowinletsafe,total,checks=render_alarmsrepinletjson=`Assoc["success",`Booltrue;"time",`Floattime;"mopsa_version",`StringVersion.version;"mopsa_dev_version",`StringVersion.dev_version;"files",`List(List.map(funf->`Stringf)files);"selectivity",`String(Format.asprintf"%d/%d"safetotal);"checks",`Listchecks;"assumptions",`List(AssumptionSet.elementsrep.report_assumptions|>List.maprender_soudness_assumtion);]inprintoutjsonletpanicexn~btrace~time~files~out_=letopenExceptionsinleterror,range,cs=matchexnwith|Panic(msg,loc)->msg,None,None|PanicAtLocation(range,msg,loc)->msg,Somerange,None|PanicAtFrame(range,cs,msg,loc)->msg,Somerange,Somecs|SyntaxError(range,msg)->msg,Somerange,None|SyntaxErrorListl->String.concat", "(List.mapsndl),None,None|_->Printexc.to_stringexn,None,Noneinletassoc=["success",`Boolfalse;"time",`Floattime;"mopsa_version",`StringVersion.version;"mopsa_dev_version",`StringVersion.dev_version;"files",`List(List.map(funf->`Stringf)files);"exception",`Stringerror;"backtrace",`Stringbtrace;]@(matchrangewith|None->[]|Somer->["range",render_ranger])@(matchcswith|None->[]|Somec->["callstack",render_callstackc])inprintout(`Assocassoc)lethelp(args:ArgExt.arglist)~out=letjson=`List(args|>List.map(funarg->`Assoc["key",`Stringarg.key;"doc",`Stringarg.doc;"category",`Stringarg.category;"default",`Stringarg.default;"type",`String(matcharg.specwith|Bool_->"bool"|Set_->"set"|Clear_->"clear"|Unit_->"unit"|String_->"string"|Set_string_->"string"|Int_->"int"|Set_int_->"int"|Symbol(l,_)->"symbol:"^(String.concat","l)|_->failwith"Not implemented")]))inprintoutjsonletlist_domains(domains:stringlist)~out=letjson=`List(domains|>List.map(fund->`Stringd))inprintoutjsonletlist_reductions(reductions:stringlist)~out=letjson=`List(reductions|>List.map(fund->`Stringd))inprintoutjsonletlist_checkschecks~out=letjson=`List(List.maprender_checkchecks)inprintoutjsonletlist_hookshooks~out=letjson=`List(hooks|>List.map(fund->`Stringd))inprintoutjsonletprintprinter~range~out=letjson=`Assoc["print",print_object_to_json(get_printed_objectprinter);"range",render_rangerange;]inprintoutjson