123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758(**************************************************************************)(* *)(* 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). *)(* *)(**************************************************************************)openCil_typesopenPrinter_tagopenGui_typestypemain_ui=Design.main_window_extension_pointstypemenu=GMenu.menuGMenu.factory(* ------------------------ Eva panel and filetree -------------------------- *)moduleUsedVarState=Cil_state_builder.Varinfo_hashtbl(Datatype.Bool)(structletsize=17letname="Value.Gui.UsedVarState"letdependencies=[Self.state](* [!Db.Inputs.self_external; !Db.Outputs.self_external] would be better
dependencies, but this introduces a very problematic recursion between
Value and Inout *)end)letused_var=UsedVarState.memo(funvar->Function_calls.partial_results()||tryletf=fst(Globals.entry_point())inletinputs=!Db.Inputs.get_externalfinletoutputs=!Db.Outputs.get_externalfinletb=Base.of_varinfovarinLocations.Zone.mem_basebinputs||Locations.Zone.mem_baseboutputswithe->Gui_parameters.error~once:true"Exception during usability analysis of var %s: %s"var.vname(Printexc.to_stringe);true(* No really sane value, so in doubt... *))(* Set when the callback is installed *)lethide_unused=ref(fun()->false)letsync_filetree(filetree:Filetree.t)=ifnot(!hide_unused())then(Globals.Functions.iter(funkf->tryletvi=Kernel_function.get_vikfinletstrikethrough=Analysis.is_computed()&¬(Results.is_calledkf)infiletree#set_global_attribute~strikethroughviwithNot_found->());Globals.Vars.iter(funvi_->ifvi.vsource=truethenfiletree#set_global_attribute~strikethrough:(Analysis.is_computed()&¬(used_varvi))vi);ifnot(filetree#flat_mode)thenList.iter(funfile->(* the display name removes the path *)letglobals_state=filetree#get_file_globalsfileinfiletree#set_file_attribute~strikethrough:(Analysis.is_computed()&&List.for_allsndglobals_state)file)(Globals.FileIndex.get_files()))else(* Some lines may have disappeared. We should reset the entire filetree,
but the method reset of design.ml already does this. *)()lethide_unused_function_or_varg=!hide_unused()&&Analysis.is_computed()&&(matchgwith|GFun({svar=vi},_)|GFunDecl(_,vi,_)->letkf=Globals.Functions.getviinnot(Results.is_calledkf)|GVarDecl(vi,_)|GVar(vi,_,_)->not(used_varvi)|_->false)letvalue_panelpack(main_ui:main_ui)=letbox=GPack.vbox()inletrun_button=GButton.button~label:"Run"~packing:(box#pack)()inletw=GPack.table~packing:(box#pack~expand:true~fill:true)~columns:2()inletbox_1_1=GPack.hbox~packing:(w#attach~left:1~top:1)()inletprecision_refresh=lettooltip=Parameters.Precision.parameter.Typed_parameter.helpinGtk_helper.on_int~lower:(-1)~upper:11~tooltipbox_1_1"precision (meta-option)"Parameters.Precision.getParameters.Precision.setinletbox_1_2=GPack.hbox~packing:(w#attach~left:1~top:2)()inletslevel_refresh=lettooltip=Parameters.SemanticUnrollingLevel.parameter.Typed_parameter.helpinGtk_helper.on_int~lower:0~upper:1000000~tooltipbox_1_2"slevel"Parameters.SemanticUnrollingLevel.getParameters.SemanticUnrollingLevel.setinletbox_1_3=GPack.hbox~packing:(w#attach~left:1~top:3)()inletvalidators=not(Kernel_function.Set.is_empty(Parameter_customize.get_c_ified_functionss))inletmain_refresh=Gtk_helper.on_string~tooltip:Kernel.MainFunction.parameter.Typed_parameter.help~validatorbox_1_3"main"Kernel.MainFunction.getKernel.MainFunction.setinletrefresh()=precision_refresh();slevel_refresh();main_refresh()inignore(run_button#connect#pressed~callback:(fun()->main_ui#protect~cancelable:true(fun()->refresh();Analysis.compute();main_ui#reset());));packbox;"Eva",box#coerce,Somerefresh(* ---------------------------- Highlighter --------------------------------- *)letactive_highlighterbufferlocalizable~start~stop=letopenGtk_helperinletbuffer=buffer#bufferin(* highlight dead code areas, non-terminating calls, and degeneration
points if Value has run.*)ifAnalysis.is_computed()thenmatchlocalizablewith|PStmt(kf,stmt)->beginletdegenerate=trySome(ifEva_utils.DegenerationPoints.findstmtthen(make_tagbuffer~name:"degeneration"[`BACKGROUND"orange"])else(make_tagbuffer~name:"unpropagated"[`BACKGROUND"yellow"]))withNot_found->Noneinmatchdegeneratewith|Somecolor_area->apply_tagbuffercolor_areastartstop|None->ifAnalysis.statuskf<>AnalyzedNoResultsthenbeginletcsf=Gui_callstacks_filters.focused_callstacks()inifGui_callstacks_filters.is_reachable_stmtcsfstmtthenbeginifGui_callstacks_filters.is_non_terminating_instrcsfstmtthenletnon_terminating=Gtk_helper.make_tagbuffer~name:"value_non_terminating"[`BACKGROUND"tomato"]inapply_tagbuffernon_terminating(stop-1)stopendelseletdead_code_area=make_tagbuffer~name:"deadcode"[`BACKGROUND"tomato";`STYLE`ITALIC]inapply_tagbufferdead_code_areastartstopendend|_->()(* ------------------------ Responses to selections ------------------------- *)letdisplay_eval_errors(main_ui:main_ui)l=letpp=function|Eval_terms.LogicEvalErroree->main_ui#pretty_information"Cannot evaluate: %a@."Eval_terms.pretty_logic_evaluation_erroree|e->main_ui#pretty_information"Unknown error during evaluation (%s)@."(Printexc.to_stringe)inList.iterpplletpretty_kf_escapedkf=Pretty_utils.(escape_underscores(to_stringKernel_function.prettykf))(* popup a menu to jump the definitions of the given functions *)letmenu_go_to_fun_definition(main_ui:main_ui)(popup_factory:menu)funs=letauxkf=tryletg=Kernel_function.get_globalkfinignore(popup_factory#add_item("Go to definition of "^pretty_kf_escapedkf^" (indirect)")~callback:(fun()->main_ui#select_or_display_globalg))withNot_found->()inList.iterauxfunsletgui_compute_values(main_ui:main_ui)=ifnot(Analysis.is_computed())thenmain_ui#launcher()letcleaned_outputskfs=letouts=Db.Outputs.kinstr(Kstmts)inletaccept=Logic_inout.accept_base~formals:true~locals:truekfinletfilter=Locations.Zone.filter_baseacceptinOption.mapfilteroutsletpretty_stmt_info(main_ui:main_ui)kfstmt=(* Is it an accessible statement ? *)ifResults.is_reachablestmtthenbeginifEva_results.is_non_terminating_instrstmtthenmatchstmt.skindwith|Instr(Call(_,_,_,_)|Local_init(_,ConsInit_,_))->(* This is not 100% accurate: the instr can also fail
when storing the result in [lvopt] *)main_ui#pretty_information"This call never terminates.@."|Instr_->main_ui#pretty_information"This instruction always fail.@."|_->()else(* Out for this statement *)letouts=cleaned_outputskfstmtinmatchoutswith|Someouts->main_ui#pretty_information"Modifies @[<hov>%a@]@."Db.Outputs.prettyouts|_->()endelsemain_ui#pretty_information"This code is dead@."typeterm_or_pred=Term|Predletpp_term_or_predfmt=function|Term->Format.pp_print_stringfmt"term"|Pred->Format.pp_print_stringfmt"predicate"letlast_evaluate_acsl_request=ref""(* ------- Make the responses from the abstractions used in analysis ------- *)(** Responses of the GUI to user actions. Built by the Select functor. *)moduletypeResponses=sigvaleval_acsl_term_pred:main_ui->gui_loc->term_or_pred->unit->unitvalleft_click_values_computed:main_ui->localizable->unitvalright_click_values_computed:main_ui->menu->localizable->unitend(** A "no response" module, when the GUI has not been built. *)moduleNo_Response=structleteval_acsl_term_pred___()=()letleft_click_values_computed__=()letright_click_values_computed___=()end(* Module argument of the Select functor: it is the module resulting
from Gui_eval.A, plus the function display_at_loc coming from
gui_callstacks_manager. *)moduletypeEval=sigincludeGui_eval.Svaldisplay_data_by_callstack:Analysis.Val.tGui_callstacks_manager.display_data_by_callstackend(* Builds the responses of the GUI to user actions. *)moduleSelect(Eval:Eval)=structletselect_locmain_uievlocv=letdata,errors=Eval.make_data_all_callstacksevlocvindisplay_eval_errorsmain_uierrors;letselection=ev.Eval.expr_to_gui_selectionvinEval.display_data_by_callstacklocselectiondataletis_scalartyp=matchCil.unrollTypetypwith|TInt_|TEnum_|TPtr_|TFloat_->true|_->falseletselect_lvmain_uiloclv=ifis_scalar(Cil.typeOfLvallv)thenselect_locmain_uiEval.lval_evloclvelseselect_locmain_uiEval.lval_as_offsm_evloclvletselect_nullmain_uiloc=select_locmain_uiEval.null_evloc()letselect_expmain_uilocexp=select_locmain_uiEval.exp_evlocexpletselect_termmain_uiloct=select_locmain_ui(Eval.term_evloc)loctletselect_tlvmain_uiloctlv=select_locmain_ui(Eval.tlval_evloc)loctlvletselect_predicatemain_uilocp=select_locmain_ui(Eval.predicate_evloc)locpletselect_predicate_with_redmain_uiloca=select_locmain_ui(Eval.predicate_with_redloc)loca(* Evaluate the user-supplied term contained in the string [txt] *)leteval_user_term_predicate(main_ui:main_ui)loctptxt=letkf=kf_of_gui_loclocintryGui_callstacks_manager.focus_selection_tab();letenv=Gui_eval.gui_loc_logic_envlocinmatchtpwith|Term->beginiftxt="NULL"thenselect_nullmain_uilocelseletterm=Logic_parse_string.term~envkftxtinmatchterm.term_nodewith|TLval_|TStartOf_->select_tlvmain_uilocterm|_->select_termmain_uiloctermend|Pred->letpred=Logic_parse_string.predicate~envkftxtinselect_predicatemain_uilocpredwith|Logic_parse_string.Error(_,mess)->main_ui#error"Invalid %a: %s"pp_term_or_predtpmess|Parsing.Parse_error->main_ui#error"Invalid %a: Parse error"pp_term_or_predtp|Eval_terms.LogicEvalErroree->main_ui#error"Cannot evaluate %a (%a)"pp_term_or_predtpEval_terms.pretty_logic_evaluation_erroree|Log.AbortFatalswhens="kernel"->letbt=Printexc.get_backtrace()in(* possibly a typing error, avoid an error message too drastic *)main_ui#error"Invalid %a (see the 'Console' tab for more details)."pp_term_or_predtp;(* print the backtrace only if in debugging mode *)Gui_parameters.debug"%s"bt|e->main_ui#error"Invalid %a: %s"pp_term_or_predtp(Cmdline.protecte)(* Opens a modal dialog asking for an ACSL expression and evaluates it
at location [loc]. *)leteval_acsl_term_predmain_uiloctp()=lettxt=Gtk_helper.input_string~title:"Evaluate"~parent:main_ui#main_window~text:!last_evaluate_acsl_request(Format.asprintf" Enter an ACSL %a to evaluate "pp_term_or_predtp)(* the spaces at beginning and end should not be necessary
but are the quickest fix for an aesthetic GTK problem *)inmatchtxtwith|None->()|Sometxt->last_evaluate_acsl_request:=txt;eval_user_term_predicatemain_uiloctptxt(* popup a menu to jump to the definitions of the callers *)letmenu_go_to_callers(main_ui:main_ui)(menu:menu)csfkf=tryletaux(menu:menu)(kf,call_sites)=letnb_sites=List.lengthcall_sitesinletlabel="Go to caller "^pretty_kf_escapedkfinletlabel=ifnb_sites>1thenlabel^" ("^(string_of_intnb_sites)^" call sites)"elselabelinletcallback()=letg=Kernel_function.get_globalkfinmain_ui#select_or_display_globalg;(* We put the cursor in the first call site and add the others (if any)
to the forward history. *)matchcall_siteswith|first_call_site::rest->main_ui#view_stmtfirst_call_site;letother_call_sites=List.map(funcall->letkf=Kernel_function.find_englobing_kfcallinHistory.Localizable(PStmt(kf,call)))restinHistory.set_forwardother_call_sites|[]->assertfalse(* list was not empty *)inignore(menu#add_item~callbacklabel)inletaux_focus(acc_focus,acc_unfocus)(kf,call_sites)=letfocus,unfocus=List.partition(Gui_callstacks_filters.callsite_matchescsf)call_sitesin(iffocus<>[]then(kf,focus)::acc_focuselseacc_focus),(ifunfocus<>[]then(kf,unfocus)::acc_unfocuselseacc_unfocus)inletfocused,unfocused=List.fold_leftaux_focus([],[])(Results.callsiteskf)inList.iter(auxmenu)focused;ifunfocused<>[]thenletsubmenu=GMenu.menu()inletitem=GMenu.menu_item~label:"Callers in unselected callstack(s)"()initem#set_submenusubmenu;menu#menu#additem;letfactory=newGMenu.factorysubmenuinList.iter(auxfactory)unfocusedwithNot_found->()(* Actions to perform when the user has left-clicked, and Value is computed.
Maintain synchronized with [can_eval_acsl_expr_selector] later in this file.*)letleft_click_values_computedmain_uilocalizable=tryletopenPropertyinmatchlocalizablewith|PStmt(kf,stmt)->ifGui_eval.results_kf_computedkfthenpretty_stmt_infomain_uikfstmt|PLval(Somekf,Kstmtstmt,lv)->ifnot(Cil.isFunctionType(Cil.typeOfLvallv))thenselect_lvmain_ui(GL_Stmt(kf,stmt))lv|PLval(Somekf,Kglobal,lv)->(* see can_eval_acsl_expr_selector *)ifnot(Cil.isFunctionType(Cil.typeOfLvallv))thenselect_lvmain_ui(GL_Prekf)lv|PExp(Somekf,Kstmtstmt,e)->select_expmain_ui(GL_Stmt(kf,stmt))e|PTermLval(Somekf,Kstmtstmt,_,tlv)->letterm=Logic_const.term(TLvaltlv)(Cil.typeOfTermLvaltlv)inselect_tlvmain_ui(GL_Stmt(kf,stmt))term|PTermLval(Somekf,Kglobal,ip,tlv)->beginmatchGui_eval.classify_pre_postkfipwith|Someloc->letterm=Logic_const.term(TLvaltlv)(Cil.typeOfTermLvaltlv)inselect_tlvmain_uilocterm|None->()end|PVDecl(Somekf,_,vi)whenvi.vformal->letlv=(Varvi,NoOffset)inselect_lvmain_ui(GL_Prekf)lv|PVDecl(Somekf,Kstmtstmt,vi)->letlv=(Varvi,NoOffset)inselect_lvmain_ui(GL_Stmt(kf,stmt))lv|PIP(IPCodeAnnot{ica_kf=kf;ica_stmt=stmt;ica_ca={annot_content=AAssert(_,p)|AInvariant(_,true,p)}asca}asip)->beginletloc=GL_Stmt(kf,stmt)inletp=p.tp_statementinletalarm_or_property=matchAlarms.findcawith|None->Red_statuses.Propip|Somea->Red_statuses.Alarmainselect_predicate_with_redmain_uiloc(alarm_or_property,p)end;|PIP(IPPredicate{ip_kf=kf;ip_kinstr=Kglobal;ip_pred=p}asip)->beginmatchGui_eval.classify_pre_postkfipwith|None->()|Someloc->select_predicate_with_redmain_uiloc(Red_statuses.Propip,Logic_const.pred_of_id_predp)end|PIP(IPPropertyInstance{ii_kf=kf;ii_stmt=stmt;ii_pred=Somepred;ii_ip=ip})->letloc=GL_Stmt(kf,stmt)inselect_predicate_with_redmain_uiloc(Red_statuses.Propip,Logic_const.pred_of_id_predpred)|PLval(None,_,_)|PExp((_,Kglobal,_)|(None,Kstmt_,_))|PTermLval(None,_,_,_)->()|PVDecl(_kf,_ki,_vi)->()|PGlobal_|PIP_|PStmtStart_|PType_->()with|Eval_terms.LogicEvalErroree->main_ui#pretty_information"Cannot evaluate term: %a@."Eval_terms.pretty_logic_evaluation_erroree(* Actions to perform when the user has right-clicked, and Value is computed *)letright_click_values_computedmain_uimenulocalizable=matchlocalizablewith|PVDecl(Somekf,_,_)->letfilter=Gui_callstacks_filters.focused_callstacks()inmenu_go_to_callersmain_uimenufilterkf|PStmt(kf,stmt)->ifGui_eval.results_kf_computedkfthenignore(menu#add_item"_Evaluate ACSL term"~callback:(eval_acsl_term_predmain_ui(GL_Stmt(kf,stmt))Term))|PLval(_kfopt,ki,lv)->letty=Cil.typeOfLvallvin(* Do special actions for functions *)begin(matchlvwith|Var_,NoOffsetwhenCil.isFunctionTypety->()(* direct calls are handled by [Design]. *)|Mem_,NoOffsetwhenCil.isFunctionTypety->begin(* Function pointers *)(* get the list of functions in the values *)lete=Eva_utils.lval_to_explvinletstate=matchkiwith|Kglobal->Eval.Analysis.get_global_state()|Kstmtstmt->Eval.Analysis.get_stmt_state~after:falsestmtinmatchstatewith|`Bottom|`Top->()|`Valuestate->letfuns,_=Eval.Analysis.eval_function_expstateeinmatchfunswith|`Bottom->()|`Valuefuns->menu_go_to_fun_definitionmain_uimenufunsend|_->())end|PStmtStart_|PVDecl(None,_,_)|PExp_|PTermLval_|PGlobal_|PIP_|PType_->()let_right_click_value_not_computed(main_ui:main_ui)(menu:menu)localizable=matchlocalizablewith|PVDecl(_,_,_)->beginignore(menu#add_item"Compute callers"~callback:(fun()->(gui_compute_valuesmain_ui)))end|_->()end(* ----------------- Reference to responses, and use it -------------------- *)(* This reference contains the responses of the GUI built by the Select
functor. It is updated each time the abstractions used in Eva are changed. *)letresponses_ref=ref(moduleNo_Response:Responses)letto_do_on_select(menu:menu)(main_ui:main_ui)~buttonselected=letmoduleResponses=(val!responses_ref)inifAnalysis.is_computed()thenifbutton=1thenResponses.left_click_values_computedmain_uiselectedelseifbutton=3thenResponses.right_click_values_computedmain_uimenuselected(* Find a location in which to evaluate things, when the given block is
selected. *)letfind_lockffdecblock=ifblock==fdec.sbodythenSome(GL_Prekf)elsematchblock.bstmtswith|[]->None|s::_->Some(GL_Stmt(kf,s))letadd_keybord_shortcut_evaluatemain_ui=(* The currently selected statement is stored to enable a keyboard shortcut
to activate it. [None] means that there is no selection or the selected
element is not part of a statement. *)letselected_loc_for_acsl=refNonein(* If we happen to go to another project that happens to share vids with
the previous one, comparing the new loc with the cached one might lead
to a crash dialog when the kernel will detect that we're trying to
use two distinct globals with the same id. Thus, changing project will
clear the selection once and for all.
*)let()=Project.register_after_set_current_hook~user_only:false(fun_->selected_loc_for_acsl:=None)in(* This function must be maintained synchronized with
[left_click_values_computed] above. *)letcan_eval_acsl_expr_selector_menu_main~button:_selected=(* We add a selector to enable a keyboard shortcut for evaluating ACSL
expressions. This selector listens to modification events and
updates selected_loc_for_acsl to the stmt of the selected element. *)letclear()=Gui_callstacks_manager.clear_default()inletselectnew_loc=beginmatchnew_loc,!selected_loc_for_acslwith|None,None->()|None,Some_|Some_,None->clear()|Somenew_loc,Someold_loc->ifnot(gui_loc_equalnew_locold_loc)thenclear();end;selected_loc_for_acsl:=new_locinmatchselectedwith|PStmt(kf,stmt)|PLval(Somekf,Kstmtstmt,_)|PExp(Somekf,Kstmtstmt,_)|PTermLval(Somekf,Kstmtstmt,_,_)->ifGui_eval.results_kf_computedkfthenselect(Some(GL_Stmt(kf,stmt)))elseselectNone|PLval(Somekf,Kglobal,_)->(* We are either on a formal, or on the declaration of the variables of
[kf] at body scope. *)ifGui_eval.results_kf_computedkfthenselect(Some(GL_Prekf))elseselectNone|PTermLval(Somekf,Kglobal,ip,_)->select(Gui_eval.classify_pre_postkfip)|PVDecl(Somekf,_,vi)whenvi.vformal->select(Some(GL_Prekf))|PVDecl(Somekf,ki,vi)whennot(vi.vformal||vi.vglob)(* local *)->beginmatchkiwith|Kstmtstmt->(* local with initializers *)select(Some(GL_Stmt(kf,stmt)))|Kglobal->(* no initializer. Find the declaration block *)(* Notice that Pretty_source focuses on the statement containing the
block itself most of the time. The case handled here happens only
when you directly select the declaration of a variable, between
the type and the name *)letfdec=Kernel_function.get_definitionkfinletbl=Ast_info.block_of_localfdecviinselect(find_lockffdecbl)end|PIP(Property.(IPCodeAnnot{ica_kf=kf;ica_stmt=stmt;ica_ca={annot_content=AAssert_|AInvariant(_,true,_)}}))->select(Some(GL_Stmt(kf,stmt)))|PIP(Property.(IPPredicate{ip_kf;ip_kinstr=Kglobal}asip))->select(Gui_eval.classify_pre_postip_kfip)|_->selectNoneinmain_ui#register_source_selectorcan_eval_acsl_expr_selector;(* We add a keyboard shortcut (Ctrl+E) to open the "Evaluate ACSL expression"
popup. This only works if the current selection is on a statement,
otherwise it does nothing. *)letaccel_group=GtkData.AccelGroup.create()inletregister_accelmodikind=GtkData.AccelGroup.connectaccel_group~key:GdkKeysyms._E~modi~callback:(fun_->match!selected_loc_for_acslwith|None->()|Someloc->letmoduleResponses=(val!responses_ref)inResponses.eval_acsl_term_predmain_uilockind());inregister_accel[`CONTROL]Term;register_accel[`CONTROL;`SHIFT]Pred;main_ui#main_window#add_accel_groupaccel_group;;(* ----------------------------- Build the GUI ------------------------------ *)(* Resets the GUI parts that depend on the abstractions used for the Eva
analysis. This needs to be done each time the abstractions are changed.
The module [A] is the current analysis module; it contains the
abstractions used by Eva for the current analysis. *)letreset(main_ui:main_ui)(moduleA:Analysis.S)=(* Types of the GUI depending on the abstractions used for the analysis. *)letmoduleGui_Types=Gui_types.Make(A.Val)in(* Evaluation functions for the GUI. *)letmoduleGui_Eval=Gui_eval.Make(A)in(* Mandatory: registers the functions that perform an evaluation by
callstack. *)Gui_callstacks_filters.register_to_zone_functions(moduleGui_Eval);(* Input module for building the callstack manager. *)letmoduleInput=structtypevalue=A.Val.tincludeGui_Typesletmake_data_for_lvaluelvalloc=fst(Gui_Eval.make_data_all_callstacksGui_Eval.lval_as_offsm_evloclval)endin(* Builds the "Values" panel on the lower notebook of the GUI. The resulting
function is used to display data by callstacks on the user demand. *)letdisplay_data_by_callstack=Gui_callstacks_manager.createmain_ui(moduleInput)in(* Input module for builting the responses of the GUI. *)letmoduleEval:Eval=structincludeGui_Evalletdisplay_data_by_callstack=display_data_by_callstackendinletmoduleResponses=Select(Eval)in(* Stores the Responses module as a reference. *)responses_ref:=(moduleResponses)(* Checkbox to display/hide the list of red alarms. [panel] is the panel
'Red alarms' created in {!Red}. [box] is the vbox in which the checkbox
will be added. *)letred_checkbox(panel:GObj.widget)(box:GPack.box)=lettooltip="Panel listing the properties which were invalid for some states"inletchk=newWidget.checkbox~label:"Show list of red alarms"~tooltip()inbox#packchk#coerce;letkey_red="Value.show_red"inchk#connect(funb->Gtk_helper.Configuration.(setkey_red(ConfBoolb));ifbthenpanel#misc#show()elsepanel#misc#hide());chk#set(Gtk_helper.Configuration.find_bool~default:truekey_red);;;letmain(main_ui:main_ui)=(* Hide unused functions and variables. Must be registered only once *)lethide,_filter_menu=main_ui#file_tree#add_global_filter~text:"Analyzed by Value only"~key:"value_hide_unused"hide_unused_function_or_varinhide_unused:=hide;main_ui#file_tree#register_reset_extensionsync_filetree;(* Very first display, we need to do a few things by hand *)if!hide_unused()thenmain_ui#file_tree#reset()elsesync_filetreemain_ui#file_tree;resetmain_ui(Analysis.current_analyzer());Analysis.register_hook(resetmain_ui);Design.register_reset_extension(fun_->Gui_callstacks_manager.reset());main_ui#register_source_selector(to_do_on_select);main_ui#register_source_highlighteractive_highlighter;letpanel_red=Gui_red.make_panelmain_uiinmain_ui#register_panel(value_panel(red_checkboxpanel_red));add_keybord_shortcut_evaluatemain_ui;;;let()=Design.register_extensionmain;;(*
Local Variables:
compile-command: "make -C ../../../.."
End:
*)