123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* 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, version 2.1. *)(* *)(* It 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. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file licenses/LGPLv2.1). *)(* *)(**************************************************************************)openPrinter_tagopenGtk_helperopenCil_typesopenPdg_typesmoduleSelectedStmt=structincludeState_builder.Option_ref(Cil_datatype.Stmt)(structletname="Impact_gui.SelectedStmt"letdependencies=[Ast.self]end)letsets=sets;Project.clear~selection:(State_selection.only_dependenciesself)();endlet()=Cmdline.run_after_extended_stage(fun()->State_dependency_graph.add_codependencies~onto:SelectedStmt.self[Pdg.Api.self])moduleHighlighted_stmt:sigvaladd:Kernel_function.t->stmt->unitvalmem:Kernel_function.t->stmt->boolvalmem_kf:Kernel_function.t->boolend=structopenCil_datatypemoduleTbl=Kernel_function.Make_Table(Stmt.Set)(structletname="Impact_gui.Highlighted_stmt"letsize=7letdependencies=[SelectedStmt.self]end)letaddkfs=ignore(Tbl.memo~change:(funset->Stmt.Set.addsset)(fun_->Stmt.Set.singletons)kf)letmemkfs=tryletset=Tbl.findkfinStmt.Set.memssetwithNot_found->falseletmem_kf=Tbl.memendmoduleImpactedNodes=State_builder.Ref(Kernel_function.Map.Make(Pdg_aux.NS))(structletname="Impact.Register_gui.ImpactedNodes"letdependencies=[SelectedStmt.self]letdefault()=Kernel_function.Map.emptyend)moduleReasonGraph=State_builder.Ref(Reason_graph.DatatypeReason)(structletname="Impact.Register_gui.ReasonGraph"letdependencies=[SelectedStmt.self]letdefault()=Reason_graph.emptyend)moduleInitialNodes=State_builder.Ref(Pdg_aux.NS)(structletname="Impact.Register_gui.InitialNodes"letdependencies=[SelectedStmt.self]letdefault()=Pdg_aux.NS.emptyend)letimpact_in_kfkf=Compute_impact.impact_in_kf(ImpactedNodes.get())kf(* Update the 'Impact' column of the gui filetree. *)letupdate_column=ref(fun_->())(* Are results shown? *)moduleEnabled=structincludeState_builder.Ref(Datatype.Bool)(structletname="Impact_gui.State"letdependencies=[]letdefault()=falseend)end(* Should perform slicing after impact? *)moduleSlicing=State_builder.Ref(Datatype.Bool)(structletname="Impact_gui.Slicing"letdependencies=[]letdefault()=falseend)(* Follow Focus mode *)moduleFollowFocus=State_builder.Ref(Datatype.Bool)(structletname="Impact_gui.FollowFocus"letdependencies=[]letdefault()=falseend)letapply_on_stmtf=function|PStmt(kf,s)->fkfs|_->()letimpact_highlighterbufferloc~start~stop=ifEnabled.get()thenletbuffer=buffer#bufferinlettagnamecolor=lett=make_tagbuffer~name[`BACKGROUNDcolor]inapply_tagbuffertstartstopinlethilightkfs=ifHighlighted_stmt.memkfsthentag"hilighed_impact""green"elseSelectedStmt.may(funsel->ifCil_datatype.Stmt.equalselsthentag"selected_impact""cyan")inapply_on_stmthilightlocletimpact_statementrestricts=letkf=Kernel_function.find_englobing_kfsinletskip=Compute_impact.skip()inletreason=Options.Reason.get()inletimpact,initial,reason=Compute_impact.nodes_impacted_by_stmts~skip~restrict~reasonkf[s]inSelectedStmt.sets;ImpactedNodes.setimpact;InitialNodes.set(Kernel_function.Map.findkfinitial);ReasonGraph.setreason;letstmts=ref[]inKernel_function.Map.iter(funkfs->letstmts'=Compute_impact.nodes_to_stmtssinstmts:=stmts'::!stmts;List.iter(Highlighted_stmt.addkf)stmts')impact;letimpact=List.concat!stmtsinifSlicing.get()thenignore(Register.sliceimpact);Enabled.settrue;impactletimpact_statement=Dynamic.register~comment:"Compute the impact of the statement in the Gui"~plugin:"impact""impact_statement_gui"(Datatype.func~label:("restrict",Some(fun()->Locations.Zone.top))Locations.Zone.ty(Datatype.funcCil_datatype.Stmt.ty(Datatype.listCil_datatype.Stmt.ty)))impact_statementletimpact_statement_ui(main_ui:Design.main_window_extension_points)s=letval_computed=Eva.Analysis.is_computed()inignore(impact_statement(*restriction*)Locations.Zone.tops);ifnotval_computedthenmain_ui#reset()else(!update_column`Contents;main_ui#rehighlight())letpretty_info=reftrueletpp_impact_on_inputs(main_ui:Design.main_window_extension_points)kf=letnodes=impact_in_kfkfinif!pretty_info&¬(Pdg_aux.NS.is_emptynodes)thenletopenPdgIndex.SignatureinletopenPdgIndex.Keyinletcall,formals,zones=Pdg_aux.NS.fold(fun(node,z)(call,formals,zonesasacc)->matchPdg.Api.node_keynodewith|SigCallKey_|CallStmt_|Stmt_|Label_->acc(* Related to one stmt: skip *)|VarDecl_->acc(* skip *)|SigKey(Out_)->acc(* probably impossible *)|SigKey(InInCtrl)->(true,formals,zones)|SigKey(In(InNumi))->(call,i::formals,zones)|SigKey(In(InImplz'))->letz=Locations.Zone.narrowzz'in(call,formals,Locations.Zone.joinzonesz))nodes(false,[],Locations.Zone.bottom)inifcall=true||formals<>[]||not(Locations.Zone.is_bottomzones)thenletformals=List.sortDatatype.Int.compareformalsinmain_ui#pretty_information"@[<hov 2>Impacted inputs of the function:@ %t%t@]@."(funfmt->ifcallthenFormat.fprintffmt"call@ may@ be@ entirely@ skipped; ")(funfmt->ifformals<>[]thenPretty_utils.pp_list~pre:"argument(s)@ "~sep:"@ "~suf:",@ "Datatype.Int.prettyfmtformals;ifnot(Locations.Zone.is_bottomzones)thenLocations.Zone.prettyfmtzones)letpp_impacted_call_outputs(main_ui:Design.main_window_extension_points)kfcall_stmt=letnodes=impact_in_kfkfinif!pretty_info&¬(Pdg_aux.NS.is_emptynodes)thenletopenPdgIndex.SignatureinletopenPdgIndex.Keyinletret,zones=Pdg_aux.NS.fold(fun(node,z)(ret,zonesasacc)->matchPdg.Api.node_keynodewith|SigCallKey(stmt',key)whenCil_datatype.Stmt.equalcall_stmtstmt'->(matchkeywith|In_->acc(* impossible *)|OutOutRet->(true,zones)|Out(OutLocz')->letz=Locations.Zone.narrowzz'in(ret,Locations.Zone.joinzonesz))|_->acc)nodes(false,Locations.Zone.bottom)inifret=true||not(Locations.Zone.is_bottomzones)thenmain_ui#pretty_information"@[<hov 2>Memory impacted by this call:@ %t%t@]@."(funfmt->ifretthenFormat.fprintffmt"return code; ")(funfmt->ifnot(Locations.Zone.is_bottomzones)thenLocations.Zone.prettyfmtzones)letimpact_selector(popup_factory:GMenu.menuGMenu.factory)main_ui~buttonlocalizable=matchlocalizablewith|PStmt(kf,s)->ifbutton=3||FollowFocus.get()then(letcallback()=ignore(impact_statement_uimain_uis)inignore(popup_factory#add_item"_Impact analysis"~callback);ifFollowFocus.get()thenignore(Glib.Idle.add(fun()->callback();false)));ifbutton=1thenbegin(* Initial nodes, at the source of the impact *)(matchSelectedStmt.get_option()with|Somes'whenCil_datatype.Stmt.equalss'->if!pretty_infothenmain_ui#pretty_information"@[Impact initial nodes:@ %a@]@."(Pretty_utils.pp_iterPdg_aux.NS.iter'~sep:",@ "Pdg_aux.pretty_node)(InitialNodes.get());|_->());pp_impacted_call_outputsmain_uikfsend|PVDecl(_,_,vi)|PGlobal(GFun({svar=vi},_))whenCil.isFunctionTypevi.vtype->ifbutton=1thenbeginletkf=Globals.Functions.getviinpp_impact_on_inputsmain_uikf;end;|_->()letimpact_panelmain_ui=letw=GPack.vbox()in(* check buttons *)letenabled_button=on_boolw"Enable"Enabled.get(funb->Enabled.setb;!update_column`Visibility;main_ui#rehighlight())inletslicing_button=on_boolw"Slicing after impact"Slicing.getSlicing.setinletfollow_focus_button=on_boolw"Follow focus"FollowFocus.getFollowFocus.setin(* panel refresh *)letrefresh()=enabled_button();slicing_button();follow_focus_button()in"Impact",w#coerce,Somerefreshletfile_tree_decorate(file_tree:Filetree.t)=update_column:=file_tree#append_pixbuf_column~title:"Impact"(funglobs->letis_hilighted=function|GFun({svar=v},_)->Highlighted_stmt.mem_kf(Globals.Functions.getv)|_->falseinletid=(* laziness of && is used for efficiency *)ifEnabled.get()&&SelectedStmt.get_option()<>None&&List.existsis_hilightedglobsthen"gtk-apply"else""in[`STOCK_IDid])(fun()->Enabled.get()&&SelectedStmt.get_option()<>None);!update_column`Visibilityletmainmain_ui=main_ui#register_source_selectorimpact_selector;main_ui#register_source_highlighterimpact_highlighter;main_ui#register_panelimpact_panel;file_tree_decoratemain_ui#file_treelet()=Design.register_extensionmain(*
Local Variables:
compile-command: "make -C ../../.."
End:
*)