1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-2024 *)(* 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). *)(* *)(**************************************************************************)openDatamoduleMd=MarkdownmoduleJs=Yojson.Basic.UtilmodulePkg=PackageopenCil_typesletpackage=Pkg.package~title:"Ast Services"~name:"ast"~readme:"ast.md"()(* -------------------------------------------------------------------------- *)(* --- Compute Ast --- *)(* -------------------------------------------------------------------------- *)let()=Request.register~package~kind:`EXEC~name:"compute"~descr:(Md.plain"Ensures that AST is computed")~input:(moduleJunit)~output:(moduleJunit)Ast.computeletast_changed_signal=Request.signal~package~name:"changed"~descr:(Md.plain"Emitted when the AST has been changed")letast_changed()=Request.emitast_changed_signalletast_update_hookf=beginAst.add_hook_on_updatef;Ast.apply_after_computed(fun_->f());endlet()=ast_update_hookast_changedlet()=Annotations.add_hook_on_changeast_changed(* -------------------------------------------------------------------------- *)(* --- File Positions --- *)(* -------------------------------------------------------------------------- *)modulePosition=structtypet=Filepath.positionletjtype=Data.declare~package~name:"source"~descr:(Md.plain"Source file positions.")(Jrecord["dir",Jstring;"base",Jstring;"file",Jstring;"line",Jnumber;])letto_jsonp=letpath=Filepath.(Normalized.to_pretty_stringp.pos_path)inletfile=ifServer_parameters.has_relative_filepath()thenpathelse(p.Filepath.pos_path:>string)in`Assoc["dir",`String(Filename.dirnamepath);"base",`String(Filename.basenamepath);"file",`Stringfile;"line",`Intp.Filepath.pos_lnum;]letof_jsonjs=letfail()=failure_from_type_error"Invalid source format"jsinmatchjswith|`Assocassoc->beginmatchList.assoc"file"assoc,List.assoc"line"assocwith|`Stringpath,`Intline->Log.source~file:(Filepath.Normalized.of_stringpath)~line|_,_->fail()|exceptionNot_found->fail()end|_->fail()end(* -------------------------------------------------------------------------- *)(* --- Generic Markers --- *)(* -------------------------------------------------------------------------- *)moduletypeTagInfo=sigtypetvalname:stringvaldescr:stringvalcreate:t->stringmoduleH:Hashtbl.Swithtypekey=tendmoduletypeTag=sigincludeData.Svalindex:t->stringvalfind:string->tendmoduleMakeTag(T:TagInfo):sigincludeTagwithtypet=T.tvaliter:(t*string->unit)->unitvalhook:(t*string->unit)->unitend=structtypet=T.ttypeindex={tags:stringT.H.t;items:(string,T.t)Hashtbl.t;}letindex()={tags=T.H.create0;items=Hashtbl.create0;}letmodule_name=String.capitalize_asciiT.namemoduleTYPE:Datatype.Swithtypet=index=Datatype.Make(structtypet=indexincludeDatatype.Undefinedletreprs=[index()]letname=Printf.sprintf"Server.Kernel_ast.%s.TYPE"module_nameletmem_project=Datatype.never_any_projectend)moduleSTATE=State_builder.Ref(TYPE)(structletname=Printf.sprintf"Server.Kernel_ast.%s.STATE"module_nameletdependencies=[]letdefault=indexend)letiterf=T.H.iter(funkeystr->f(key,str))(STATE.get()).tagslethooks=ref[]lethookf=hooks:=!hooks@[f]letindexitem=let{tags;items}=STATE.get()intryT.H.findtagsitemwithNot_found->lettag=T.createiteminT.H.addtagsitemtag;Hashtbl.additemstagitem;List.iter(funfn->fn(item,tag))!hooks;tagletfindtag=Hashtbl.find(STATE.get()).itemstagletjtype=Data.declare~package~name:T.name~descr:(Md.plainT.descr)(Pkg.JkeyT.name)letto_jsonitem=`String(indexitem)letof_jsonjs=tryfind(Js.to_stringjs)withNot_found->Data.failure"invalid %s (%a)"T.nameJson.pp_dumpjsendmoduleDecl=MakeTag(structopenPrinter_tagtypet=declarationletname="decl"letdescr="AST Declarations markers"moduleH=Declaration.Hashtblletkid=ref0letcreate=function|SEnum_->Printf.sprintf"#E%d"(incrkid;!kid)|SComp_->Printf.sprintf"#C%d"(incrkid;!kid)|SType_->Printf.sprintf"#T%d"(incrkid;!kid)|SGlobalvi->Printf.sprintf"#G%d"vi.vid|SFunctionkf->Printf.sprintf"#F%d"@@Kernel_function.get_idkfend)moduleMarker=MakeTag(structopenPrinter_tagtypet=localizableletname="marker"letdescr="Localizable AST markers"moduleH=Localizable.Hashtblletkid=ref0letcreate=function|PStmt(_,s)->Printf.sprintf"#s%d"s.sid|PStmtStart(_,s)->Printf.sprintf"#k%d"s.sid|PVDecl(_,_,v)->Printf.sprintf"#v%d"v.vid|PLval_->Printf.sprintf"#l%d"(incrkid;!kid)|PExp(_,_,e)->Printf.sprintf"#e%d"e.eid|PTermLval_->Printf.sprintf"#t%d"(incrkid;!kid)|PGlobal_->Printf.sprintf"#g%d"(incrkid;!kid)|PIP_->Printf.sprintf"#p%d"(incrkid;!kid)|PType_->Printf.sprintf"#y%d"(incrkid;!kid)end)modulePrinterTag=Printer_tag.Make(structlettag=Marker.indexend)(* -------------------------------------------------------------------------- *)(* --- Ast Data --- *)(* -------------------------------------------------------------------------- *)moduleLval=structopenPrinter_tagtypet=kinstr*lvalletjtype=Marker.jtypeletto_json(kinstr,lval)=letkf=matchkinstrwith|Kglobal->None|Kstmtstmt->Some(Kernel_function.find_englobing_kfstmt)inMarker.to_json(PLval(kf,kinstr,lval))letfind=function|PLval(_,kinstr,lval)->kinstr,lval|PVDecl(_,kinstr,vi)->kinstr,Cil.varvi|PGlobal(GVar(vi,_,_)|GVarDecl(vi,_))->Kglobal,Cil.varvi|_->raiseNot_foundletmemtag=trylet_=findtagintruewithNot_found->falseletof_jsonjs=tryfind(Marker.of_jsonjs)withNot_found->Data.failure"not a lval marker"endmoduleStmt=structtypet=stmtletjtype=Marker.jtypeletto_jsonst=letkf=Kernel_function.find_englobing_kfstinMarker.to_json(PStmtStart(kf,st))letof_jsonjs=letopenPrinter_taginmatchMarker.of_jsonjswith|PStmt(_,st)|PStmtStart(_,st)->st|_->Data.failure"not a stmt marker"endmoduleKinstr=structtypet=kinstrletjtype=Pkg.JoptionMarker.jtypeletto_json=function|Kglobal->`Null|Kstmtst->Stmt.to_jsonstletof_json=function|`Null->Kglobal|js->Kstmt(Stmt.of_jsonjs)end(* -------------------------------------------------------------------------- *)(* --- Declaration Attributes --- *)(* -------------------------------------------------------------------------- *)moduleDeclKind=structopenPrinter_tagtypet=declarationletjtype=Data.declare~package~name:"declKind"~descr:(Md.plain"Declaration kind")(Junion[Jkey"ENUM";Jkey"UNION";Jkey"STRUCT";Jkey"TYPEDEF";Jkey"GLOBAL";Jkey"FUNCTION";])letto_json=function|SEnum_->`String"ENUM"|SComp{cstruct=true}->`String"STRUCT"|SComp{cstruct=false}->`String"UNION"|SType_->`String"TYPEDEF"|SGlobal_->`String"GLOBAL"|SFunction_->`String"FUNCTION"endmoduleDeclAttributes=structopenPrinter_tagletmodel=States.model()(* We must iterate over all known declaration in the Ast, contrarily to
markers, for which we ony need attributes of already generated markers. *)letiter_declarationf=ifAst.is_computed()thenletmarked=Declaration.Hashtbl.create0inCil.iterGlobals(Ast.get())(fung->matchdeclaration_of_globalgwith|None->()|Somed->ifnot@@Declaration.Hashtbl.memmarkeddthenbeginDeclaration.Hashtbl.addmarkedd();f(d,Decl.indexd)end)let()=States.column~name:"kind"~descr:(Md.plain"Declaration kind")~data:(moduleDeclKind)~get:fstmodellet()=States.column~name:"self"~descr:(Md.plain"Declaration's marker")~data:(moduleMarker)~get:(fun(decl,_)->localizable_of_declarationdecl)modellet()=States.column~name:"name"~descr:(Md.plain"Declaration identifier")~data:(moduleJstring)~get:(fun(decl,_)->name_of_declarationdecl)modellet()=States.column~name:"label"~descr:(Md.plain"Declaration label (uncapitalized kind & name)")~data:(moduleJstring)~get:(fun(decl,_)->Pretty_utils.to_stringpp_declarationdecl)modellet()=States.column~name:"source"~descr:(Md.plain"Source location")~data:(modulePosition)~get:(fun(decl,_)->fst@@loc_of_declarationdecl)modelletarray=States.register_array~package~name:"declAttributes"~descr:(Md.plain"Declaration attributes")~key:snd~keyName:"decl"~keyType:Decl.jtype~iter:iter_declaration~add_reload_hook:ast_update_hookmodellet()=Decl.hook(States.updatearray)end(* -------------------------------------------------------------------------- *)(* --- Decl Printer --- *)(* -------------------------------------------------------------------------- *)letprint_global_astglobal=letstacked_libc=Kernel.PrintLibc.get()intryifnotstacked_libcthenKernel.PrintLibc.settrue;letprinter=PrinterTag.(with_unfold_precond(fun_->true)pp_global)inletast=Jbuffer.to_jsonprinterglobalinifnotstacked_libcthenKernel.PrintLibc.setfalse;astwitherr->ifnotstacked_libcthenKernel.PrintLibc.setfalse;raiseerrlet()=Request.register~package~kind:`GET~name:"printDeclaration"~descr:(Md.plain"Prints an AST Declaration")~signals:[ast_changed_signal]~input:(moduleDecl)~output:(moduleJtext)(fund->print_global_ast@@Printer_tag.definition_of_declarationd)(* -------------------------------------------------------------------------- *)(* --- Marker Attributes --- *)(* -------------------------------------------------------------------------- *)moduleMarkerKind=structopenPrinter_tagtypet=localizableletjtype=Data.declare~package~name:"markerKind"~descr:(Md.plain"Marker kind")(Junion[Jkey"STMT";Jkey"LFUN";Jkey"DFUN";Jkey"LVAR";Jkey"DVAR";Jkey"LVAL";Jkey"EXP";Jkey"TERM";Jkey"TYPE";Jkey"PROPERTY";Jkey"DECLARATION";])letto_json=function|PStmt_|PStmtStart_->`String"STMT"|PVDecl(_,Kglobal,vi)->`String(ifGlobals.Functions.memvithen"DFUN"else"DVAR")|PVDecl_->`String"DVAR"|PTermLval(_,_,_,(TVar{lv_origin=Somevi},TNoOffset))|PLval(_,_,(Varvi,NoOffset))->`String(ifGlobals.Functions.memvithen"LFUN"else"LVAR")|PLval_->`String"LVAL"|PExp_->`String"EXP"|PTermLval_->`String"TERM"|PType_->`String"TYPE"|PIP_->`String"PROPERTY"|PGlobal_->`String"DECLARATION"endmoduleMarkerAttributes=structopenPrinter_tagletlabel_kind~shortm=matchvarinfo_of_localizablemwith|Somevi->ifGlobals.Functions.memvithen"Function"elseifvi.vglobthenifshortthen"Global"else"Global Variable"elseifvi.vformalthenifshortthen"Formal"else"Formal Parameter"elseifvi.vtempthenifshortthen"Temp"else"Temporary Variable (generated)"elseifshortthen"Local"else"Local Variable"|None->matchmwith|PStmt_|PStmtStart_->ifshortthen"Stmt"else"Statement"|PLval_->ifshortthen"Lval"else"L-value"|PTermLval_->ifshortthen"Lval"else"ACSL L-value"|PVDecl_->assertfalse|PExp_->ifshortthen"Expr"else"Expression"|PIP_->ifshortthen"Prop"else"Property"|PGlobal(GType_|GCompTag_|GEnumTag_|GEnumTagDecl_)|PType_->"Type"|PGlobal_->ifshortthen"Decl"else"Declaration"letdescr_localizablefmt=function|PGlobal(GType(ti,_))->PrinterTag.pp_typfmt(TNamed(ti,[]))|PGlobal(GCompTag(ci,_)|GCompTagDecl(ci,_))->PrinterTag.pp_typfmt(TComp(ci,[]))|PGlobal(GEnumTag(ei,_)|GEnumTagDecl(ei,_))->PrinterTag.pp_typfmt(TEnum(ei,[]))|g->pp_localizablefmtgletmodel=States.model()let()=States.column~name:"kind"~descr:(Md.plain"Marker kind (key)")~data:(moduleMarkerKind)~get:fstmodellet()=States.option~name:"scope"~descr:(Md.plain"Marker Scope (where it is printed in)")~data:(moduleDecl)~get:(fun(tag,_)->declaration_of_localizabletag)modellet()=States.option~name:"definition"~descr:(Md.plain"Marker's Target Definition (when applicable)")~data:(moduleMarker)~get:(fun(tag,_)->definition_of_localizabletag)modellet()=States.column~name:"labelKind"~descr:(Md.plain"Marker kind label")~data:(moduleJalpha)~get:(fun(tag,_)->label_kind~short:truetag)modellet()=States.column~name:"titleKind"~descr:(Md.plain"Marker kind title")~data:(moduleJalpha)~get:(fun(tag,_)->label_kind~short:falsetag)modellet()=States.option~name:"name"~descr:(Md.plain"Marker identifier (when applicable)")~data:(moduleJalpha)~get:(fun(tag,_)->Printer_tag.name_of_localizabletag)modellet()=States.column~name:"descr"~descr:(Md.plain"Marker description")~data:(moduleJstring)~get:(fun(tag,_)->Rich_text.to_stringdescr_localizabletag)modellet()=letget(tag,_)=letpos=fst(Printer_tag.loc_of_localizabletag)inifCil_datatype.Position.(equalunknownpos)thenNoneelseSomeposinStates.option~name:"sloc"~descr:(Md.plain"Source location")~data:(modulePosition)~getmodelletarray=States.register_array~package~name:"markerAttributes"~descr:(Md.plain"Marker attributes")~key:snd~keyName:"marker"~keyType:Marker.jtype~iter:Marker.iter~add_reload_hook:ast_update_hookmodellet()=Marker.hook(States.updatearray)end(* -------------------------------------------------------------------------- *)(* --- Functions --- *)(* -------------------------------------------------------------------------- *)let()=Request.register~package~kind:`GET~name:"getMainFunction"~descr:(Md.plain"Get the current 'main' function.")~input:(moduleJunit)~output:(moduleJoption(Decl))beginfun()->trySome(SFunction(fst@@Globals.entry_point()))withGlobals.No_such_entry_point_->Noneendlet()=Request.register~package~kind:`GET~name:"getFunctions"~descr:(Md.plain"Collect all functions in the AST")~input:(moduleJunit)~output:(moduleJlist(Decl))beginfun()->letpool=ref[]inGlobals.Functions.iter(funkf->pool:=Printer_tag.SFunctionkf::!pool);List.rev!poolendmoduleFunctions=structletkeykf=Printf.sprintf"kf#%d"(Kernel_function.get_idkf)letsignaturekf=letg=Kernel_function.get_globalkfinletlibc=Kernel.PrintLibc.get()intryifnotlibcthenKernel.PrintLibc.settrue;lettxt=Rich_text.to_stringPrinter_tag.pp_localizable(PGlobalg)inifnotlibcthenKernel.PrintLibc.setfalse;ifKernel_function.is_entry_pointkfthen(txt^" /* main */")elsetxtwitherr->ifnotlibcthenKernel.PrintLibc.setfalse;raiseerrletis_builtinkf=Cil_builtins.has_fc_builtin_attr(Kernel_function.get_vikf)letis_externkf=letvi=Kernel_function.get_vikfinvi.vstorage=Externletiterf=Globals.Functions.iter(funkf->letname=Kernel_function.get_namekfinifnot(Ast_info.start_with_frama_c_builtinname)thenfkf)letarray:kernel_functionStates.array=beginletmodel=States.model()inStates.columnmodel~name:"decl"~descr:(Md.plain"Declaration Tag")~data:(moduleDecl)~get:(funkf->Printer_tag.SFunctionkf);States.columnmodel~name:"name"~descr:(Md.plain"Name")~data:(moduleData.Jalpha)~get:Kernel_function.get_name;States.columnmodel~name:"signature"~descr:(Md.plain"Signature")~data:(moduleData.Jstring)~get:signature;States.columnmodel~name:"main"~descr:(Md.plain"Is the function the main entry point")~data:(moduleData.Jbool)~default:false~get:Kernel_function.is_entry_point;States.columnmodel~name:"defined"~descr:(Md.plain"Is the function defined?")~data:(moduleData.Jbool)~default:false~get:Kernel_function.is_definition;States.columnmodel~name:"stdlib"~descr:(Md.plain"Is the function from the Frama-C stdlib?")~data:(moduleData.Jbool)~default:false~get:Kernel_function.is_in_libc;States.columnmodel~name:"builtin"~descr:(Md.plain"Is the function a Frama-C builtin?")~data:(moduleData.Jbool)~default:false~get:is_builtin;States.columnmodel~name:"extern"~descr:(Md.plain"Is the function extern?")~data:(moduleData.Jbool)~default:false~get:is_extern;States.columnmodel~name:"sloc"~descr:(Md.plain"Source location")~data:(modulePosition)~get:(funkf->fst(Kernel_function.get_locationkf));States.register_arraymodel~package~key~name:"functions"~descr:(Md.plain"AST Functions")~iter~add_reload_hook:ast_update_hookendend(* -------------------------------------------------------------------------- *)(* --- Global variables --- *)(* -------------------------------------------------------------------------- *)moduleGlobalVars=structletkeyvi=Printf.sprintf"vi#%d"vi.vidlet_:varinfoStates.array=letmodel=States.model()inStates.columnmodel~name:"decl"~descr:(Md.plain"Declaration Tag")~data:(moduleDecl)~get:(funvi->Printer_tag.SGlobalvi);States.columnmodel~name:"name"~descr:(Md.plain"Name")~data:(moduleData.Jalpha)~get:(funvi->vi.vname);States.columnmodel~name:"type"~descr:(Md.plain"Type")~data:(moduleJstring)~get:(funvi->Rich_text.to_stringPrinter.pp_typvi.vtype);States.columnmodel~name:"stdlib"~descr:(Md.plain"Is the variable from the Frama-C stdlib?")~data:(moduleData.Jbool)~get:(funvi->Cil.is_in_libcvi.vattr);States.columnmodel~name:"extern"~descr:(Md.plain"Is the variable extern?")~data:(moduleData.Jbool)~get:(funvi->vi.vstorage=Extern);States.columnmodel~name:"const"~descr:(Md.plain"Is the variable const?")~data:(moduleData.Jbool)~get:(funvi->Cil.isGlobalInitConstvi);States.columnmodel~name:"volatile"~descr:(Md.plain"Is the variable volatile?")~data:(moduleData.Jbool)~get:(funvi->Cil.isVolatileTypevi.vtype);States.columnmodel~name:"ghost"~descr:(Md.plain"Is the variable ghost?")~data:(moduleData.Jbool)~get:(funvi->Cil.isGhostTypevi.vtype);States.columnmodel~name:"init"~descr:(Md.plain"Is the variable explicitly initialized?")~data:(moduleData.Jbool)~get:(funvi->Option.is_some(Globals.Vars.findvi).init);States.columnmodel~name:"source"~descr:(Md.plain"Is the variable in the source code?")~data:(moduleData.Jbool)~get:(funvi->vi.vsource);States.columnmodel~name:"sloc"~descr:(Md.plain"Source location")~data:(modulePosition)~get:(funvi->fstvi.vdecl);States.register_arraymodel~package~key~name:"globals"~descr:(Md.plain"AST global variables")~iter:(funf->Globals.Vars.iter(funvi_init->fvi))~add_reload_hook:ast_update_hookend(* -------------------------------------------------------------------------- *)(* --- Marker Information --- *)(* -------------------------------------------------------------------------- *)moduleInformation=structtypeinfo={id:string;rank:int;label:string;(* short name *)title:string;(* full title name *)descr:string;(* description for information values *)enable:unit->bool;pretty:Format.formatter->Printer_tag.localizable->unit}(* Info markers serialization *)moduleS=structtypet=(info*Jtext.t)letjtype=Package.(Jrecord["id",Jstring;"label",Jstring;"title",Jstring;"descr",Jstring;"text",Jtext.jtype;])letof_json_=failwith"Information.Info"letto_json(info,text)=`Assoc["id",`Stringinfo.id;"label",`Stringinfo.label;"title",`Stringinfo.title;"descr",`Stringinfo.descr;"text",text;]end(* Info markers registry *)letrankId=ref0letregistry:(string,info)Hashtbl.t=Hashtbl.create0letjtextppmarker=tryletbuffer=Jbuffer.create()inletfmt=Jbuffer.formatterbufferinppfmtmarker;Format.pp_print_flushfmt();Jbuffer.contentsbufferwithNot_found->`Nullletrank({rank},_)=rankletby_rankab=Stdlib.compare(ranka)(rankb)letget_informationtgt=letinfos=ref[]inHashtbl.iter(fun_info->ifinfo.enable()thenmatchtgtwith|None->infos:=(info,`Null)::!infos|Somemarker->lettext=jtextinfo.prettymarkerinifnot(Jbuffer.is_emptytext)theninfos:=(info,text)::!infos)registry;List.sortby_rank!infosletsignal=Request.signal~package~name:"getInformationUpdate"~descr:(Md.plain"Updated AST information")letupdate()=Request.emitsignalletregister~id~label~title?(descr=title)?(enable=fun_->true)pretty=letrank=incrrankId;!rankIdinletinfo={id;rank;label;title;descr;enable;pretty}inifHashtbl.memregistryidthen(letmsg=Format.sprintf"Server.Kernel_ast.register_info: duplicate %S"idinraise(Invalid_argumentmsg));Hashtbl.addregistryidinfoendlet()=Request.register~package~kind:`GET~name:"getInformation"~descr:(Md.plain"Get available information about markers. \
When no marker is given, returns all kinds \
of information (with empty `descr` field).")~input:(moduleJoption(Marker))~output:(moduleJlist(Information.S))~signals:[Information.signal]Information.get_information(* -------------------------------------------------------------------------- *)(* --- Default Kernel Information --- *)(* -------------------------------------------------------------------------- *)let()=Information.register~id:"kernel.ast.location"~label:"Location"~title:"Source file location"beginfunfmtloc->letpos=fst@@Printer_tag.loc_of_localizablelocinifFilepath.Normalized.is_emptypos.pos_paththenraiseNot_found;Filepath.pp_posfmtposendlet()=Information.register~id:"kernel.ast.varinfo"~label:"Var"~title:"Variable Information"beginfunfmtloc->matchlocwith|PLval(_,_,(Varx,NoOffset))|PVDecl(_,_,x)->ifnotx.vreferencedthenFormat.pp_print_stringfmt"unused ";beginmatchx.vstoragewith|NoStorage->()|Extern->Format.pp_print_stringfmt"extern "|Static->Format.pp_print_stringfmt"static "|Register->Format.pp_print_stringfmt"register "end;ifx.vghostthenFormat.pp_print_stringfmt"ghost ";ifx.vaddrofthenFormat.pp_print_stringfmt"aliased ";ifx.vformalthenFormat.pp_print_stringfmt"formal"elseifx.vglobthenFormat.pp_print_stringfmt"global"elseifx.vtempthenFormat.pp_print_stringfmt"temporary"elseFormat.pp_print_stringfmt"local";|_->raiseNot_foundendlet()=Information.register~id:"kernel.ast.typeinfo"~label:"Type"~title:"Type of C/ASCL expression"beginfunfmtloc->letopenPrinterinmatchlocwith|PExp(_,_,e)->pp_typfmt(Cil.typeOfe)|PLval(_,_,lval)->pp_typfmt(Cil.typeOfLvallval)|PTermLval(_,_,_,lv)->pp_logic_typefmt(Cil.typeOfTermLvallv)|PVDecl(_,_,vi)->pp_typfmtvi.vtype|_->raiseNot_foundendlet()=Information.register~id:"kernel.ast.typedef"~label:"Typedef"~title:"Type Definition"beginfunfmtloc->matchlocwith|PType(TNamed_asty)|PGlobal(GType({ttype=ty},_))->beginlettdef=Cil.unrollTypetyinmatchPrinter_tag.definition_of_typetdefwith|Somemarker->lettag=Marker.indexmarkerinFormat.fprintffmt"@{<%s>%a@}"tagPrinter.pp_typtdef|None->PrinterTag.pp_typfmttdefend|_->raiseNot_foundendlet()=Information.register~id:"kernel.ast.typesizeof"~label:"Sizeof"~title:"Size of a C-type or C-variable"beginfunfmtloc->lettyp=matchlocwith|PTypetyp->typ|PVDecl(_,_,vi)->vi.vtype|PGlobal(GType(ti,_))->ti.ttype|PGlobal(GCompTagDecl(ci,_)|GCompTag(ci,_))->TComp(ci,[])|PGlobal(GEnumTagDecl(ei,_)|GEnumTag(ei,_))->TEnum(ei,[])|_->raiseNot_foundinletbits=tryCil.bitsSizeOftypwithCil.SizeOfError_->raiseNot_foundinletbytes=bits/8inletrbits=bitsmod8inifrbits>0thenifbytes>0thenFormat.fprintffmt"%d bytes + %d bits"bytesrbitselseFormat.fprintffmt"%d bits"rbitselseFormat.fprintffmt"%d bytes"bytesendlet()=Information.register~id:"kernel.ast.propertyStatus"~label:"Status"~title:"Property Consolidated Status"beginfunfmtloc->matchlocwith|PIPpropwhenProperty.has_statusprop->Property_status.Feedback.prettyfmt@@Property_status.Feedback.getprop|_->raiseNot_foundendlet()=Information.register~id:"kernel.ast.marker"~label:"Marker"~title:"Ivette marker (for debugging)"~enable:(fun_->Server_parameters.debug_atleast1)beginfunfmtloc->lettag=Marker.indexlocinFormat.fprintffmt"%S"tagendlet()=Server_parameters.Debug.add_hook_on_update(fun_->Information.update())(* -------------------------------------------------------------------------- *)(* --- Marker at a position --- *)(* -------------------------------------------------------------------------- *)letget_marker_at~file~line~col=iffile=""thenNoneelseletpos_path=Filepath.Normalized.of_stringfileinletpos=Filepath.{pos_path;pos_lnum=line;pos_cnum=col;pos_bol=0;}inPrinter_tag.loc_to_localizable~precise_col:trueposlet()=letdescr=Md.plain"Returns the marker and function at a source file position, if any. \
Input: file path, line and column. \
File can be empty, in case no marker is returned."inletsignature=Request.signature~output:(moduleJoption(Marker))()inletget_file=Request.paramsignature~name:"file"~descr:(Md.plain"File path")(moduleJstring)inletget_line=Request.paramsignature~name:"line"~descr:(Md.plain"Line (1-based)")(moduleJint)inletget_col=Request.paramsignature~name:"column"~descr:(Md.plain"Column (0-based)")(moduleJint)inRequest.register_sigsignature~package~descr~kind:`GET~name:"getMarkerAt"~signals:[ast_changed_signal](funrq()->get_marker_at~file:(get_filerq)~line:(get_linerq)~col:(get_colrq))(* -------------------------------------------------------------------------- *)(* --- Files --- *)(* -------------------------------------------------------------------------- *)letget_files()=letfiles=Kernel.Files.get()inList.map(funf->(f:Filepath.Normalized.t:>string))fileslet()=Request.register~package~descr:(Md.plain"Get the currently analyzed source file names")~kind:`GET~name:"getFiles"~input:(moduleJunit)~output:(moduleJlist(Jstring))get_filesletset_filesfiles=lets=String.concat","filesinKernel.Files.As_string.setslet()=Request.register~package~descr:(Md.plain"Set the source file names to analyze.")~kind:`SET~name:"setFiles"~input:(moduleJlist(Jstring))~output:(moduleJunit)set_files(* -------------------------------------------------------------------------- *)(* --- Build a marker from an ACSL term --- *)(* -------------------------------------------------------------------------- *)letenvironment()=letopenLogic_typinginLenv.empty()|>append_pre_label|>append_init_label|>append_here_labelletparse_exprenvkfstmtterm=letterm=Logic_parse_string.term~envkfterminletexp=Logic_to_c.term_to_expterminPrinter_tag.PExp(Somekf,Kstmtstmt,exp)letparse_lvalenvkfstmtterm=letterm=Logic_parse_string.term_lval~envkfterminletlval=Logic_to_c.term_lval_to_lvalterminPrinter_tag.PLval(Somekf,Kstmtstmt,lval)letbuild_markerparsemarkerterm=matchPrinter_tag.ki_of_localizablemarkerwith|Kglobal->Data.failure"No statement at selection point"|Kstmtstmt->letmoduleC=Logic_to_cinletmoduleParser=Logic_parse_stringinletkf()=Kernel_function.find_englobing_kfstmtintryparse(environment())(kf())stmttermwithNot_found|Parser.(Error_|Unbound_)|C.No_conversion->Data.failure"Invalid term"let()=letmoduleMd=Markdowninlets=Request.signature~output:(moduleMarker)()inletget_marker=Request.params~name:"stmt"~descr:(Md.plain"Marker position from where to localize the term")(moduleMarker)inletget_term=Request.params~name:"term"~descr:(Md.plain"ACSL term to parse")(moduleData.Jstring)inRequest.register_sig~packages~kind:`GET~name:"parseExpr"~descr:(Md.plain"Parse a C expression and returns the associated marker")(funrq()->build_markerparse_expr(get_markerrq)(get_termrq))let()=letmoduleMd=Markdowninlets=Request.signature~output:(moduleMarker)()inletget_marker=Request.params~name:"stmt"~descr:(Md.plain"Marker position from where to localize the term")(moduleMarker)inletget_term=Request.params~name:"term"~descr:(Md.plain"ACSL term to parse")(moduleData.Jstring)inRequest.register_sig~packages~kind:`GET~name:"parseLval"~descr:(Md.plain"Parse a C lvalue and returns the associated marker")(funrq()->build_markerparse_lval(get_markerrq)(get_termrq))(* -------------------------------------------------------------------------- *)