From a052353965e8b9d7eb0e582a31ab2762c1037c1f Mon Sep 17 00:00:00 2001
From: Maxime Jacquemin <maxime.jacquemin@cea.fr>
Date: Tue, 3 Oct 2023 13:51:21 +0200
Subject: [PATCH] [Ivette] Minor modification

Tried to make the code cleaner and clearer.
---
 ivette/src/dome/renderer/text/editor.tsx | 22 +++++++++++-
 ivette/src/frama-c/kernel/ASTview.tsx    | 36 +++++++++----------
 src/plugins/eva/api/general_requests.ml  | 46 +++++++++++-------------
 3 files changed, 59 insertions(+), 45 deletions(-)

diff --git a/ivette/src/dome/renderer/text/editor.tsx b/ivette/src/dome/renderer/text/editor.tsx
index ea59f699394..094988c0656 100644
--- a/ivette/src/dome/renderer/text/editor.tsx
+++ b/ivette/src/dome/renderer/text/editor.tsx
@@ -48,13 +48,33 @@ export { RangeSet } from '@codemirror/state';
 
 
 
+// -----------------------------------------------------------------------------
+// Ranges definition and interface
+// -----------------------------------------------------------------------------
+
+// Type definition.
+export type Range = { from: number, to: number };
+
+// Comparison function
+export function compareRange(x: Range, y: Range): number {
+  return (x.from !== y.from) ? (x.from - y.from) : (y.to - x.to);
+}
+
+// Checks if the start of the range x belongs in y.
+export function startInto(x: Range, y: Range): boolean {
+  return y.from <= x.from && x.from < y.to;
+}
+
+// -----------------------------------------------------------------------------
+
+
+
 // -----------------------------------------------------------------------------
 //  CodeMirror state's extensions types definitions
 // -----------------------------------------------------------------------------
 
 // Helper types definitions.
 export type View = EditorView | null;
-export type Range = { from: number, to: number };
 export type Set<A> = (view: View, value: A) => void;
 export type Get<A> = (state: EditorState | undefined) => A;
 export type IsUpdated = (update: ViewUpdate) => boolean;
diff --git a/ivette/src/frama-c/kernel/ASTview.tsx b/ivette/src/frama-c/kernel/ASTview.tsx
index 531e0bee723..7d8d6e34d10 100644
--- a/ivette/src/frama-c/kernel/ASTview.tsx
+++ b/ivette/src/frama-c/kernel/ASTview.tsx
@@ -325,31 +325,29 @@ function createMultipleDecorator(): Editor.Extension {
 const emptyDeadCode = { reached: [], unreachable: [], nonTerminating: [] };
 const Dead = Editor.createField<Eva.deadCode>(emptyDeadCode);
 
-function diffRanges(a: Editor.Range[], b: Editor.Range[]): Editor.Range[] {
-  const cmp = (x: Editor.Range, y: Editor.Range): number => {
-    return (x.from !== y.from) ? (x.from - y.from) : (y.to - x.to);
-  };
-  a.sort(cmp);
-  b.sort(cmp);
-  function split(x: Editor.Range): Editor.Range[] {
-    const y = b.find((r) => r.from >= x.from && r.from < x.to);
-    if (y === undefined) return [x];
-    const t = [];
-    if (x.from < y.from) t.push({ from: x.from, to: y.from - 1 });
-    if (y.to < x.to) return t.concat(split({ from: y.to + 1, to: x.to }));
-    return t;
+// The unreachable statements given by the server may contain reachable
+// statements. This function is used to filter those reached statements.
+function filterReached(unreachables: Range[], reachables: Range[]): Range[] {
+  function keepTrulyUnreached(unreached: Range): Range[] {
+    const reached = reachables.find((r) => Editor.startInto(r, unreached));
+    if (reached === undefined) return [unreached];
+    const next = { from: reached.to + 1, to: unreached.to };
+    const result = (reached.to < unreached.to) ? keepTrulyUnreached(next) : [];
+    const reallyUnreached = { from: unreached.from, to: reached.from - 1 };
+    if (unreached.from < reached.from) result.unshift(reallyUnreached);
+    return result;
   }
-  return a.flatMap(split);
+  return unreachables.map(keepTrulyUnreached).flat();
 }
 
 const UnreachableRanges = createUnreachableRanges();
 function createUnreachableRanges(): Editor.Aspect<Editor.Range[]> {
   const deps = { dead: Dead, ranges: Ranges };
-  return Editor.createAspect(deps, ({ dead, ranges }) => {
-    const unreachable = mapFilter(dead.unreachable, m => ranges.get(m)).flat();
-    const reached = mapFilter(dead.reached, m => ranges.get(m)).flat();
-    const r = diffRanges(unreachable, reached);
-    return r;
+  return Editor.createAspect(deps, ({ dead, ranges: rs }) => {
+    const get = (ms: Ast.marker[]): Range[][] => mapFilter(ms, m => rs.get(m));
+    const unreachable = get(dead.unreachable).flat().sort(Editor.compareRange);
+    const reached = get(dead.reached).flat().sort(Editor.compareRange);
+    return filterReached(unreachable, reached);
   });
 }
 
diff --git a/src/plugins/eva/api/general_requests.ml b/src/plugins/eva/api/general_requests.ml
index edfea51036a..76c68cd47ab 100644
--- a/src/plugins/eva/api/general_requests.ml
+++ b/src/plugins/eva/api/general_requests.ml
@@ -168,8 +168,8 @@ module DeadCode = struct
   let jtype = R.jtype
 
   let to_json (dead_code) =
-    let make_stmt stmt = Printer_tag.PStmt (dead_code.kf, stmt)
-    and make_non_term stmt = Printer_tag.PStmtStart (dead_code.kf, stmt) in
+    let make_stmt stmt = Printer_tag.PStmt (dead_code.kf, stmt) in
+    let make_non_term stmt = Printer_tag.PStmtStart (dead_code.kf, stmt) in
     R.default |>
     R.set reached (List.map make_stmt dead_code.reached) |>
     R.set unreachable (List.map make_stmt dead_code.unreachable) |>
@@ -177,30 +177,26 @@ module DeadCode = struct
     R.to_json
 end
 
+let all_statements kf =
+  try (Kernel_function.get_definition kf).sallstmts
+  with Kernel_function.No_Definition -> []
+
 let dead_code kf =
-  let empty =
-    { kf; reached = []; unreachable = []; non_terminating = []; }
-  in
-  if Analysis.is_computed ()
-  then
-    try
-      let fundec = Kernel_function.get_definition kf in
-      match Analysis.status kf with
-      | Unreachable | SpecUsed | Builtin _ ->
-        { empty with unreachable = fundec.sallstmts; }
-      | Analyzed NoResults -> empty
-      | Analyzed (Partial | Complete) ->
-        let classify acc stmt =
-          if Results.(before stmt |> is_empty)
-          then { acc with unreachable = stmt :: acc.unreachable }
-          else
-            let acc = { acc with reached = stmt :: acc.reached } in
-            if Results.(after stmt |> is_empty)
-            then { acc with non_terminating = stmt :: acc.non_terminating }
-            else acc
-        in
-        List.fold_left classify empty fundec.sallstmts
-    with Kernel_function.No_Definition -> empty
+  let empty = { kf ; reached = [] ; unreachable = [] ; non_terminating = [] } in
+  if Analysis.is_computed () then
+    let body = all_statements kf in
+    match Analysis.status kf with
+    | Unreachable | SpecUsed | Builtin _ -> { empty with unreachable = body }
+    | Analyzed NoResults -> empty
+    | Analyzed (Partial | Complete) ->
+      let classify { kf ; reached ; unreachable ; non_terminating = nt } stmt =
+        let before = Results.(before stmt |> is_empty) in
+        let after = Results.(after stmt |> is_empty) in
+        let unreachable = if before then stmt :: unreachable else unreachable in
+        let reached = if not before then stmt :: reached else reached in
+        let non_terminating = if not before && after then stmt :: nt else nt in
+        { kf ; reached ; unreachable ; non_terminating }
+      in List.fold_left classify empty body
   else empty
 
 let () = Request.register ~package
-- 
GitLab