From 2cb5a77fba7ab2748fd73f4f97c756fcd3fc953f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr>
Date: Fri, 25 Jan 2019 16:35:41 +0100
Subject: [PATCH] [WP] create better properties for dynamics

---
 src/kernel_services/ast_data/property.ml      | 11 ++--
 .../ast_printing/description.ml               |  3 +
 src/plugins/wp/calculus.ml                    | 24 ++++----
 src/plugins/wp/dyncall.ml                     | 58 +++++++++++--------
 src/plugins/wp/dyncall.mli                    |  8 +--
 .../tests/wp_plugin/dynamic.i.0.report.json   |  9 ++-
 .../tests/wp_plugin/oracle/dynamic.res.oracle |  2 +-
 .../oracle_qualif/dynamic.res.oracle          |  2 +-
 src/plugins/wp/wpAnnot.ml                     | 10 +---
 9 files changed, 69 insertions(+), 58 deletions(-)

diff --git a/src/kernel_services/ast_data/property.ml b/src/kernel_services/ast_data/property.ml
index c1b6a0334b9..5a7c62cbe97 100644
--- a/src/kernel_services/ast_data/property.ml
+++ b/src/kernel_services/ast_data/property.ml
@@ -858,11 +858,15 @@ module Names = struct
       Format.asprintf  "%sextended%a" (extended_loc_prefix le) pp_names [name]
     | IPCodeAnnot (kf,_, ca) ->
         let name = match ca.annot_content with
-          | AAssert _ -> "assert" 
+          | AAssert _ -> "assert"
           | AInvariant (_,true,_) -> "loop_inv"
           | AInvariant _ -> "inv"
           | APragma _ -> "pragma"
-          | _ -> assert false
+          | AStmtSpec _ -> "contract"
+          | AAssigns _ -> "assigns"
+          | AVariant _ -> "variant"
+          | AAllocation _ -> "allocates"
+          | AExtended(_,_,(_,clause,_,_)) -> clause
         in Format.asprintf "%s%s%a" (kf_prefix kf) name pp_code_annot_names ca
     | IPComplete (kf, ki, a, lb) ->
         Format.asprintf  "%s%s%acomplete%a"
@@ -1125,7 +1129,7 @@ let ip_property_instance kf stmt ipred iprop =
 let ip_of_code_annot kf stmt ca =
   let ki = Kstmt stmt in
   match ca.annot_content with
-  | AAssert _ | AInvariant _ -> [ IPCodeAnnot(kf, stmt, ca) ]
+  | AAssert _ | AInvariant _ | AExtended _ -> [ IPCodeAnnot(kf, stmt, ca) ]
   | AStmtSpec (active,s) -> ip_of_spec kf ki active s
   | AVariant t -> [ IPDecrease (kf,ki,(Some ca),t) ]
   | AAllocation _ -> 
@@ -1137,7 +1141,6 @@ let ip_of_code_annot kf stmt ca =
   | APragma p when Logic_utils.is_property_pragma p ->
     [ IPCodeAnnot (kf,stmt,ca) ]
   | APragma _ -> []
-  | AExtended _ -> []
 
 let ip_of_code_annot_single kf stmt ca = match ip_of_code_annot kf stmt ca with
   | [] ->
diff --git a/src/kernel_services/ast_printing/description.ml b/src/kernel_services/ast_printing/description.ml
index a11da2374c6..00b2d7edd66 100644
--- a/src/kernel_services/ast_printing/description.ml
+++ b/src/kernel_services/ast_printing/description.ml
@@ -260,6 +260,9 @@ let rec pp_prop kfopt kiopt kloc fmt = function
       pp_for bs
       pp_named np
       (pp_kloc kloc) np.pred_loc
+  | IPCodeAnnot(_,stmt,{annot_content=AExtended(bs,_,(_,clause,_,_))}) ->
+    Format.fprintf fmt "%a%a%a"
+      pp_capitalize clause pp_for bs (pp_stmt kloc) stmt
   | IPCodeAnnot(_,stmt,_) ->
     Format.fprintf fmt "Annotation %a" (pp_stmt kloc) stmt
   | IPAllocation(kf,Kglobal,Id_contract (_,bhv),(frees,allocates)) ->
diff --git a/src/plugins/wp/calculus.ml b/src/plugins/wp/calculus.ml
index 39dce31afc8..d93b66804f4 100644
--- a/src/plugins/wp/calculus.ml
+++ b/src/plugins/wp/calculus.ml
@@ -438,7 +438,7 @@ module Cfg (W : Mcfg.S) = struct
     then W.call_goal_precond wenv stmt kf args ~pre:(pre_goals) obj
     else obj
 
-  let wp_calls ((caller_kf, cfg, strategy, _, wenv)) res v stmt
+  let wp_calls ((_, cfg, strategy, _, wenv)) res v stmt
       lval call args p_post p_exit
     =
     debug "[wp_calls] %a@." Cil2cfg.pp_call_type call;
@@ -451,18 +451,16 @@ module Cfg (W : Mcfg.S) = struct
         wp_call_kf wenv cenv stmt lval kf args precond ~p_post ~p_exit
     | Cil2cfg.Dynamic fct ->
         let bhv = WpStrategy.behavior_name_of_strategy strategy in
-        let calls = Dyncall.get ?bhv stmt in
-        if calls = [] then
-          wp_call_any wenv cenv ~p_post ~p_exit
-        else
-          let precond = R.is_pass1 res in
-          let call kf =
-            let wp = wp_call_kf wenv cenv stmt lval
-                kf args precond ~p_post ~p_exit in
-            kf , wp in
-          let prop = Dyncall.property ~kf:caller_kf ?bhv ~stmt ~calls in
-          let pid = WpPropId.mk_property prop in
-          W.call_dynamic wenv stmt pid fct (List.map call calls)
+        match Dyncall.get ?bhv stmt with
+        | None -> wp_call_any wenv cenv ~p_post ~p_exit
+        | Some (prop,calls) ->
+            let precond = R.is_pass1 res in
+            let do_call kf =
+              let wp = wp_call_kf wenv cenv stmt lval
+                  kf args precond ~p_post ~p_exit in
+              kf , wp in
+            let pid = WpPropId.mk_property prop in
+            W.call_dynamic wenv stmt pid fct (List.map do_call calls)
 
   let wp_stmt wenv s obj = match s.skind with
     | Return (r, _) -> W.return wenv s r obj
diff --git a/src/plugins/wp/dyncall.ml b/src/plugins/wp/dyncall.ml
index a13a06ebc5f..c7e14a68f6f 100644
--- a/src/plugins/wp/dyncall.ml
+++ b/src/plugins/wp/dyncall.ml
@@ -86,7 +86,7 @@ let pp_calls fmt calls =
 
 module PInfo = struct let module_name = "Dyncall.Point" end
 module Point = Datatype.Pair_with_collections(Datatype.String)(Stmt)(PInfo)
-module Calls = Datatype.List(Kernel_function)
+module Calls = Datatype.Pair(Property)(Datatype.List(Kernel_function))
 module CInfo =
 struct
   let name = "Dyncall.CallPoints"
@@ -95,10 +95,12 @@ struct
 end
 module CallPoints = State_builder.Hashtbl(Point.Hashtbl)(Calls)(CInfo)
 
-let property ~kf ?bhv ~stmt ~calls =
-  let fact = match bhv with
-    | None -> Format.asprintf "@[<hov 2>calls%a@]" pp_calls calls
-    | Some b -> Format.asprintf "@[<hov 2>calls%a for %s@]" pp_calls calls b
+let property ~kf ~bhv ~stmt calls =
+  let fact =
+    if bhv = Cil.default_behavior_name then
+      Format.asprintf "@[<hov 2>calls%a@]" pp_calls calls
+    else
+      Format.asprintf "@[<hov 2>calls%a for %s@]" pp_calls calls bhv
   in
   Property.(ip_other fact (OLStmt (kf,stmt)))
 
@@ -116,6 +118,9 @@ class dyncall =
 
     method count = count
 
+    method private kf =
+      match self#current_kf with None -> assert false | Some kf -> kf
+
     method private stmt =
       match self#current_stmt with None -> assert false | Some stmt -> stmt
 
@@ -128,32 +133,39 @@ class dyncall =
       | Cil_types.AExtended (bhvs,_,(_, "calls", _,Ext_terms calls)) ->
           if calls <> [] && (scope <> [] || not (Stack.is_empty block_calls))
           then begin
+            let kf = self#kf in
             let bhvs =
               match bhvs with
               | [] -> [ Cil.default_behavior_name ]
               | bhvs -> bhvs
             in
+            let debug_calls bhv stmt kfs =
+              if Wp_parameters.has_dkey dkey_calls then
+                let source = snd (Stmt.loc stmt) in
+                if Cil.default_behavior_name = bhv then
+                  Wp_parameters.result ~source
+                    "@[<hov 2>Calls%a@]" pp_calls kfs
+                else
+                  Wp_parameters.result ~source
+                    "@[<hov 2>Calls (for %s)%a@]" bhv pp_calls kfs
+            in
+            let pool = ref [] in (* collect emitted properties *)
             let add_calls_info stmt =
               count <- succ count ;
               List.iter
                 (fun bhv ->
                    let kfs = List.map get_call calls in
-                   begin
-                     if Wp_parameters.has_dkey dkey_calls then
-                       let source = snd (Stmt.loc stmt) in
-                       if Cil.default_behavior_name = bhv then
-                         Wp_parameters.result ~source
-                           "@[<hov 2>Calls%a@]" pp_calls kfs
-                       else
-                         Wp_parameters.result ~source
-                           "@[<hov 2>Calls (for %s)%a@]" bhv pp_calls kfs
-                   end;
-                   CallPoints.add (bhv,stmt) kfs)
+                   debug_calls bhv stmt kfs ;
+                   let prop = property ~kf ~bhv ~stmt kfs in
+                   pool := prop :: !pool ;
+                   CallPoints.add (bhv,stmt) (prop,kfs))
                 bhvs
             in
-            if scope <> [] then List.iter add_calls_info scope
-            else
-              List.iter add_calls_info (Stack.top block_calls)
+            let callpoints =
+              if scope <> [] then scope else Stack.top block_calls in
+            List.iter add_calls_info callpoints ;
+            let annot = Property.ip_of_code_annot_single kf self#stmt ca in
+            ignore (annot,!pool) ;
           end;
           SkipChildren
       | _ -> SkipChildren
@@ -216,15 +228,15 @@ let compute =
 let get ?bhv stmt =
   compute () ;
   let get bhv =
-    try CallPoints.find (bhv,stmt)
-    with Not_found -> []
+    try Some (CallPoints.find (bhv,stmt))
+    with Not_found -> None
   in
   match bhv with
   | None -> get Cil.default_behavior_name
   | Some bhv ->
       (match get bhv with
-       | [] -> get Cil.default_behavior_name
-       | l -> l)
+       | None -> get Cil.default_behavior_name
+       | result -> result)
 
 (* -------------------------------------------------------------------------- *)
 (* --- Registry                                                           --- *)
diff --git a/src/plugins/wp/dyncall.mli b/src/plugins/wp/dyncall.mli
index 823c5c331be..85678b9f73c 100644
--- a/src/plugins/wp/dyncall.mli
+++ b/src/plugins/wp/dyncall.mli
@@ -24,12 +24,8 @@ open Cil_types
 
 val pp_calls : Format.formatter -> kernel_function list -> unit
 
-val property : kf:kernel_function -> ?bhv:string -> stmt:stmt ->
-  calls:kernel_function list -> Property.t
-(** Returns an property identifier for the precondition. *)
-
-val get : ?bhv:string -> stmt -> kernel_function list
-(** Returns empty list if there is no specified dynamic call. *)
+val get : ?bhv:string -> stmt -> (Property.t * kernel_function list) option
+(** Returns [None] if there is no specified dynamic call. *)
 
 val compute : unit -> unit
 (** Forces computation of dynamic calls.
diff --git a/src/plugins/wp/tests/wp_plugin/dynamic.i.0.report.json b/src/plugins/wp/tests/wp_plugin/dynamic.i.0.report.json
index 6f08ea23f4e..a092c5cd51e 100644
--- a/src/plugins/wp/tests/wp_plugin/dynamic.i.0.report.json
+++ b/src/plugins/wp/tests/wp_plugin/dynamic.i.0.report.json
@@ -57,9 +57,12 @@
                                                       "wp:main": { "total": 5,
                                                                    "valid": 5,
                                                                    "rank": 5 } } },
-                    "behavior": { "behavior_stmt_calls_h1_h2_for_bhv1": 
-                                    { "qed": { "total": 1, "valid": 1 },
-                                      "wp:main": { "total": 1, "valid": 1 } },
+                    "behavior": { "behavior_stmt_calls_h1_h2": { "qed": 
+                                                                   { "total": 1,
+                                                                    "valid": 1 },
+                                                                 "wp:main": 
+                                                                   { "total": 1,
+                                                                    "valid": 1 } },
                                   "behavior_bhv1_assign": { "qed": { "total": 6,
                                                                     "valid": 6 },
                                                             "wp:main": 
diff --git a/src/plugins/wp/tests/wp_plugin/oracle/dynamic.res.oracle b/src/plugins/wp/tests/wp_plugin/oracle/dynamic.res.oracle
index a9538e54c89..80192d5d7d4 100644
--- a/src/plugins/wp/tests/wp_plugin/oracle/dynamic.res.oracle
+++ b/src/plugins/wp/tests/wp_plugin/oracle/dynamic.res.oracle
@@ -17,7 +17,7 @@
   Function behavior with behavior bhv1
 ------------------------------------------------------------
 
-Goal Calls h1 h2 for bhv1 in 'behavior' at instruction (file tests/wp_plugin/dynamic.i, line 65):
+Goal Calls h1 h2 in 'behavior' at instruction (file tests/wp_plugin/dynamic.i, line 65):
 Prove: true.
 
 ------------------------------------------------------------
diff --git a/src/plugins/wp/tests/wp_plugin/oracle_qualif/dynamic.res.oracle b/src/plugins/wp/tests/wp_plugin/oracle_qualif/dynamic.res.oracle
index 219867a51e0..38972927867 100644
--- a/src/plugins/wp/tests/wp_plugin/oracle_qualif/dynamic.res.oracle
+++ b/src/plugins/wp/tests/wp_plugin/oracle_qualif/dynamic.res.oracle
@@ -5,7 +5,7 @@
 [wp] tests/wp_plugin/dynamic.i:78: Warning: Missing 'calls' for default behavior
 [wp] Warning: Missing RTE guards
 [wp] 51 goals scheduled
-[wp] [Qed] Goal typed_behavior_stmt_calls_h1_h2_for_bhv1 : Valid
+[wp] [Qed] Goal typed_behavior_stmt_calls_h1_h2 : Valid
 [wp] [Qed] Goal typed_behavior_bhv1_post_part1 : Valid
 [wp] [Qed] Goal typed_behavior_bhv1_post_part2 : Valid
 [wp] [Qed] Goal typed_behavior_bhv1_assign_exit_part1 : Valid
diff --git a/src/plugins/wp/wpAnnot.ml b/src/plugins/wp/wpAnnot.ml
index 16a29702a4b..3b92a70d828 100644
--- a/src/plugins/wp/wpAnnot.ml
+++ b/src/plugins/wp/wpAnnot.ml
@@ -770,9 +770,8 @@ let get_call_annots config v s fct =
 
   | Cil2cfg.Dynamic _ ->
       let bhv = asked_bhv config.cur_bhv in
-      let calls = Dyncall.get ?bhv s in
-      if calls=[] then
-        begin
+      match Dyncall.get ?bhv s with
+      | None | Some(_,[]) ->
           Wp_parameters.warning ~once:true ~source:(fst (Stmt.loc s))
             "Missing 'calls' for %s"
             (match bhv with
@@ -780,13 +779,10 @@ let get_call_annots config v s fct =
              | Some b -> b) ;
           let annots = WpStrategy.add_call_assigns_any WpStrategy.empty_acc s in
           WpStrategy.empty_acc, (annots , annots)
-        end
-      else
-        begin
+      | Some(_,calls) ->
           List.fold_left
             (fun acc kf -> add_call_annots config s kf l_post acc)
             empty calls
-        end
 
 (*----------------------------------------------------------------------------*)
 let add_variant_annot config s ca var_exp loop_entry loop_back =
-- 
GitLab