123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356(**************************************************************************)(* *)(* 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). *)(* *)(**************************************************************************)moduleMd=MarkdownmodulePkg=PackageopenDataopenKernel_astletpackage=Pkg.package~title:"Property Services"~name:"properties"()(* -------------------------------------------------------------------------- *)(* --- Property Kind --- *)(* -------------------------------------------------------------------------- *)modulePropKind=structletkinds=Enum.dictionary()lett_kindnamedescr=Enum.tag~name~label:(Md.plainname)~descr:(Md.plaindescr)kindslett_clausename=t_kindname(Printf.sprintf"Clause `@%s`"name)lett_loopname=t_kind("loop_"^name)(Printf.sprintf"Clause `@loop %s`"name)lett_behavior=t_kind"behavior""Contract behavior"lett_complete=t_kind"complete""Complete behaviors clause"lett_disjoint=t_kind"disjoint""Disjoint behaviors clause"lett_assumes=t_clause"assumes"lett_requires=t_kind"requires""Function precondition"lett_instance=t_kind"instance""Instance of a precondition at a call site"lett_breaks=t_clause"breaks"lett_continues=t_clause"continues"lett_returns=t_clause"returns"lett_exits=t_clause"exits"lett_ensures=t_kind"ensures""Function postcondition"lett_terminates=t_kind"terminates""Function termination clause"lett_allocates=t_kind"allocates""Function allocation"lett_decreases=t_clause"decreases"lett_assigns=t_kind"assigns""Function assigns"lett_froms=t_kind"froms""Functional dependencies in function assigns"lett_assert=t_kind"assert""Assertion"lett_check=t_kind"check""Check"lett_admit=t_kind"admit""Hypothesis"lett_loop_invariant=t_loop"invariant"lett_loop_assigns=t_loop"assigns"lett_loop_variant=t_loop"variant"lett_loop_allocates=t_loop"allocates"lett_loop_pragma=t_loop"pragma"lett_reachable=t_kind"reachable""Reachable statement"lett_code_contract=t_kind"code_contract""Statement contract"lett_code_invariant=t_kind"code_invariant""Generalized loop invariant"lett_type_invariant=t_kind"type_invariant""Type invariant"lett_global_invariant=t_kind"global_invariant""Global invariant"lett_axiomatic=t_kind"axiomatic""Axiomatic definitions"lett_axiom=t_kind"axiom""Logical axiom"lett_lemma=t_kind"lemma""Logical lemma"lett_check_lemma=t_kind"check_lemma""Logical check lemma"lett_ext=t_kind"extension""ACSL extension"letp_ext=Enum.prefixkinds~name:"ext"~var:"<clause>"~descr:(Md.plain"ACSL extension `<clause>`")letp_loop_ext=Enum.prefixkinds~name:"loop_ext"~var:"<clause>"~descr:(Md.plain"ACSL loop extension `loop <clause>`")letp_other=Enum.prefixkinds~name:"prop"~var:"<prop>"~descr:(Md.plain"Plugin Specific properties")openPropertyletlookup=function|IPPredicate{ip_kind}->beginmatchip_kindwith|PKRequires_->t_requires|PKAssumes_->t_assumes|PKEnsures(_,Normal)->t_ensures|PKEnsures(_,Exits)->t_exits|PKEnsures(_,Breaks)->t_breaks|PKEnsures(_,Continues)->t_continues|PKEnsures(_,Returns)->t_returns|PKTerminates->t_terminatesend|IPExtended{ie_ext={ext_name=_}}->t_ext|IPAxiomatic_->t_axiomatic|IPLemma{il_pred={tp_kind=Admit}}->t_axiom|IPLemma{il_pred={tp_kind=Assert}}->t_lemma|IPLemma{il_pred={tp_kind=Check}}->t_check_lemma|IPBehavior_->t_behavior|IPComplete_->t_complete|IPDisjoint_->t_disjoint|IPCodeAnnot{ica_ca={annot_content}}->beginmatchannot_contentwith|AAssert(_,{tp_kind=Assert})->t_assert|AAssert(_,{tp_kind=Check})->t_check|AAssert(_,{tp_kind=Admit})->t_admit|AStmtSpec_->t_code_contract|AInvariant(_,false,_)->t_code_invariant|AInvariant(_,true,_)->t_loop_invariant|AVariant_->t_loop_variant|AAssigns_->t_loop_assigns|AAllocation_->t_loop_allocates|APragma_->t_loop_pragma|AExtended(_,_,{ext_name=_})->t_extend|IPAllocation_->t_allocates|IPAssigns_->t_assigns|IPFrom_->t_froms|IPDecrease_->t_decreases|IPReachable_->t_reachable|IPPropertyInstance_->t_instance|IPTypeInvariant_->t_type_invariant|IPGlobalInvariant_->t_global_invariant|IPOther{io_name}->Enum.instancep_otherio_namelet()=Enum.set_lookupkindslookupletdata=Request.dictionary~package~name:"propKind"~descr:(Md.plain"Property Kinds")kindsinclude(valdata:Swithtypet=Property.t)endletregister_propkind~name~kind?label~descr()=letopenPropKindinletprefix=matchkindwith|`Clause->p_ext|`Loop->p_loop_ext|`Other->p_otherinignore@@Enum.extendsprefix~name?label~descr(* -------------------------------------------------------------------------- *)(* --- Property Status --- *)(* -------------------------------------------------------------------------- *)modulePropStatus=structletstatus=Enum.dictionary()lett_statusvaluename?labeldescr=Enum.tag~name?label:(Option.mapMd.plainlabel)~descr:(Md.plaindescr)~valuestatusopenProperty_status.Feedbacklett_unknown=t_statusUnknown"unknown""Unknown status"lett_never_tried=t_statusNever_tried"never_tried"~label:"Never tried""Unknown status (never tried)"lett_inconsistent=t_statusInconsistent"inconsistent""Inconsistent status"lett_valid=t_statusValid"valid""Valid property"lett_valid_under_hyp=t_statusValid_under_hyp"valid_under_hyp"~label:"Valid (?)""Valid (under hypotheses)"lett_considered_valid=t_statusConsidered_valid"considered_valid"~label:"Valid (!)""Valid (external assumption)"lett_invalid=t_statusInvalid"invalid""Invalid property (counter example found)"lett_invalid_under_hyp=t_statusInvalid_under_hyp"invalid_under_hyp"~label:"Invalid (?)""Invalid property (under hypotheses)"lett_invalid_but_dead=t_statusInvalid_but_dead"invalid_but_dead"~label:"Invalid (✝)""Dead property (but invalid)"lett_valid_but_dead=t_statusValid_but_dead"valid_but_dead"~label:"Valid (✝)""Dead property (but valid)"lett_unknown_but_dead=t_statusUnknown_but_dead"unknown_but_dead"~label:"Unknown (✝)""Dead property (but unknown)"let()=Enum.set_lookupstatusbeginfunction|Valid->t_valid|Invalid->t_invalid|Unknown->t_unknown|Never_tried->t_never_tried|Valid_under_hyp->t_valid_under_hyp|Valid_but_dead->t_valid_but_dead|Considered_valid->t_considered_valid|Invalid_under_hyp->t_invalid_under_hyp|Invalid_but_dead->t_invalid_but_dead|Unknown_but_dead->t_unknown_but_dead|Inconsistent->t_inconsistentendletdata=Request.dictionary~package~name:"propStatus"~descr:(Md.plain"Property Status (consolidated)")statusinclude(valdata:Swithtypet=Property_status.Feedback.t)end(* -------------------------------------------------------------------------- *)(* --- Alarm kind --- *)(* -------------------------------------------------------------------------- *)[@@@warning"-60"]moduleAlarmKind=structletalarms=Enum.dictionary()letregisteralarm=letname=Alarms.get_short_namealarminletlabel=Md.plainnameinletdescr=Md.plain(Alarms.get_descriptionalarm)inEnum.addalarms~name~label~descrlet()=List.iterregisterAlarms.reprslet()=Enum.set_lookupalarmsbeginfunctionalarm->letname=Alarms.get_short_namealarmintryEnum.find_tagalarmsnamewithNot_found->failure"Unknown alarm kind: %s"nameendletdata=Request.dictionary~package~name:"alarms"~descr:(Md.plain"Alarm Kinds")alarmsinclude(valdata:Swithtypet=Alarms.t)end[@@@warning"+60"](* -------------------------------------------------------------------------- *)(* --- Property Model --- *)(* -------------------------------------------------------------------------- *)letfind_alarm=function|Property.IPCodeAnnotannot->Alarms.findannot.ica_ca|_->Noneletmodel=States.model()let()=States.columnmodel~name:"descr"~descr:(Md.plain"Full description")~data:(moduleJstring)~get:(funip->Format.asprintf"%a"Property.prettyip)let()=States.columnmodel~name:"kind"~descr:(Md.plain"Kind")~data:(modulePropKind)~get:(funip->ip)let()=States.columnmodel~name:"names"~descr:(Md.plain"Names")~data:(moduleJlist(Jstring))~get:Property.get_nameslet()=States.columnmodel~name:"status"~descr:(Md.plain"Status")~data:(modulePropStatus)~get:(Property_status.Feedback.get)let()=States.columnmodel~name:"fct"~descr:(Md.plain"Function")~data:(moduleJoption(Function))~get:Property.get_kflet()=States.columnmodel~name:"kinstr"~descr:(Md.plain"Instruction")~data:(moduleKinstr)~get:Property.get_kinstrlet()=States.columnmodel~name:"source"~descr:(Md.plain"Position")~data:(moduleKernel_ast.Position)~get:(funip->Property.locationip|>fst)let()=States.columnmodel~name:"alarm"~descr:(Md.plain"Alarm name (if the property is an alarm)")~data:(moduleJoption(Jstring))~get:(funip->Option.mapAlarms.get_short_name(find_alarmip))let()=States.columnmodel~name:"alarm_descr"~descr:(Md.plain"Alarm description (if the property is an alarm)")~data:(moduleJoption(Jstring))~get:(funip->Option.mapAlarms.get_description(find_alarmip))let()=States.columnmodel~name:"predicate"~descr:(Md.plain"Predicate")~data:(moduleJoption(Jstring))~get:(funip->Option.mapsnd(Description.property_kind_and_nodeip))letis_relevantip=matchProperty.get_kfipwith|None->true|Somekf->not(Ast_info.is_frama_c_builtin(Kernel_function.get_namekf)||Cil_builtins.is_unused_builtin(Kernel_function.get_vikf))letiterf=Property_status.iter(funip->ifis_relevantipthenfip)(* Must reload the entire table when status changed: property dependencies
are not taken into account when status are updated. *)letadd_reload_hook(f:unit->unit):unit=Property_status.register_status_update_hook(fun_emitter_ip_status->f())letadd_update_hook(f:Property.t->unit):unit=Property_status.register_property_add_hook(funip->ifis_relevantipthenfip)letadd_remove_hook(f:Property.t->unit):unit=Property_status.register_property_remove_hook(funip->ifis_relevantipthenfip)letarray=States.register_array~package~name:"status"~descr:(Md.plain"Status of Registered Properties")~key:(funip->Kernel_ast.Marker.tag(PIPip))~keyType:Kernel_ast.Marker.jtype~iter~add_reload_hook~add_remove_hook~add_update_hookmodelletreload()=States.reloadarray(* -------------------------------------------------------------------------- *)