From d14e3b2a6198a9bd1bcc302cd70627b968e50fba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr>
Date: Sat, 25 Nov 2023 15:40:12 +0100
Subject: [PATCH] [server] New synchronized array for global variables.

---
 ivette/src/frama-c/kernel/api/ast/index.ts | 120 +++++++++++++++++++++
 src/plugins/server/kernel_ast.ml           |  73 +++++++++++++
 2 files changed, 193 insertions(+)

diff --git a/ivette/src/frama-c/kernel/api/ast/index.ts b/ivette/src/frama-c/kernel/api/ast/index.ts
index 749c722b9e3..65907b9357a 100644
--- a/ivette/src/frama-c/kernel/api/ast/index.ts
+++ b/ivette/src/frama-c/kernel/api/ast/index.ts
@@ -513,6 +513,126 @@ export const functionsDataDefault: functionsData =
     stdlib: undefined, builtin: undefined, extern: undefined,
     sloc: sourceDefault };
 
+/** Data for array rows [`globals`](#globals)  */
+export interface globalsData {
+  /** Entry identifier. */
+  key: Json.key<'#globals'>;
+  /** Declaration Tag */
+  decl: decl;
+  /** Name */
+  name: string;
+  /** Type */
+  type: string;
+  /** Is the variable from the Frama-C stdlib? */
+  stdlib: boolean;
+  /** Is the variable extern? */
+  extern: boolean;
+  /** Is the variable const? */
+  const: boolean;
+  /** Is the variable volatile? */
+  volatile: boolean;
+  /** Is the variable ghost? */
+  ghost: boolean;
+  /** Is the variable explicitly initialized? */
+  init: boolean;
+  /** Is the variable in the source code? */
+  source: boolean;
+  /** Source location */
+  sloc: source;
+}
+
+/** Decoder for `globalsData` */
+export const jGlobalsData: Json.Decoder<globalsData> =
+  Json.jObject({
+    key: Json.jKey<'#globals'>('#globals'),
+    decl: jDecl,
+    name: Json.jString,
+    type: Json.jString,
+    stdlib: Json.jBoolean,
+    extern: Json.jBoolean,
+    const: Json.jBoolean,
+    volatile: Json.jBoolean,
+    ghost: Json.jBoolean,
+    init: Json.jBoolean,
+    source: Json.jBoolean,
+    sloc: jSource,
+  });
+
+/** Natural order for `globalsData` */
+export const byGlobalsData: Compare.Order<globalsData> =
+  Compare.byFields
+    <{ key: Json.key<'#globals'>, decl: decl, name: string, type: string,
+       stdlib: boolean, extern: boolean, const: boolean, volatile: boolean,
+       ghost: boolean, init: boolean, source: boolean, sloc: source }>({
+    key: Compare.string,
+    decl: byDecl,
+    name: Compare.alpha,
+    type: Compare.string,
+    stdlib: Compare.boolean,
+    extern: Compare.boolean,
+    const: Compare.boolean,
+    volatile: Compare.boolean,
+    ghost: Compare.boolean,
+    init: Compare.boolean,
+    source: Compare.boolean,
+    sloc: bySource,
+  });
+
+/** Signal for array [`globals`](#globals)  */
+export const signalGlobals: Server.Signal = {
+  name: 'kernel.ast.signalGlobals',
+};
+
+const reloadGlobals_internal: Server.GetRequest<null,null> = {
+  kind: Server.RqKind.GET,
+  name: 'kernel.ast.reloadGlobals',
+  input: Json.jNull,
+  output: Json.jNull,
+  signals: [],
+};
+/** Force full reload for array [`globals`](#globals)  */
+export const reloadGlobals: Server.GetRequest<null,null>= reloadGlobals_internal;
+
+const fetchGlobals_internal: Server.GetRequest<
+  number,
+  { reload: boolean, removed: Json.key<'#globals'>[], updated: globalsData[],
+    pending: number }
+  > = {
+  kind: Server.RqKind.GET,
+  name: 'kernel.ast.fetchGlobals',
+  input: Json.jNumber,
+  output: Json.jObject({
+            reload: Json.jBoolean,
+            removed: Json.jArray(Json.jKey<'#globals'>('#globals')),
+            updated: Json.jArray(jGlobalsData),
+            pending: Json.jNumber,
+          }),
+  signals: [],
+};
+/** Data fetcher for array [`globals`](#globals)  */
+export const fetchGlobals: Server.GetRequest<
+  number,
+  { reload: boolean, removed: Json.key<'#globals'>[], updated: globalsData[],
+    pending: number }
+  >= fetchGlobals_internal;
+
+const globals_internal: State.Array<Json.key<'#globals'>,globalsData> = {
+  name: 'kernel.ast.globals',
+  getkey: ((d:globalsData) => d.key),
+  signal: signalGlobals,
+  fetch: fetchGlobals,
+  reload: reloadGlobals,
+  order: byGlobalsData,
+};
+/** AST global variables */
+export const globals: State.Array<Json.key<'#globals'>,globalsData> = globals_internal;
+
+/** Default value for `globalsData` */
+export const globalsDataDefault: globalsData =
+  { key: Json.jKey<'#globals'>('#globals')(''), decl: declDefault, name: '',
+    type: '', stdlib: false, extern: false, const: false, volatile: false,
+    ghost: false, init: false, source: false, sloc: sourceDefault };
+
 /** Updated AST information */
 export const getInformationUpdate: Server.Signal = {
   name: 'kernel.ast.getInformationUpdate',
diff --git a/src/plugins/server/kernel_ast.ml b/src/plugins/server/kernel_ast.ml
index db570556c41..41fc7a08cf5 100644
--- a/src/plugins/server/kernel_ast.ml
+++ b/src/plugins/server/kernel_ast.ml
@@ -683,6 +683,79 @@ struct
 
 end
 
+(* -------------------------------------------------------------------------- *)
+(* --- Global variables                                                   --- *)
+(* -------------------------------------------------------------------------- *)
+
+module GlobalVars = struct
+
+  let key vi = Printf.sprintf "vi#%d" vi.vid
+
+  let _ : varinfo States.array =
+    let model = States.model () in
+    States.column model
+      ~name:"decl"
+      ~descr:(Md.plain "Declaration Tag")
+      ~data:(module Decl)
+      ~get:(fun vi -> Printer_tag.SGlobal vi);
+    States.column model
+      ~name:"name"
+      ~descr:(Md.plain "Name")
+      ~data:(module Data.Jalpha)
+      ~get:(fun vi -> vi.vname);
+    States.column model
+      ~name:"type"
+      ~descr:(Md.plain "Type")
+      ~data:(module Jstring)
+      ~get:(fun vi -> Rich_text.to_string Printer.pp_typ vi.vtype);
+    States.column model
+      ~name:"stdlib"
+      ~descr:(Md.plain "Is the variable from the Frama-C stdlib?")
+      ~data:(module Data.Jbool)
+      ~get:(fun vi -> Cil.is_in_libc vi.vattr);
+    States.column model
+      ~name:"extern"
+      ~descr:(Md.plain "Is the variable extern?")
+      ~data:(module Data.Jbool)
+      ~get:(fun vi -> vi.vstorage = Extern);
+    States.column model
+      ~name:"const"
+      ~descr:(Md.plain "Is the variable const?")
+      ~data:(module Data.Jbool)
+      ~get:(fun vi -> Cil.isGlobalInitConst vi);
+    States.column model
+      ~name:"volatile"
+      ~descr:(Md.plain "Is the variable volatile?")
+      ~data:(module Data.Jbool)
+      ~get:(fun vi -> Cil.isVolatileType vi.vtype);
+    States.column model
+      ~name:"ghost"
+      ~descr:(Md.plain "Is the variable ghost?")
+      ~data:(module Data.Jbool)
+      ~get:(fun vi -> Cil.isGhostType vi.vtype);
+    States.column model
+      ~name:"init"
+      ~descr:(Md.plain "Is the variable explicitly initialized?")
+      ~data:(module Data.Jbool)
+      ~get:(fun vi -> Option.is_some (Globals.Vars.find vi).init);
+    States.column model
+      ~name:"source"
+      ~descr:(Md.plain "Is the variable in the source code?")
+      ~data:(module Data.Jbool)
+      ~get:(fun vi -> vi.vsource);
+    States.column model
+      ~name:"sloc"
+      ~descr:(Md.plain "Source location")
+      ~data:(module Position)
+      ~get:(fun vi -> fst vi.vdecl);
+    States.register_array model
+      ~package ~key
+      ~name:"globals"
+      ~descr:(Md.plain "AST global variables")
+      ~iter:(fun f -> Globals.Vars.iter (fun vi _init -> f vi))
+      ~add_reload_hook:ast_update_hook
+end
+
 (* -------------------------------------------------------------------------- *)
 (* --- Marker Information                                                 --- *)
 (* -------------------------------------------------------------------------- *)
-- 
GitLab