From 104d8519aef1aa37cfe689bde6eb1eceb906d702 Mon Sep 17 00:00:00 2001
From: Maxime Jacquemin <maxime2.jacquemin@gmail.com>
Date: Tue, 29 Mar 2022 17:06:45 +0200
Subject: [PATCH] [ivette] Visual details

---
 ivette/src/frama-c/plugins/eva/valuetable.tsx | 55 ++++++++++++-------
 1 file changed, 34 insertions(+), 21 deletions(-)

diff --git a/ivette/src/frama-c/plugins/eva/valuetable.tsx b/ivette/src/frama-c/plugins/eva/valuetable.tsx
index 90d150d605c..44e5cac8643 100644
--- a/ivette/src/frama-c/plugins/eva/valuetable.tsx
+++ b/ivette/src/frama-c/plugins/eva/valuetable.tsx
@@ -21,6 +21,7 @@
 /* ************************************************************************ */
 
 import React from 'react';
+import _ from 'lodash';
 import * as Ivette from 'ivette';
 import * as Dome from 'dome/dome';
 import * as States from 'frama-c/states';
@@ -44,7 +45,7 @@ import { Inset, Button, ButtonGroup } from 'dome/frame/toolbars';
 
 type Request<A, B> = (a: A) => Promise<B>;
 type StateToDisplay = { before: boolean; after: boolean }
-const defaultState = { before: false, after: true }
+const defaultState = { before: true, after: true };
 
 type Alarm = [ 'True' | 'False' | 'Unknown', string ]
 function getAlarmStatus(alarms: Alarm[] | undefined): string {
@@ -145,6 +146,7 @@ interface Probe extends Location {
   code?: string;
   stmt?: Ast.marker;
   rank?: number;
+  evaluable: boolean;
   effects?: boolean;
   condition?: boolean;
   evaluate: Request<callstack, Evaluation>
@@ -376,12 +378,13 @@ function ProbeHeader(props: ProbeHeaderProps): JSX.Element {
   const { code = '(error)', stmt, target, fct } = probe;
   const color = classes(MarkerStatusClass(status), 'eva-table-header-sticky');
   const { selectProbe, removeProbe, pinProbe } = props;
+  const { before, after } = state;
 
   // Computing the number of columns..
   let span = 0;
-  if (state.before) span += 2;
-  if (state.after && !probe.condition) span += 2;
-  if (state.after && probe.condition) span += 4;
+  if (before || after && !probe.effects) span += 2;
+  if (after && probe.effects) span += 2;
+  if (after && probe.condition) span += 4;
   if (span === 0) return <></>;
 
   // When the location is selected, we scroll the header into view, making it
@@ -432,6 +435,7 @@ interface ProbeDescrProps {
 
 function ProbeDescr(props: ProbeDescrProps): JSX.Element[] {
   const { probe, state } = props;
+  const { before, after } = state;
   const valuesClass = classes('eva-table-values', 'eva-table-values-center');
   const tableClass = classes('eva-table-descrs', 'eva-table-descr-sticky');
   const cls = classes(valuesClass, tableClass);
@@ -441,9 +445,10 @@ function ProbeDescr(props: ProbeDescrProps): JSX.Element[] {
   function push(title: string, children: JSX.Element | string): void {
     elements.push(<td {...infos} title={title}>{children}</td>);
   }
-  if (state.before) push(title('before'), 'Before');
-  if (state.after && !probe.condition) push(title('after'), 'After');
-  if (state.after && probe.condition) {
+  if (before && probe.effects) push(title('before'), 'Before');
+  if (after && probe.effects) push(title('after'), 'After');
+  if ((before || after) && !probe.effects) push('Values at the statement', '-');
+  if (after && probe.condition) {
     const pushCondition = (s: string): void => {
       const t = `Values after the condition, in the ${s.toLowerCase()} branch`;
       const child =
@@ -485,6 +490,7 @@ interface ProbeValuesProps {
 
 function ProbeValues(props: ProbeValuesProps): Request<callstack, JSX.Element> {
   const { probe, summary, state, addLoc, summaryOnly } = props;
+  const { before, after } = state;
   const summaryStatus = getAlarmStatus(summary.vBefore?.alarms);
 
   // Building common parts
@@ -511,33 +517,37 @@ function ProbeValues(props: ProbeValuesProps): Request<callstack, JSX.Element> {
     const selected = isSelected && callstack !== 'Summary' ? 'eva-focused' : '';
     const font = summaryOnly && callstack === 'Summary' ? 'eva-italic' : '';
     const className = classes('eva-table-values', selected, font);
-    function td(e?: Values.evaluation): JSX.Element {
+    const kind = callstack === 'Summary' ? 'one' : 'this';
+    const title = `At least one alarm is raised in ${kind} callstack`;
+    const width = summaryStatus !== 'none' ? 'eva-table-values-alarms' : '';
+    function td(e?: Values.evaluation, colSpan = 1): JSX.Element {
       const { alarms, value = '-' } = e ?? {};
       const status = getAlarmStatus(alarms);
       const alarmClass = classes('eva-cell-alarms', `eva-alarm-${status}`);
-      const kind = callstack === 'Summary' ? 'one' : 'this';
-      const title = `At least one alarm is raised in ${kind} callstack`;
       const align = value?.includes('\n') ? 'left' : 'center';
       const alignClass = `eva-table-values-${align}`;
-      const width = summaryStatus !== 'none' ? 'eva-table-values-alarms' : '';
       const c = classes(className, alignClass, width);
       return (
         <>
-          <td className={c} onContextMenu={onContextMenu(e)}>
+          <td className={c} colSpan={colSpan} onContextMenu={onContextMenu(e)}>
             <span >{value}</span>
           </td>
-          <td className={classes('eva-table-alarm', selected)}>
+          <td
+            className={classes('eva-table-alarm', selected)}
+            style={{ width: status === 'none' ? '0px' : '17px' }}
+          >
             <Icon className={alarmClass} size={10} title={title} id="WARNING" />
           </td>
         </>
       );
     }
     const elements: JSX.Element[] = [];
-    if (state.before) elements.push(td(vBefore));
-    if (state.after && !probe.condition) elements.push(td(vAfter));
-    if (state.after && probe.condition) {
-      elements.push(td(vThen));
-      elements.push(td(vElse));
+    if (before && after && probe.effects && _.isEqual(vBefore, vAfter))
+      elements.push(td(vBefore, 3));
+    else {
+      if (before || after && !probe.effects) elements.push(td(vBefore));
+      if (after && probe.effects) elements.push(td(vAfter));
+      if (after && probe.condition) elements.push(td(vThen), td(vElse));
     }
     return <>{React.Children.toArray(elements)}</>;
   };
@@ -953,10 +963,13 @@ function EvaTable(): JSX.Element {
     const target = selection?.current?.marker;
     const fct = selection?.current?.fct;
     const loc = (target && fct) ? { target, fct } : undefined;
-    const f = (p: Probe): void => { if (fct && p.code) fcts.newFunction(fct); };
-    const update = (p: Probe): void => { f(p) ; setFocus(p); locEvt.emit(p); };
     fcts.clean(loc);
-    if (loc) getProbe(loc).then(update);
+    const doUpdate = (p: Probe): void => {
+      if (!p.evaluable) { setFocus(undefined); return; }
+      if (fct && p.code) fcts.newFunction(fct);
+      setFocus(p); locEvt.emit(p);
+    }
+    if (loc) getProbe(loc).then(doUpdate);
     else setFocus(undefined);
   }, [ fcts, selection, getProbe, setFocus, locEvt ]);
 
-- 
GitLab