123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586(**************************************************************************)(* *)(* This file is part of WP plug-in of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* CEA (Commissariat a l'energie atomique et aux energies *)(* 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). *)(* *)(**************************************************************************)(* -------------------------------------------------------------------------- *)(* --- Dependencies of Logic Definitions --- *)(* -------------------------------------------------------------------------- *)openCilopenCil_typesopenCil_datatypeopenClabelsopenVisitor(* -------------------------------------------------------------------------- *)(* --- Name Utilities --- *)(* -------------------------------------------------------------------------- *)lettrimname=letrecfirstskn=ifk<n&&s.[k]='_'thenfirsts(succk)nelsekinletreclastsk=ifk>=0&&s.[k]='_'thenlasts(predk)elsekinletn=String.lengthnameinifn>0thenif(name.[0]='_'||name.[n-1]='_')thenletp=firstname0ninletq=lastname(predn)inifp<=qthenletname=String.subnamep(q+1-p)inmatchname.[0]with|'0'..'9'->"_"^name|_->nameelse"_"elsenameelse"_"(* -------------------------------------------------------------------------- *)(* --- Definition Blocks --- *)(* -------------------------------------------------------------------------- *)typelogic_lemma={lem_name:string;lem_position:Filepath.position;lem_types:stringlist;lem_labels:logic_labellist;lem_predicate:toplevel_predicate;lem_depends:logic_lemmalist;(* global lemmas declared before in AST order (in reverse order) *)lem_attrs:attributes;}typeaxiomatic={ax_name:string;ax_position:Filepath.position;ax_property:Property.t;mutableax_types:logic_type_infolist;mutableax_logics:logic_infolist;mutableax_lemmas:logic_lemmalist;mutableax_reads:Varinfo.Set.t;(* read-only *)}typelogic_section=|Toplevelofint|Axiomaticofaxiomaticletis_global_axiomaticax=ax.ax_types=[]&&ax.ax_logics=[]&&ax.ax_lemmas<>[]moduleSMap=Datatype.String.MapmoduleTMap=Logic_type_info.MapmoduleLMap=Logic_info.MapmoduleLSet=Logic_info.Set(* -------------------------------------------------------------------------- *)(* --- Usage and Dependencies --- *)(* -------------------------------------------------------------------------- *)typeinductive_case={ind_logic:logic_info;ind_case:string;mutableind_call:LabelSet.tLabelMap.t;}typedatabase={mutablecases:inductive_caselistLMap.t;mutableclash:LSet.tSMap.t;mutablenames:stringLMap.t;mutabletypes:logic_sectionTMap.t;mutablelogics:logic_sectionLMap.t;mutablelemmas:(logic_lemma*logic_section)SMap.t;mutablerecursives:LSet.t;mutableaxiomatics:axiomaticSMap.t;mutableproofcontext:logic_lemmalist;}letempty_database()={cases=LMap.empty;names=LMap.empty;clash=SMap.empty;types=TMap.empty;logics=LMap.empty;lemmas=SMap.empty;recursives=LSet.empty;axiomatics=SMap.empty;proofcontext=[];}moduleDatabaseType=Datatype.Make(structtypet=databaseincludeDatatype.Serializable_undefinedletreprs=[empty_database()]letname="Wp.LogicUsage.DatabaseType"end)moduleDatabase=State_builder.Ref(DatabaseType)(structletname="Wp.LogicUsage.Database"letdependencies=[Ast.self;Annotations.code_annot_state]letdefault=empty_databaseend)letpp_logicfmtl=Printer.pp_logic_varfmtl.l_var_info(* -------------------------------------------------------------------------- *)(* --- Overloading --- *)(* -------------------------------------------------------------------------- *)letbasenamex=trimx.vorig_nameletcompute_logicnamel=letd=Database.get()intryLMap.findld.nameswithNot_found->letbase=l.l_var_info.lv_nameinletover=trySMap.findbased.clashwithNot_found->LSet.empty(*TODO: Undetected usage -> overloading issue *)inmatchLSet.elementsoverwith|[]|[_]->d.names<-LMap.addlbased.names;base|symbols->letrecregisterk=function|l::ls->letname=Printf.sprintf"%s_%d_"basekind.names<-LMap.addlnamed.names;register(succk)ls|[]->()inregister1symbols;LMap.findld.namesletis_overloadedl=letd=Database.get()intryLSet.cardinal(SMap.findl.l_var_info.lv_named.clash)>1withNot_found->falseletpp_profilefmtl=Format.fprintffmt"%s"l.l_var_info.lv_name;matchl.l_profilewith|[]->()|x::xs->Format.fprintffmt"@[<hov 1>(%a"Printer.pp_logic_typex.lv_type;List.iter(funy->Format.fprintffmt",@,%a"Printer.pp_logic_typey.lv_type)xs;Format.fprintffmt")@]"(* -------------------------------------------------------------------------- *)(* --- Utilities --- *)(* -------------------------------------------------------------------------- *)letip_lemmal=Property.ip_lemma{il_name=l.lem_name;il_labels=l.lem_labels;il_args=l.lem_types;il_loc=(l.lem_position,l.lem_position);il_attrs=l.lem_attrs;il_pred=l.lem_predicate;}letlemma_of_global~context=function|Dlemma(name,labels,types,pred,attrs,loc)->{lem_name=name;lem_position=fstloc;lem_types=types;lem_labels=labels;lem_predicate=pred;lem_depends=context;lem_attrs=attrs;}|_->assertfalseletpopulatea~context=function|Dfun_or_pred(l,_)->a.ax_logics<-l::a.ax_logics|Dtype(t,_)->a.ax_types<-t::a.ax_types|Dlemma_asg->a.ax_lemmas<-lemma_of_global~contextg::a.ax_lemmas|_->()letip_of_axiomaticg=matchProperty.ip_of_global_annotation_singlegwith|None->assertfalse|Someip->ipletaxiomatic_of_global~context=function|Daxiomatic(name,globals,_,loc)asg->leta={ax_name=name;ax_position=fstloc;ax_property=ip_of_axiomaticg;ax_reads=Varinfo.Set.empty;ax_types=[];ax_lemmas=[];ax_logics=[];}inList.iter(populatea~context)globals;a.ax_types<-List.reva.ax_types;a.ax_logics<-List.reva.ax_logics;a.ax_lemmas<-List.reva.ax_lemmas;a|_->assertfalseletregister_logicdsectionl=letname=l.l_var_info.lv_nameinletover=tryLSet.addl(SMap.findnamed.clash)withNot_found->LSet.singletonlinbegind.clash<-SMap.addnameoverd.clash;d.logics<-LMap.addlsectiond.logics;endletregister_lemmadsectionl=begind.lemmas<-SMap.addl.lem_name(l,section)d.lemmas;endletregister_typedsectiont=begind.types<-TMap.addtsectiond.types;endletregister_axiomaticda=begind.axiomatics<-SMap.adda.ax_namead.axiomatics;endletregister_caseslinds=letd=Database.get()ind.cases<-LMap.addlindsd.cases(* -------------------------------------------------------------------------- *)(* --- Adding a label called in an inductive case --- *)(* -------------------------------------------------------------------------- *)(* calls : LabelSet.t LabelMap.t
Given an inductive phi{...A...}
In case H{...B...}, have a call to phi{...B...}
Then: ( A \in calls[B] ).
*)letadd_callcallsl_al_b=leta=Clabels.of_logicl_ainletb=Clabels.of_logicl_binlets=tryLabelSet.adda(LabelMap.findbcalls)withNot_found->LabelSet.singletonainLabelMap.addbscalls(* -------------------------------------------------------------------------- *)(* --- Visitor --- *)(* -------------------------------------------------------------------------- *)classvisitor=object(self)inheritVisitor.frama_c_inplacevaldatabase=Database.get()valmutablecaller:logic_infooption=Nonevalmutableaxiomatic:axiomaticoption=Nonevalmutableinductive:inductive_caseoption=Nonevalmutabletoplevel=0methodprivatesection=matchaxiomaticwith|None->Topleveltoplevel|Somea->Axiomaticamethodprivatedo_varx=matchaxiomaticwith|None->()|Somea->a.ax_reads<-Varinfo.Set.addxa.ax_readsmethodprivatedo_lvarx=tryself#do_call(Logic_env.find_logic_consx)[]withNot_found->()methodprivatedo_callllabels=matchinductivewith|Somecase->ifLogic_info.equallcase.ind_logicthencase.ind_call<-List.fold_left2add_callcase.ind_calll.l_labelslabels|None->matchcallerwith|None->()|Somef->ifLogic_info.equalflthendatabase.recursives<-LSet.addfdatabase.recursivesmethodprivatedo_casel(case,_labels,_types,pnamed)=beginletindcase={ind_logic=l;ind_case=case;ind_call=LabelMap.empty;}ininductive<-Someindcase;ignore(visitFramacPredicate(self:>frama_c_visitor)pnamed);inductive<-None;indcaseend(* --- LVALUES --- *)method!vlval=function|(Varx,_)->self#do_varx;DoChildren|_->DoChildrenmethod!vterm_lval=function|(TVar{lv_origin=Somex},_)->self#do_varx;DoChildren|(TVarx,_)->self#do_lvarx;DoChildren|_->DoChildren(* --- TERMS --- *)method!vterm_node=function|Tapp(l,labels,_)->self#do_callllabels;DoChildren|_->DoChildren(* --- PREDICATE --- *)method!vpredicate_node=function|Papp(l,labels,_)->self#do_callllabels;DoChildren|_->DoChildrenmethod!vannotationglobal=matchglobalwith(* --- AXIOMATICS --- *)|Daxiomatic_->beginletpf=database.proofcontextinletax=axiomatic_of_global~context:pfglobalinregister_axiomaticdatabaseax;axiomatic<-Someax;DoChildrenPost(fung->ifnot(is_global_axiomaticax)thendatabase.proofcontext<-pf;axiomatic<-None;toplevel<-succtoplevel;g)end(* --- LOGIC INFO --- *)|Dtype_annot(l,_)|Dinvariant(l,_)|Dfun_or_pred(l,_)->beginregister_logicdatabaseself#sectionl;matchl.l_bodywith|LBnonewhenaxiomatic=None->SkipChildren|LBnone|LBreads_|LBterm_|LBpred_->caller<-Somel;DoChildrenPost(fung->caller<-None;g)|LBinductivecases->register_casesl(List.map(self#do_casel)cases);SkipChildrenend(* --- LEMMAS --- *)|Dlemma_->letlem=lemma_of_global~context:database.proofcontextglobalinregister_lemmadatabaseself#sectionlem;ifLogic_utils.use_predicatelem.lem_predicate.tp_kindthendatabase.proofcontext<-lem::database.proofcontext;SkipChildren|Dtype(t,_)->register_typedatabaseself#sectiont;SkipChildren(* --- OTHERS --- *)|Dvolatile_|Dmodel_annot_|Dextended_->SkipChildrenmethod!vfunc_=Cil.SkipChildrenendletcompute()=Wp_parameters.feedback~ontty:`Transient"Collecting axiomatic usage";Visitor.visitFramacFile(newvisitor)(Ast.get())(* -------------------------------------------------------------------------- *)(* --- External API --- *)(* -------------------------------------------------------------------------- *)let(compute,_)=State_builder.apply_once"LogicUsage.compute"[Ast.self;Annotations.code_annot_state]computeletis_recursivel=compute();letd=Database.get()inLSet.memld.recursivesletget_induction_labelslcase=compute();tryletd=Database.get()inletcases=LMap.findld.casesintry(List.find(funi->i.ind_case=case)cases).ind_callwithNot_found->Wp_parameters.fatal"No case '%s' for inductive '%s'"casel.l_var_info.lv_namewithNot_found->Wp_parameters.fatal"Non-inductive '%s'"l.l_var_info.lv_nameletaxiomatica=compute();tryletd=Database.get()inSMap.findad.axiomaticswithNot_found->Wp_parameters.fatal"Axiomatic '%s' undefined"aletsection_of_typet=compute();tryletd=Database.get()inTMap.findtd.typeswithNot_found->Wp_parameters.fatal"Logic type '%s' undefined"t.lt_nameletsection_of_logicl=compute();tryletd=Database.get()inLMap.findld.logicswithNot_found->Wp_parameters.fatal"Logic '%a' undefined"pp_logiclletget_lemmal=compute();tryletd=Database.get()inSMap.findld.lemmaswithNot_found->Wp_parameters.fatal"Lemma '%s' undefined"lletiter_lemmasf=compute();letd=Database.get()inSMap.iter(fun_name(lem,_)->flem)d.lemmasletfold_lemmasf=compute();letd=Database.get()inSMap.fold(fun_name(lem,_)->flem)d.lemmasletlogic_lemmal=fst(get_lemmal)letsection_of_lemmal=snd(get_lemmal)letproof_context()=(* No need for compute: if no lemma, database is empty ! *)letd=Database.get()ind.proofcontext(* -------------------------------------------------------------------------- *)(* --- Dump API --- *)(* -------------------------------------------------------------------------- *)letpp_typefmtt=Format.fprintffmt" * type '%s'@\n"t.lt_nameletpp_sigfmtkindl=beginFormat.fprintffmt" * %s '%s'@\n"kind(compute_logicnamel);ifis_overloadedlthenFormat.fprintffmt" profile %a@\n"pp_profilel;ifis_recursivelthenFormat.fprintffmt" recursive@\n";endletpp_declfmtdl=begintryletcases=LMap.findld.casesinpp_sigfmt"inductive"l;List.iter(funind->Format.fprintffmt" @[case %s:"ind.ind_case;LabelMap.iter(funls->Format.fprintffmt"@ @[<hov 2>{%a:"Clabels.prettyl;LabelSet.iter(funl->Format.fprintffmt"@ %a"Clabels.prettyl)s;Format.fprintffmt"}@]")ind.ind_call;Format.fprintffmt"@]@\n")cases;withNot_found->letkind=ifl.l_type=Nonethen"predicate"else"function"inpp_sigfmtkindl;endletpp_lemmafmtl=Format.fprintffmt" * %a '%s'@\n"Cil_printer.pp_lemma_kindl.lem_predicate.tp_kindl.lem_nameletget_namel=compute();compute_logicnamelletpp_sectionfmt=function|Toplevel0->Format.fprintffmt"Toplevel"|Topleveln->Format.fprintffmt"Toplevel(%d)"n|Axiomatica->Format.fprintffmt"Axiomatic '%s'"a.ax_nameletdump()=compute();Log.print_on_outputbeginfunfmt->letd=Database.get()inSMap.iter(fun_a->Format.fprintffmt"Axiomatic %s {@\n"a.ax_name;List.iter(pp_typefmt)a.ax_types;List.iter(pp_declfmtd)a.ax_logics;List.iter(pp_lemmafmt)a.ax_lemmas;Format.fprintffmt"}@\n")d.axiomatics;TMap.iter(funts->Format.fprintffmt" * type '%s' in %a@\n"t.lt_namepp_sections)d.types;LMap.iter(funls->Format.fprintffmt" * logic '%a' in %a@\n"pp_logiclpp_sections)d.logics;SMap.iter(funl(lem,s)->Format.fprintffmt" * %a '%s' in %a@\n"Cil_printer.pp_lemma_kindlem.lem_predicate.tp_kindlpp_sections)d.lemmas;Format.fprintffmt"-------------------------------------------------@.";end