From 9c909beefb2b2053643ed66c5fcd867f8b7dd401 Mon Sep 17 00:00:00 2001
From: Virgile Prevosto <virgile.prevosto@m4x.org>
Date: Fri, 19 Jun 2020 15:29:38 +0200
Subject: [PATCH] [logic] don't lose annot_id when merging loop assigns or loop
 allocates

---
 src/kernel_services/ast_data/annotations.ml   | 162 ++++++------------
 .../oracle/loop_assigns_generated.res.oracle  |   4 +-
 2 files changed, 52 insertions(+), 114 deletions(-)

diff --git a/src/kernel_services/ast_data/annotations.ml b/src/kernel_services/ast_data/annotations.ml
index a433735fd86..67f6b5de159 100644
--- a/src/kernel_services/ast_data/annotations.ml
+++ b/src/kernel_services/ast_data/annotations.ml
@@ -319,56 +319,49 @@ let merge_stmt_contracts_emitters contracts =
        :: acc)
     merged_contracts []
 
-let merge_loop_assigns_emitters annots =
-  let merge_assigns bhvs (a,e) acc =
+let merge_annots_emitters extract merge make annots =
+  let merge_same_bhvs bhvs (ca,a,e) acc =
     let elt =
       match Behavior_set_map.find_opt bhvs acc with
-      | Some (a',e') ->
-        let a' = merge_assigns ~keep_empty:false a a' in
+      | Some (ca', a',e') ->
+        let a' = merge a a' in
         let e' = if Emitter.equal e e' then e else Emitter.kernel in
-        a', e'
-      | None -> a,e
+        let ca' =
+          if Cil_datatype.Code_annotation.compare ca' ca < 0 then ca' else ca
+        in
+        let annot_content = make (Datatype.String.Set.elements bhvs) a' in
+        let ca' = { ca' with annot_content } in
+        ca', a', e'
+      | None -> ca,a,e
     in
     Behavior_set_map.add bhvs elt acc
   in
   let treat_code_annot acc (ca,e) =
-    match ca.annot_content with
-    | AAssigns(bhvs,a) ->
-      merge_assigns (Datatype.String.Set.of_list bhvs) (a,e) acc
-    | _ -> acc
+    match extract ca with
+    | Some(bhvs,a) ->
+      merge_same_bhvs (Datatype.String.Set.of_list bhvs) (ca,a,e) acc
+    | None -> acc
   in
   let bhvs = List.fold_left treat_code_annot Behavior_set_map.empty annots in
-  Behavior_set_map.fold
-    (fun bhvs (a,e) acc ->
-       (Logic_const.new_code_annotation
-         (AAssigns (Datatype.String.Set.elements bhvs, a)),e)
-       :: acc)
-    bhvs []
+  Behavior_set_map.fold (fun _ (ca,_,e) acc -> (ca,e) :: acc) bhvs []
 
-let merge_loop_allocation annots =
-  let merge_allocates bhvs (a,e) acc =
-    let elt =
-      match Behavior_set_map.find_opt bhvs acc with
-      | Some (a', e') ->
-        let a' = merge_allocation ~keep_empty:false a a' in
-        let e' = if Emitter.equal e e' then e else Emitter.kernel in
-        a', e'
-      | None -> a,e
-    in Behavior_set_map.add bhvs elt acc
-  in
-  let treat_code_annot acc (ca, e) =
+let merge_loop_assigns_emitter =
+  let extract ca =
     match ca.annot_content with
-    | AAllocation(bhvs,a) ->
-      merge_allocates (Datatype.String.Set.of_list bhvs) (a,e) acc
-    | _ -> acc
+    | AAssigns(bhvs,a) -> Some(bhvs,a)
+    | _ -> None
   in
-  let bhvs = List.fold_left treat_code_annot Behavior_set_map.empty annots in
-  Behavior_set_map.fold
-    (fun bhvs (a,e) acc ->
-       (Logic_const.new_code_annotation
-          (AAllocation (Datatype.String.Set.elements bhvs, a)),e)
-       ::acc)
-    bhvs []
+  let merge a a' = merge_assigns ~keep_empty:false a a' in
+  let make bhvs a = AAssigns(bhvs,a) in
+  merge_annots_emitters extract merge make
+
+let merge_loop_allocation_emitter =
+  let extract ca =
+    match ca.annot_content with AAllocation(bhvs,a) -> Some (bhvs,a) | _ -> None
+  in
+  let merge a a' = merge_allocation ~keep_empty:false a a' in
+  let make bhvs a = AAllocation(bhvs,a) in
+  merge_annots_emitters extract merge make
 
 let partition_code_annot_emitter l =
   let add_one_ca (contracts, assigns, alloc, others) (ca,_ as v) =
@@ -410,8 +403,8 @@ let code_annot_emitter ?filter stmt =
     in
     let contracts,assigns,allocation,others = partition_code_annot_emitter l in
     merge_stmt_contracts_emitters contracts @
-    merge_loop_assigns_emitters assigns @
-    merge_loop_allocation allocation @
+    merge_loop_assigns_emitter assigns @
+    merge_loop_allocation_emitter allocation @
     others
   with Not_found ->
     []
@@ -1177,78 +1170,23 @@ let add_code_annot emitter ?kf stmt ca =
         | AAssigns (bhvs', _) -> is_same_behavior_set bhvs bhvs'
         | _ -> false
       in
-      let assigns' = code_annot ~filter stmt in
-      (match assigns' with
-       | [] -> a, Property.ip_of_code_annot kf stmt a
-       | l ->
-         let merge_assigns_ca acc ca =
-           match ca.annot_content with
-           | AAssigns(_,assigns') ->
-             merge_assigns ~keep_empty:false assigns' acc
-           | _ -> acc
-         in
-         let assigns' = List.fold_left merge_assigns_ca WritesAny l in
-         let merged_ca = { a with annot_content = AAssigns(bhvs,assigns') }
-         in
-         let ip =
-           Property.(
-             ip_of_assigns
-               kf (Kstmt stmt) (Id_loop merged_ca) assigns')
-         in
-         Extlib.may Property_status.remove ip;
-         (match assigns' with
-          | WritesAny -> ()
-          | Writes l ->
-            List.iter
-              (fun from ->
-                 let ip =
-                   Property.(
-                     ip_of_from kf (Kstmt stmt)
-                       (Id_loop merged_ca) from)
-                 in
-                 Extlib.may Property_status.remove ip)
-              l);
-         let new_assigns =
-           merge_assigns ~keep_empty:false assigns' assigns
-         in
-         let new_ca = { a with annot_content = AAssigns(bhvs,new_assigns) }
-         in
-         let ips =
-           Extlib.list_of_opt
-             Property.(
-               ip_of_assigns
-                 kf (Kstmt stmt) (Id_loop new_ca) new_assigns)
-         in
-         let ips =
-           match new_assigns with
-           | WritesAny -> ips
-           | Writes l ->
-             List.fold_left
-               (fun acc f ->
-                  Extlib.opt_fold
-                    (fun x y -> x::y)
-                    Property.(
-                      ip_of_from kf (Kstmt stmt)
-                        (Id_loop new_ca) f)
-                    acc)
-               ips l
-         in
-         let ca' = code_annot ~filter stmt in
-         let new_a =
-           match ca' with
-           | [] -> a
-           | [ { annot_content = AAssigns(_, assigns') } as ca ] ->
-             remove_code_annot_internal emitter ~kf stmt ca;
-             let merged =
-               merge_assigns ~keep_empty:false assigns' assigns
-             in
-             { a with annot_content = AAssigns (bhvs, merged) }
-           | _ ->
-             Kernel.fatal
-               "More than one loop assigns clause for a statement. \
-                Annotations internal state broken."
-         in
-         new_a, ips)
+      let ca' = code_annot ~filter stmt in
+      let new_a =
+        match ca' with
+        | [] -> a
+        | [ { annot_content = AAssigns(_, assigns') } as ca ] ->
+          remove_code_annot_internal emitter ~kf stmt ca;
+          let merged =
+            merge_assigns ~keep_empty:false assigns' assigns
+          in
+          { a with annot_content = AAssigns (bhvs, merged) }
+        | _ ->
+          Kernel.fatal
+            "More than one loop assigns clause for a statement. \
+             Annotations internal state broken."
+      in
+      let ips = Property.ip_of_code_annot kf stmt new_a in
+      new_a, ips
     | AAllocation (bhvs, alloc) ->
       let filter ca =
         match ca.annot_content with
diff --git a/tests/spec/oracle/loop_assigns_generated.res.oracle b/tests/spec/oracle/loop_assigns_generated.res.oracle
index a30771642fd..b2a2c0e9084 100644
--- a/tests/spec/oracle/loop_assigns_generated.res.oracle
+++ b/tests/spec/oracle/loop_assigns_generated.res.oracle
@@ -7,8 +7,8 @@ void f(void)
   int k;
   int j;
   int i = 0;
-  /*@ loop allocates (added_by_emitter1: p), (added_by_emitter2: q);
-      loop assigns i, (added_by_emitter1: j), (added_by_emitter2: k);
+  /*@ loop assigns i, (added_by_emitter1: j), (added_by_emitter2: k);
+      loop allocates (added_by_emitter1: p), (added_by_emitter2: q);
   */
   while (i < 10) i ++;
   return;
-- 
GitLab