From e4ba69e0bb2f450ff372b6c468cedb322dca9aef Mon Sep 17 00:00:00 2001
From: Valentin Perrelle <valentin.perrelle@cea.fr>
Date: Wed, 3 Nov 2021 19:19:23 +0100
Subject: [PATCH] [Nonterm] Use the new Eva API

---
 src/plugins/nonterm/nonterm_run.ml | 105 +++++++++++------------------
 1 file changed, 39 insertions(+), 66 deletions(-)

diff --git a/src/plugins/nonterm/nonterm_run.ml b/src/plugins/nonterm/nonterm_run.ml
index 23d5aa76359..0784bc25e03 100644
--- a/src/plugins/nonterm/nonterm_run.ml
+++ b/src/plugins/nonterm/nonterm_run.ml
@@ -181,7 +181,7 @@ class unreachable_stmt_visitor kf to_ignore = object
 
   method! vstmt stmt =
     if Stmt.Hptset.mem stmt syntactically_reachable &&
-       Db.Value.is_reachable_stmt stmt = false &&
+       not (Eva.Results.is_reachable stmt) &&
        not (Stmt.Hptset.mem stmt !semantically_considered)
     then begin
       (* add node and its reachable successors to the considered statements *)
@@ -197,11 +197,10 @@ end
    1. SyntacticallyUnreachable is disabled (otherwise it already checks them);
    2. No warnings were emitted for the function (otherwise it may be redundant). *)
 let check_unreachable_returns kf =
-  let st = Db.Value.get_initial_state kf in
-  if Db.Value.is_reachable st then begin
+  if Eva.Results.is_called kf then begin
     try
       let ret_stmt = Kernel_function.find_return kf in
-      if not (Db.Value.is_reachable_stmt ret_stmt) then
+      if not (Eva.Results.is_reachable ret_stmt) then
         warn_unreachable_statement ret_stmt
     with
     | Kernel_function.No_Statement -> (* should never happen *)
@@ -221,25 +220,24 @@ let check_unreachable_statements kf ~to_ignore ~dead_code ~warned_kfs =
                 considered as always terminating"
       Kernel_function.pretty kf
   else
-    let st = Db.Value.get_initial_state kf in
-    if Db.Value.is_reachable st then begin
-      try
-        let vis = new unreachable_stmt_visitor kf to_ignore in
+  if Eva.Results.is_called kf then begin
+    try
+      let vis = new unreachable_stmt_visitor kf to_ignore in
+      ignore (Visitor.visitFramacKf (vis :> Visitor.frama_c_visitor) kf);
+      if dead_code then begin
+        (* compute syntactically unreachable statements *)
+        let vis = new dead_cc_collector kf in
         ignore (Visitor.visitFramacKf (vis :> Visitor.frama_c_visitor) kf);
-        if dead_code then begin
-          (* compute syntactically unreachable statements *)
-          let vis = new dead_cc_collector kf in
-          ignore (Visitor.visitFramacKf (vis :> Visitor.frama_c_visitor) kf);
-          let cc_heads = List.map List.hd vis#get in
-          Stmt.Hptset.iter (fun h -> warn_dead_code h) (Stmt.Hptset.of_list cc_heads)
-        end
-        else if not (Kernel_function.Set.mem kf warned_kfs) then
-          check_unreachable_returns kf
-      with
-      | Kernel_function.No_Statement -> (* should never happen *)
-        Self.error "function %a has no return statement, skipping"
-          Kernel_function.pretty kf;
-    end
+        let cc_heads = List.map List.hd vis#get in
+        Stmt.Hptset.iter (fun h -> warn_dead_code h) (Stmt.Hptset.of_list cc_heads)
+      end
+      else if not (Kernel_function.Set.mem kf warned_kfs) then
+        check_unreachable_returns kf
+    with
+    | Kernel_function.No_Statement -> (* should never happen *)
+      Self.error "function %a has no return statement, skipping"
+        Kernel_function.pretty kf;
+  end
 
 (* To avoid redundant warnings, calls to possibly non-terminating functions
    are ignored if:
@@ -281,14 +279,6 @@ class stmt_collector = object
   method get_instr_stmts = List.rev !instr_stmts
 end
 
-let get_callstack_state ~after stmt cs =
-  match Db.Value.get_stmt_state_callstack ~after stmt with
-  | None -> None (* unreachable stmt *)
-  | Some table ->
-    try
-      Some (Value_types.Callstack.Hashtbl.find table cs)
-    with Not_found -> None
-
 (* collects the list of non-terminating instructions *)
 let collect_nonterminating_statements fd nonterm_stacks =
   let vis = new stmt_collector in
@@ -309,40 +299,23 @@ let collect_nonterminating_statements fd nonterm_stacks =
       | _ ->
         let source = fst (Stmt.loc stmt) in
         Self.debug ~source "processing stmt:@ %a" Printer.pp_stmt stmt;
-        match Db.Value.get_stmt_state_callstack ~after:false stmt with
-        | None -> () (* unreachable stmt *)
-        | Some before_table ->
-          Value_types.Callstack.Hashtbl.iter
-            (fun cs before_state ->
-               try
-                 match Db.Value.get_stmt_state_callstack ~after:true stmt with
-                 | None -> (* no after table => non-terminating statement *)
-                   add_stack stmt cs
-                 | Some after_table ->
-                   let after_state =
-                     Value_types.Callstack.Hashtbl.find after_table cs
-                   in
-                   if Cvalue.Model.is_reachable before_state then
-                     if not (Cvalue.Model.is_reachable after_state) then add_stack stmt cs
-                     else if match stmt.skind with Loop _ -> true | _ -> false then begin
-                       (* special treatment for loops: even if their after state
-                          is reachable, we must check that at least one outgoing
-                          edge is reachable *)
-                       let out_edges = Stmts_graph.get_all_stmt_out_edges stmt in
-                       let all_out_edges_unreachable =
-                         List.for_all (fun (_, out_stmt) ->
-                             match get_callstack_state ~after:false out_stmt cs with
-                             | None -> true
-                             | Some state -> not (Cvalue.Model.is_reachable state)
-                           ) out_edges
-                       in
-                       if all_out_edges_unreachable then add_stack stmt cs
-                     end
-               with
-               | Not_found ->
-                 (* in this callstack, the statement is non-terminating *)
-                 add_stack stmt cs
-            ) before_table
+        let process_callstack cs _ =
+          if Eva.Results.(after stmt |> in_callstack cs |> is_empty) then
+            add_stack stmt cs
+          else if match stmt.skind with Loop _ -> true | _ -> false then begin
+            (* special treatment for loops: even if their after state
+                is reachable, we must check that at least one outgoing
+                edge is reachable *)
+            let out_edges = Stmts_graph.get_all_stmt_out_edges stmt in
+            let all_out_edges_unreachable =
+              List.for_all (fun (_, out_stmt) ->
+                  Eva.Results.(before out_stmt |> in_callstack cs |> is_empty)
+                ) out_edges
+            in
+            if all_out_edges_unreachable then add_stack stmt cs
+          end
+        in
+        Eva.Results.(before stmt |> iter_callstacks process_callstack)
     ) vis#get_instr_stmts;
   !new_nonterm_stmts
 
@@ -364,7 +337,7 @@ let cmp_callstacks cs1 cs2 =
 let run () =
   if not (Ast.is_computed ()) then
     Self.abort "nonterm requires a computed AST";
-  if not (Db.Value.is_computed ()) then
+  if not (Eva.Analysis.is_computed ()) then
     Self.abort "nonterm requires a computed value analysis";
   Self.debug "Starting analysis...";
   let file = Ast.get () in
@@ -398,7 +371,7 @@ let run () =
   Self.feedback ~level:2 "Analysis done."
 ;;
 
-let run_once, _ = State_builder.apply_once "Nonterm.run" [Db.Value.self] run
+let run_once, _ = State_builder.apply_once "Nonterm.run" [Eva.Analysis.self] run
 
 let main () =
   if Enabled.get () then run_once ()
-- 
GitLab