123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301(**************************************************************************)(* *)(* 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_typestypehistory_elt=|Globalofglobal|LocalizableofPretty_source.localizablemoduleHistoryElt=structincludeDatatype.Make(structincludeDatatype.Undefinedtypet=history_eltletname="History.history_elt"letreprs=List.map(fung->Globalg)Cil_datatype.Global.reprsletmem_project=Datatype.never_any_projectletequale1e2=matche1,e2with|Globalg1,Globalg2->Cil_datatype.Global.equalg1g2|Localizablel1,Localizablel2->Printer_tag.Localizable.equall1l2|(Global_|Localizable_),__->falseend)(* Identify two elements that belong to the same function *)letin_same_fune1e2=letf=function|Global(GFunDecl(_,vi,_)|GFun({svar=vi},_))->(trySome(Globals.Functions.getvi)withNot_found->None)|Localizablel->Pretty_source.kf_of_localizablel|_->Noneinmatchfe1with|None->false|Somef1->matchfe2with|None->false|Somef2->Kernel_function.equalf1f2endtypehistory={back:history_eltlist;current:history_eltoption;forward:history_eltlist;}letdefault_history={back=[];current=None;forward=[];}moduleHistory=Datatype.Make(structincludeDatatype.Undefinedtypet=historyletname="History.history"letreprs=[default_history]letmem_project=Datatype.never_any_projectletprettyfmth=Format.fprintffmt"back %d, cur %b, forward %d"(List.lengthh.back)(h.current<>None)(List.lengthh.forward)end)includeHistorymoduleCurrentHistory=State_builder.Ref(History)(structletname="History.CurrentHistory"letdependencies=[Ast.self]letdefault_=default_historyend)(* This is correct because the implementation makes sure that [.current = None]
implies [.forward = [] && .back = []] *)letis_empty()=(CurrentHistory.get()).current=Noneletcan_go_back()=(CurrentHistory.get()).back<>[]letcan_go_forward()=(CurrentHistory.get()).forward<>[]letdisplay_elt=ref(fun_->())letset_display_elt_callbackf=display_elt:=fletshow_current()=leth=CurrentHistory.get()inOption.iter!display_elth.current;CurrentHistory.sethletback()=leth=CurrentHistory.get()inmatchh.current,h.backwith|Somecur,prev::prevs->leth'={back=prevs;current=Someprev;forward=cur::h.forward}in!display_eltprev;CurrentHistory.seth'|None,prev::prevs->leth'={back=prevs;current=Someprev;forward=h.forward}in!display_eltprev;CurrentHistory.seth'|_,[]->()letforward()=leth=CurrentHistory.get()inmatchh.current,h.forwardwith|Somecur,next::nexts->leth'={back=cur::h.back;current=Somenext;forward=nexts}in!display_eltnext;CurrentHistory.seth'|None,next::nexts->leth'={back=h.back;current=Somenext;forward=nexts}in!display_eltnext;CurrentHistory.seth'|_,[]->()leton_current_history()=leth=CurrentHistory.get()infunf->CurrentHistory.seth;f()letget_current()=(CurrentHistory.get()).currentletpushcur=leth=CurrentHistory.get()inleth'=matchh.currentwith|None->{back=h.back;current=Somecur;forward=[]}|Someprev->ifHistoryElt.equalcurprevthenhelseifHistoryElt.in_same_funcurprevthen{hwithcurrent=Somecur}else{back=prev::h.back;current=Somecur;forward=[]}inCurrentHistory.seth'letset_forwardels=leth=CurrentHistory.get()inleth'={hwithforward=els}inCurrentHistory.seth'letselected_localizable()=match(CurrentHistory.get()).currentwith|None|Some(Global_)->None|Some(Localizableloc)->Somelocletcreate_buttons(menu_manager:Menu_manager.menu_manager)=letrefresh=menu_manager#refreshinmenu_manager#add_plugin~title:"Navigation"[Menu_manager.toolmenubar~sensitive:can_go_back~icon:`GO_BACK~label:"Back"~tooltip:"Go to previous visited source location"(Menu_manager.Unit_callback(fun()->back();refresh()));Menu_manager.toolmenubar~sensitive:can_go_forward~icon:`GO_FORWARD~label:"Forward"~tooltip:"Go to next visited source location"(Menu_manager.Unit_callback(fun()->forward();refresh()));]exceptionFound_globalofglobal(* We build a 'fake' global for [kf], so as to be able to search for it
in the AST. Do not use Kernel_function.get_global, as [kf] is no longer
in the proper project when kf_to_global is called, which leads to crashes. *)letkf_to_globalkf=matchkf.fundecwith|Definition(d,loc)->GFun(d,loc)|Declaration(spec,vi,_,loc)->GFunDecl(spec,vi,loc)lettranslate_history_eltold_helt=lettest_name_fileold_namenew_nameold_locnew_loc=old_name=new_name&&(fstold_loc).Filepath.pos_path=(fstnew_loc).Filepath.pos_pathinletglobalold_g=letiternew_g=letopenCil_typesin(* In the same file, same constructor and same original name *)matchold_g,new_gwith|(GType({torig_name=old_name},old_loc),GType({torig_name=new_name},new_loc))|(GEnumTag({eorig_name=old_name},old_loc),GEnumTag({eorig_name=new_name},new_loc))|(GEnumTagDecl({eorig_name=old_name},old_loc),GEnumTagDecl({eorig_name=new_name},new_loc))|(GCompTag({corig_name=old_name},old_loc),GCompTag({corig_name=new_name},new_loc))|(GCompTagDecl({corig_name=old_name},old_loc),GCompTagDecl({corig_name=new_name},new_loc))|(GVarDecl({vorig_name=old_name},old_loc),GVarDecl({vorig_name=new_name},new_loc))|(GFunDecl(_,{vorig_name=old_name},old_loc),GFunDecl(_,{vorig_name=new_name},new_loc))|(GVar({vorig_name=old_name},_,old_loc),GVar({vorig_name=new_name},_,new_loc))|(GFun({svar={vorig_name=old_name}},old_loc),GFun({svar={vorig_name=new_name}},new_loc))|(GAnnot(Dtype({lt_name=old_name},_),old_loc),GAnnot(Dtype({lt_name=new_name},_),new_loc))|(GAnnot(Daxiomatic(old_name,_,_,_),old_loc),GAnnot(Daxiomatic(new_name,_,_,_),new_loc))|(GAnnot(Dlemma(old_name,_,_,_,_,_),old_loc),GAnnot(Dlemma(new_name,_,_,_,_,_),new_loc))|(GAnnot(Dfun_or_pred({l_var_info={lv_name=old_name}},_),old_loc),GAnnot(Dfun_or_pred({l_var_info={lv_name=new_name}},_),new_loc))whentest_name_fileold_namenew_nameold_locnew_loc->raise(Found_globalnew_g)|GAsm_,GAsm_|GText_,GText_|GPragma_,GPragma_|GAnnot(Dvolatile_,_),GAnnot(Dvolatile_,_)|GAnnot(Dinvariant_,_),GAnnot(Dinvariant_,_)|GAnnot(Dtype_annot_,_),GAnnot(Dtype_annot_,_)|GAnnot(Dmodel_annot_,_),GAnnot(Dmodel_annot_,_)->(* they have no names *)()|_->(* different constructors *)()intryList.iteriter(Ast.get()).globals;NonewithFound_globalnew_g->Somenew_ginletopenPretty_sourceinletopenCil_datatypeinletglobal_Globalg=Option.map(funx->Globalx)(globalg)inmatchold_heltwith|Globalold_g->global_Globalold_g|Localizable(PGlobalold_g)->global_Globalold_g|Localizable(PVDecl(Somekf,_,_))->global_Global(kf_to_globalkf)|Localizable(PStmt(kf,_)|PStmtStart(kf,_)|PLval(Somekf,_,_)|PExp(Somekf,_,_)|PTermLval(Somekf,_,_,_)asloc)->beginmatchglobal(kf_to_globalkf)with|None->(* The kernel function can't be found nothing to say *)None|Someg->(* Try to stay at the same offset in the function *)letold_kf_loc=fst(Kernel_function.get_locationkf)inletold_loc=matchki_of_localizablelocwith|Kstmts->fst(Stmt.locs)|Kglobal->(* fallback *)old_kf_locinletoffset=old_loc.Filepath.pos_lnum-old_kf_loc.Filepath.pos_lnuminletnew_kf_loc=fst(Global.locg)inletnew_loc={new_kf_locwithFilepath.pos_lnum=new_kf_loc.Filepath.pos_lnum+offset;Filepath.pos_cnum=old_loc.Filepath.pos_cnum;}inmatchPrinter_tag.loc_to_localizablenew_locwith|None->(* the line is unknown *)Some(Globalg)|Somelocali->beginmatchkf_of_localizablelocaliwith|None->(* not in a kf so return the start of the function *)Some(Globalg)|Somekfwhennot(Global.equal(kf_to_globalkf)g)->(* Fall in the wrong global, so return the start of the function *)Some(Globalg)|_->(* Fall in the correct global *)Some(Localizablelocali)endend|Localizable(PLval(None,_,_)|PExp(None,_,_)|PTermLval(None,_,_,_)|PVDecl(None,_,_)|PType_)->(* no names useful? *)None|Localizable(PIP_)->(* no names available *)None(*
Local Variables:
compile-command: "make -C ../../.."
End:
*)