diff --git a/ivette/src/frama-c/kernel/ASTinfo.tsx b/ivette/src/frama-c/kernel/ASTinfo.tsx
index 907787a07bc9b6d5ee54ea6b5263e640ff437866..7f6dc684a7e408b10805a21a16ebd90cdf9033da 100644
--- a/ivette/src/frama-c/kernel/ASTinfo.tsx
+++ b/ivette/src/frama-c/kernel/ASTinfo.tsx
@@ -80,20 +80,17 @@ function markerKind (props: AST.markerInfoData): JSX.Element {
 interface InfoItemProps {
   label: string;
   title: string;
-  descr: DATA.text;
+  text: DATA.text;
 }
 
 function InfoItem(props: InfoItemProps): JSX.Element {
   return (
     <div className="astinfo-infos">
-      <div
-        className="dome-text-label astinfo-kind"
-        title={props.title}
-      >
+      <div className="dome-text-label astinfo-kind" title={props.title}>
         {props.label}
       </div>
-      <div className="dome-text-cell astinfo-data">
-        <Text text={props.descr} />
+      <div className="dome-text-cell astinfo-data" title={props.title}>
+        <Text text={props.text} />
       </div>
     </div>
   );
@@ -102,8 +99,9 @@ function InfoItem(props: InfoItemProps): JSX.Element {
 interface ASTinfos {
   id: string;
   label: string;
+  descr: string;
   title: string;
-  descr: DATA.text;
+  text: DATA.text;
 }
 
 interface InfoSectionProps {
@@ -281,7 +279,7 @@ function openFilter(
     };
     return {
       id: info.id,
-      label: `${info.title} (${info.label})`,
+      label: `${info.descr} (${info.label})`,
       checked,
       onClick,
     };
diff --git a/ivette/src/frama-c/kernel/Properties.tsx b/ivette/src/frama-c/kernel/Properties.tsx
index a03ba1c9bf6e1662f13fbaabbbd9fa7eff102525..992743ff4c890b8cce406f532cc797df62d110dc 100644
--- a/ivette/src/frama-c/kernel/Properties.tsx
+++ b/ivette/src/frama-c/kernel/Properties.tsx
@@ -202,27 +202,21 @@ function filterAlarm(alarm: string | undefined): boolean {
 }
 
 function filterEva(p: Property): boolean {
-  let b = true;
   if ('priority' in p && p.priority === false && filter('eva.priority_only'))
-    b = false;
+    return false;
   if ('taint' in p) {
     switch (p.taint) {
       case 'not_tainted':
       case 'not_applicable':
-        if (filter('eva.data_tainted_only') || filter('eva.ctrl_tainted_only'))
-          b = false;
-        break;
-      case 'data_tainted':
-        if (filter('eva.ctrl_tainted_only'))
-          b = false;
-        break;
-      case 'control_tainted':
-        if (filter('eva.data_tainted_only'))
-          b = false;
-        break;
+        return !filter('eva.data_tainted_only') &&
+               !filter('eva.ctrl_tainted_only');
+      case 'direct_taint':
+        return !(filter('eva.ctrl_tainted_only'));
+      case 'indirect_taint':
+        return !(filter('eva.data_tainted_only'));
     }
   }
-  return b;
+  return true;
 }
 
 function filterProperty(p: Property): boolean {
diff --git a/ivette/src/frama-c/kernel/api/ast/index.ts b/ivette/src/frama-c/kernel/api/ast/index.ts
index 932488fecae57980244f4ec7f97e0d99a4db764a..fe8ebaddbc40f66b911d413addc181aa30b8f865 100644
--- a/ivette/src/frama-c/kernel/api/ast/index.ts
+++ b/ivette/src/frama-c/kernel/api/ast/index.ts
@@ -462,7 +462,7 @@ export const getInformationUpdate: Server.Signal = {
 const getInformation_internal: Server.GetRequest<
   marker |
   undefined,
-  { id: string, label: string, title: string, descr: text }[]
+  { id: string, label: string, descr: string, title: string, text: text }[]
   > = {
   kind: Server.RqKind.GET,
   name:   'kernel.ast.getInformation',
@@ -471,8 +471,9 @@ const getInformation_internal: Server.GetRequest<
             Json.jObject({
               id: Json.jFail(Json.jString,'String expected'),
               label: Json.jFail(Json.jString,'String expected'),
+              descr: Json.jFail(Json.jString,'String expected'),
               title: Json.jFail(Json.jString,'String expected'),
-              descr: jTextSafe,
+              text: jTextSafe,
             })),
   signals: [ { name: 'kernel.ast.getInformationUpdate' } ],
 };
@@ -480,7 +481,7 @@ const getInformation_internal: Server.GetRequest<
 export const getInformation: Server.GetRequest<
   marker |
   undefined,
-  { id: string, label: string, title: string, descr: text }[]
+  { id: string, label: string, descr: string, title: string, text: text }[]
   >= getInformation_internal;
 
 const getMarkerAt_internal: Server.GetRequest<
diff --git a/ivette/src/frama-c/plugins/eva/api/general/index.ts b/ivette/src/frama-c/plugins/eva/api/general/index.ts
index 0cc4595adf33d3b1fd1d4afe1a6329010a34775d..cf5797288c8a25bac16d62fbdfff5c641d670080 100644
--- a/ivette/src/frama-c/plugins/eva/api/general/index.ts
+++ b/ivette/src/frama-c/plugins/eva/api/general/index.ts
@@ -247,12 +247,12 @@ export enum taintStatus {
   error = 'error',
   /** **Not applicable:** no taint for this kind of property */
   not_applicable = 'not_applicable',
-  /** **Data tainted:**
+  /** **Direct taint:**
       this property is related to a memory location that can be affected by an attacker */
-  data_tainted = 'data_tainted',
-  /** **Control tainted:**
+  direct_taint = 'direct_taint',
+  /** **Indirect taint:**
       this property is related to a memory location whose assignment depends on path conditions that can be affected by an attacker */
-  control_tainted = 'control_tainted',
+  indirect_taint = 'indirect_taint',
   /** **Untainted property:** this property is safe */
   not_tainted = 'not_tainted',
 }
diff --git a/src/plugins/eva/Eva.mli b/src/plugins/eva/Eva.mli
index df135da7849fbc957d259dbdf022611f6cd5107c..9a535134ce61730528cc9ed81d7eb2c3fe3c5af9 100644
--- a/src/plugins/eva/Eva.mli
+++ b/src/plugins/eva/Eva.mli
@@ -289,6 +289,22 @@ module Results: sig
     (** Memory zone read to compute data addresses. *)
   }
 
+  (** Taint of a memory zone, according to the taint domain. *)
+  type taint =
+    | Direct
+    (** Direct data dependency from values provided by the attacker to the given
+        memory zone, meaning that the attacker may be able to alter its value. *)
+    | Indirect
+    (** Indirect dependency from values provided by the attacker to the given
+        memory zone. The attacker cannot directly alter this memory, but he may
+        be able to impact on the path by which its value is computed. *)
+    | Untainted
+    (** No taint: the given memory zone cannot be modified by the attacker. *)
+
+  (** Evaluates the taint of a given memory zone, according to the taint domain.
+      Returns an error if the taint domain was not enabled. *)
+  val is_tainted : Locations.Zone.t -> request -> (taint, error) Result.t
+
   (** Computes (an overapproximation of) the memory dependencies of an
       expression. *)
   val expr_dependencies : Cil_types.exp -> request -> deps
diff --git a/src/plugins/eva/api/general_requests.ml b/src/plugins/eva/api/general_requests.ml
index e5e522cdd535b6c06febe29b902ffa85661deffc..af6c92b62aeadc55eb1666d4ff39e73cee6ac886 100644
--- a/src/plugins/eva/api/general_requests.ml
+++ b/src/plugins/eva/api/general_requests.ml
@@ -161,33 +161,95 @@ let () = Request.register ~package
 
 (* ----- Register Eva information ------------------------------------------- *)
 
+let term_lval_to_lval tlval =
+  try !Db.Properties.Interp.term_lval_to_lval ~result:None tlval
+  with Db.Properties.Interp.No_conversion -> raise Not_found
+
 let print_value fmt loc =
-  let stmt, eval =
+  let is_scalar = Cil.isScalarType in
+  let kinstr, eval =
     match loc with
-    | Printer_tag.PLval (_kf, Kstmt stmt, lval)
-      when Cil.isScalarType (Cil.typeOfLval lval) ->
-      stmt, Results.eval_lval lval
-    | Printer_tag.PExp (_kf, Kstmt stmt, expr)
-      when Cil.isScalarType (Cil.typeOf expr) ->
-      stmt, Results.eval_exp expr
+    | Printer_tag.PLval (_kf, ki, lval) when is_scalar (Cil.typeOfLval lval) ->
+      ki, Results.eval_lval lval
+    | Printer_tag.PExp (_kf, ki, expr) when is_scalar (Cil.typeOf expr) ->
+      ki, Results.eval_exp expr
+    | PVDecl (_kf, ki, vi) when is_scalar vi.vtype ->
+      ki, Results.eval_var vi
+    | PTermLval (_kf, ki, _ip, tlval) ->
+      let lval = term_lval_to_lval tlval in
+      ki, Results.eval_lval lval
     | _ -> raise Not_found
   in
-  let eval_cvalue at = Results.(at stmt |> eval |> as_cvalue_or_uninitialized) in
-  let before = eval_cvalue Results.before in
-  let after = eval_cvalue Results.after in
   let pretty = Cvalue.V_Or_Uninitialized.pretty in
-  if Cvalue.V_Or_Uninitialized.equal before after
-  then pretty fmt before
-  else Format.fprintf fmt "Before: %a@\nAfter:  %a" pretty before pretty after
+  let eval_cvalue at = Results.(eval at |> as_cvalue_or_uninitialized) in
+  let before = eval_cvalue (Results.before_kinstr kinstr) in
+  match kinstr with
+  | Kglobal -> pretty fmt before
+  | Kstmt stmt ->
+    let after = eval_cvalue (Results.after stmt) in
+    if Cvalue.V_Or_Uninitialized.equal before after
+    then pretty fmt before
+    else Format.fprintf fmt "Before: %a@\nAfter:  %a" pretty before pretty after
 
 let () =
   Server.Kernel_ast.Information.register
     ~id:"eva.value"
     ~label:"Value"
-    ~title:"Possible values inferred by Eva"
+    ~descr:"Possible values inferred by Eva"
     ~enable:Analysis.is_computed
     print_value
 
+let print_taint fmt marker =
+  let loc = Cil_datatype.Location.unknown in
+  let expr, stmt =
+    match marker with
+    | Printer_tag.PLval (_kf, Kstmt stmt, lval) ->
+      Cil.new_exp ~loc (Lval lval), stmt
+    | Printer_tag.PExp (_kf, Kstmt stmt, expr) -> expr, stmt
+    | PVDecl (_kf, Kstmt stmt, vi) ->
+      Cil.new_exp ~loc (Lval (Var vi, NoOffset)), stmt
+    | PTermLval (_kf, Kstmt stmt, _ip, tlval) ->
+      let lval = term_lval_to_lval tlval in
+      Cil.new_exp ~loc (Lval lval), stmt
+    | _ -> raise Not_found
+  in
+  let evaluate_taint request =
+    let deps = Results.expr_dependencies expr request in
+    Result.get_ok (Results.is_tainted deps.data request),
+    Result.get_ok (Results.is_tainted deps.indirect request)
+  in
+  let before = evaluate_taint Results.(before stmt) in
+  let after = evaluate_taint Results.(after stmt) in
+  let str_taint = function
+    | Results.Untainted -> "untainted"
+    | Direct -> "direct taint"
+    | Indirect -> "indirect taint"
+  in
+  let pretty fmt = let open Results in function
+      | taint, Untainted -> Format.fprintf fmt "%s" (str_taint taint)
+      | t1, t2 ->
+        Format.fprintf fmt
+          "%s to the value, %s %s to values used to compute lvalues addresses"
+          (str_taint t1) (if t1 = Untainted then "but" else "and") (str_taint t2)
+  in
+  if before = after
+  then Format.fprintf fmt "%a" pretty before
+  else Format.fprintf fmt "Before: %a@\nAfter:  %a" pretty before pretty after
+
+let () =
+  let enable () = Analysis.is_computed () && Taint_domain.Store.is_computed () in
+  let title =
+    "Taint status:\n\
+     - Direct taint: data dependency from values provided by the attacker, \
+     meaning that the attacker may be able to alter this value\n\
+     - Indirect taint: the attacker cannot directly alter this value, but he \
+     may be able to impact the path by which its value is computed.\n\
+     - Untainted: cannot be modified by the attacker."
+  in
+  Server.Kernel_ast.Information.register
+    ~id:"eva.taint" ~label:"Taint" ~descr: "Taint status according to Eva"
+    ~title ~enable print_taint
+
 let () =
   Analysis.register_computation_hook
     (fun _ -> Server.Kernel_ast.Information.update ())
@@ -196,7 +258,9 @@ let () =
 
 module Taint = struct
   open Server.Data
-  open Taint_domain
+
+  type taint = Results.taint = Direct | Indirect | Untainted
+  type error = NotComputed | Irrelevant | LogicError
 
   let dictionary = Enum.dictionary ()
 
@@ -220,39 +284,69 @@ module Taint = struct
     tag (Error Irrelevant) "not_applicable" "—"
       "Not applicable" "no taint for this kind of property"
 
-  let tag_data_tainted =
-    tag (Ok Data) "data_tainted" "Tainted (data)"
-      "Data tainted"
+  let tag_direct_taint =
+    tag (Ok Direct) "direct_taint" "Tainted (direct)"
+      "Direct taint"
       "this property is related to a memory location that can be affected \
        by an attacker"
 
-  let tag_control_tainted =
-    tag (Ok Control) "control_tainted" "Tainted (control)"
-      "Control tainted"
+  let tag_indirect_taint =
+    tag (Ok Indirect) "indirect_taint" "Tainted (indirect)"
+      "Indirect taint"
       "this property is related to a memory location whose assignment depends \
        on path conditions that can be affected by an attacker"
 
   let tag_untainted =
-    tag (Ok None) "not_tainted" "Untainted"
+    tag (Ok Untainted) "not_tainted" "Untainted"
       "Untainted property" "this property is safe"
 
   let () = Enum.set_lookup dictionary
       begin function
-        | Error Taint_domain.NotComputed -> tag_not_computed
-        | Error Taint_domain.Irrelevant -> tag_not_applicable
-        | Error Taint_domain.LogicError -> tag_error
-        | Ok Data -> tag_data_tainted
-        | Ok Control -> tag_control_tainted
-        | Ok None -> tag_untainted
+        | Error NotComputed -> tag_not_computed
+        | Error Irrelevant -> tag_not_applicable
+        | Error LogicError -> tag_error
+        | Ok Direct -> tag_direct_taint
+        | Ok Indirect -> tag_indirect_taint
+        | Ok Untainted -> tag_untainted
       end
 
   let data = Request.dictionary ~package ~name:"taintStatus"
       ~descr:(Markdown.plain "Taint status of logical properties") dictionary
 
-  include (val data : S with type t = taint_result)
+  include (val data : S with type t = (taint, error) result)
+
+  let zone_of_predicate kinstr predicate =
+    let state = Results.(before_kinstr kinstr |> get_cvalue_model) in
+    let env = Eval_terms.env_only_here state in
+    let logic_deps = Eval_terms.predicate_deps env predicate in
+    match Option.map Cil_datatype.Logic_label.Map.bindings logic_deps with
+    | Some [ BuiltinLabel Here, zone ] -> Ok zone
+    | _ -> Error LogicError
+
+  let get_predicate = function
+    | Property.IPCodeAnnot ica ->
+      begin
+        match ica.ica_ca.annot_content with
+        | AAssert (_, predicate) | AInvariant (_, _, predicate) ->
+          Ok predicate.tp_statement
+        | _ -> Error Irrelevant
+      end
+    | IPPropertyInstance { ii_pred = None } -> Error LogicError
+    | IPPropertyInstance { ii_pred = Some ip } -> Ok ip.ip_content.tp_statement
+    | _ -> Error Irrelevant
+
+  let is_tainted_property ip =
+    if not (Analysis.is_computed () && Taint_domain.Store.is_computed ())
+    then Error NotComputed
+    else
+      let (let+) = Result.bind in
+      let kinstr = Property.get_kinstr ip in
+      let+ predicate = get_predicate ip in
+      let+ zone = zone_of_predicate kinstr predicate in
+      let result = Results.(before_kinstr kinstr |> is_tainted zone) in
+      Result.map_error (fun _ -> NotComputed) result
 end
 
-
 let model = States.model ()
 
 let () = States.column model ~name:"priority"
@@ -265,7 +359,7 @@ let () = States.column model ~name:"taint"
     ~descr:(Markdown.plain "Is the property tainted according to \
                             the Eva taint domain?")
     ~data:(module Taint)
-    ~get:(fun ip -> Taint_domain.is_tainted_property ip)
+    ~get:(fun ip -> Taint.is_tainted_property ip)
 
 let _array =
   States.register_array
diff --git a/src/plugins/eva/domains/taint_domain.ml b/src/plugins/eva/domains/taint_domain.ml
index f32bc939b956f7adb1b141cb95258b418d0bb4fb..95ea09a4a544a6ab00a9f0624547c84d57f67bf0 100644
--- a/src/plugins/eva/domains/taint_domain.ml
+++ b/src/plugins/eva/domains/taint_domain.ml
@@ -24,7 +24,7 @@ open Cil_types
 open Cil_datatype
 open Locations
 
-type taint = {
+type taint_state = {
   (* Over-approximation of the memory locations that are tainted due to a data
      dependency. *)
   locs_data: Zone.t;
@@ -73,7 +73,7 @@ module LatticeTaint = struct
   include Datatype.Make_with_collections(struct
       include Datatype.Serializable_undefined
 
-      type t = taint
+      type t = taint_state
 
       let name = "taint"
 
@@ -296,7 +296,7 @@ end
 
 
 module TaintDomain = struct
-  type state = taint
+  type state = taint_state
   type value = Cvalue.V.t
   type location = Precise_locs.precise_location
   type origin
@@ -595,48 +595,11 @@ let flag =
 let () = Abstractions.register_hook interpret_taint_logic
 
 
-type taint_error = NotComputed | Irrelevant | LogicError
-type taint_ok = Data | Control | None
-type taint_result = (taint_ok, taint_error) result
-
-let zone_of_predicate env predicate =
-  let logic_deps = Eval_terms.predicate_deps env predicate in
-  let deps_list = Option.map Logic_label.Map.bindings logic_deps in
-  match deps_list with
-  | Some [ BuiltinLabel Here, zone ] -> Ok zone
-  | _ -> Error LogicError
-
-let get_predicate = function
-  | Property.IPCodeAnnot ica ->
-    begin
-      match ica.ica_ca.annot_content with
-      | AAssert (_, predicate) | AInvariant (_, _, predicate) ->
-        Ok predicate.tp_statement
-      | _ -> Error Irrelevant
-    end
-  | IPPropertyInstance { ii_pred = None } -> Error LogicError
-  | IPPropertyInstance { ii_pred = Some pred } -> Ok pred.ip_content.tp_statement
-  | _ -> Error Irrelevant
-
-let get_stmt ip =
-  let kinstr = Property.get_kinstr ip in
-  match kinstr with
-  | Kglobal -> Error Irrelevant
-  | Kstmt stmt -> Ok stmt
-
-let is_tainted_property ip =
-  let (let+) = Result.bind in
-  if not (Store.is_computed ()) then Error NotComputed else
-    let+ stmt = get_stmt ip in
-    let+ predicate = get_predicate ip in
-    match Store.get_stmt_state ~after:false stmt with
-    | `Bottom -> Ok None
-    | `Value state ->
-      let cvalue = Db.Value.get_stmt_state ~after:false stmt in
-      let env = Eval_terms.env_only_here cvalue in
-      let+ zone = zone_of_predicate env predicate in
-      if Zone.intersects zone state.locs_data
-      then Ok Data
-      else if Zone.intersects zone state.locs_control
-      then Ok Control
-      else Ok None
+type taint = Direct | Indirect | Untainted
+
+let is_tainted { locs_data ; locs_control } ?indirect zone =
+  let intersects_any z = Zone.(intersects (join locs_data locs_control) z) in
+  let is_indirect () = Option.fold indirect ~none:false ~some:intersects_any in
+  if Zone.intersects zone locs_data then Direct
+  else if Zone.intersects zone locs_control || is_indirect () then Indirect
+  else Untainted
diff --git a/src/plugins/eva/domains/taint_domain.mli b/src/plugins/eva/domains/taint_domain.mli
index 7d911a85ec3668bf67076ed7444bab8d9445c60c..263dcf4d714fd2b52e1c8cacc9e643994163b888 100644
--- a/src/plugins/eva/domains/taint_domain.mli
+++ b/src/plugins/eva/domains/taint_domain.mli
@@ -28,25 +28,9 @@ include Abstract_domain.Leaf
 
 val flag: Abstractions.flag
 
-type taint_error =
-  | NotComputed (** The Eva analysis has not been run, or the taint domain
-                    was not enabled. *)
-  | Irrelevant  (** Properties other than assertions, invariants and
-                    preconditions are irrelevant here. *)
-  | LogicError  (** The memory zone on which the property depends could not
-                    be computed. *)
+type taint = | Direct | Indirect | Untainted
 
-type taint_ok =
-  | Data    (** Data-taint: there is a data dependency from the values provided
-                by the attacker to the given property, meaning that the attacker
-                may alter the values on which the property depends. *)
-  | Control (** Control-taint: there is a control-dependency from the values
-                provided by the attacker to the given property. The attacker
-                cannot directly alter the values on which the property depends,
-                but he may be able to choose the path where these values are
-                computed. *)
-  | None    (** No taint: the property cannot be altered by the attacker. *)
-
-type taint_result = (taint_ok, taint_error) result
-
-val is_tainted_property: Property.t -> taint_result
+(** Is a memory zone tainted according to a given state? 
+    If [indirect] is provided, return an [Indirect] taint if [indirect] is
+    tainted (either directly or indirectly). *)
+val is_tainted: state -> ?indirect:Locations.Zone.t -> Locations.Zone.t -> taint
diff --git a/src/plugins/eva/utils/results.ml b/src/plugins/eva/utils/results.ml
index c7b44e783a11eac858a3a04e99a7e9d4f670b308..d57d536e50ba076ac5d30445a6fb8abbaa1cf401 100644
--- a/src/plugins/eva/utils/results.ml
+++ b/src/plugins/eva/utils/results.ml
@@ -320,6 +320,11 @@ struct
     | Some extract ->
       convert (Response.map_join extract Cvalue.Model.join (get req))
 
+  let get_state req key join =
+    match A.Dom.get key with
+    | None -> Result.error DisabledDomain
+    | Some extract -> convert (Response.map_join extract join (get req))
+
   let print_states ?filter req =
     let state = Response.map_join (fun x -> x) A.Dom.join (get req) in
     let print (type s)
@@ -738,6 +743,15 @@ let expr_dependencies expr request =
   let lval_to_loc lv = eval_address lv request |> as_precise_loc in
   Eva_utils.deps_of_expr lval_to_loc expr
 
+(* Taint *)
+
+type taint = Taint_domain.taint = Direct | Indirect | Untainted
+
+let is_tainted zone request =
+  let module M = Make () in
+  let state = M.get_state request Taint_domain.key Taint_domain.join in
+  Result.map (fun state -> Taint_domain.is_tainted state zone) state
+
 (* Reachability *)
 
 let is_empty rq =
diff --git a/src/plugins/eva/utils/results.mli b/src/plugins/eva/utils/results.mli
index ec7bc51d785b9b4c67436b2af5f527584a4412d6..d221fe82aa36ff2d69860d31e068065918aa475d 100644
--- a/src/plugins/eva/utils/results.mli
+++ b/src/plugins/eva/utils/results.mli
@@ -194,6 +194,22 @@ type deps = Function_Froms.Deps.deps = {
   (** Memory zone read to compute data addresses. *)
 }
 
+(** Taint of a memory zone, according to the taint domain. *)
+type taint =
+  | Direct
+  (** Direct data dependency from values provided by the attacker to the given
+      memory zone, meaning that the attacker may be able to alter its value. *)
+  | Indirect
+  (** Indirect dependency from values provided by the attacker to the given
+      memory zone. The attacker cannot directly alter this memory, but he may
+      be able to impact on the path by which its value is computed. *)
+  | Untainted
+  (** No taint: the given memory zone cannot be modified by the attacker. *)
+
+(** Evaluates the taint of a given memory zone, according to the taint domain.
+    Returns an error if the taint domain was not enabled. *)
+val is_tainted : Locations.Zone.t -> request -> (taint, error) Result.t
+
 (** Computes (an overapproximation of) the memory dependencies of an
     expression. *)
 val expr_dependencies : Cil_types.exp -> request -> deps
diff --git a/src/plugins/server/kernel_ast.ml b/src/plugins/server/kernel_ast.ml
index a50aeb4f09d790b283cb68bf813a6ca8b6b7ae71..1abf9ab1efbf4e4770fe1f41c422085f0397eef8 100644
--- a/src/plugins/server/kernel_ast.ml
+++ b/src/plugins/server/kernel_ast.ml
@@ -577,6 +577,7 @@ struct
     id: string;
     rank: int;
     label: string;
+    descr: string;
     title: string;
     enable: unit -> bool;
     pretty: Format.formatter -> Printer_tag.localizable -> unit
@@ -590,15 +591,17 @@ struct
     let jtype = Package.(Jrecord[
         "id", Jstring ;
         "label", Jstring ;
+        "descr", Jstring ;
         "title", Jstring ;
-        "descr", Jtext.jtype ;
+        "text", Jtext.jtype ;
       ])
     let of_json _ = failwith "Information.Info"
     let to_json (info,text) = `Assoc [
         "id", `String info.id ;
         "label", `String info.label ;
+        "descr", `String info.descr ;
         "title", `String info.title ;
-        "descr", text ;
+        "text", text ;
       ]
   end
 
@@ -640,9 +643,9 @@ struct
 
   let update () = Request.emit signal
 
-  let register ~id ~label ~title ?(enable = fun _ -> true) pretty =
+  let register ~id ~label ~descr ?(title = descr) ?(enable = fun _ -> true) pretty =
     let rank = incr rankId ; !rankId in
-    let info = { id ; rank ; label ; title ; enable ; pretty } in
+    let info = { id ; rank ; label ; descr; title ; enable ; pretty } in
     if Hashtbl.mem registry id then
       ( let msg = Format.sprintf
             "Server.Kernel_ast.register_info: duplicate %S" id in
@@ -669,7 +672,7 @@ let () = Request.register ~package
 let () = Information.register
     ~id:"kernel.ast.location"
     ~label:"Location"
-    ~title:"Source file location"
+    ~descr:"Source file location"
     begin fun fmt loc ->
       let location = Printer_tag.loc_of_localizable loc in
       Filepath.pp_pos fmt (fst location)
@@ -678,7 +681,7 @@ let () = Information.register
 let () = Information.register
     ~id:"kernel.ast.varinfo"
     ~label:"Var"
-    ~title:"Variable Information"
+    ~descr:"Variable Information"
     begin fun fmt loc ->
       match loc with
       | PLval (_ , _, (Var x,NoOffset)) | PVDecl(_,_,x) ->
@@ -702,7 +705,7 @@ let () = Information.register
 let () = Information.register
     ~id:"kernel.ast.typeinfo"
     ~label:"Type"
-    ~title:"Type of C/ASCL expression"
+    ~descr:"Type of C/ASCL expression"
     begin fun fmt loc ->
       let open Printer in
       match loc with
diff --git a/src/plugins/server/kernel_ast.mli b/src/plugins/server/kernel_ast.mli
index bda08edd105c008e283deb57aa911bd7ab69d398..c8e0c52dc788c6e55d2f35ce48def72e3e954a40 100644
--- a/src/plugins/server/kernel_ast.mli
+++ b/src/plugins/server/kernel_ast.mli
@@ -71,15 +71,17 @@ sig
   (**
      Registers a marker information printer.
      Identifier [id] shall be unique.
-     Label [label] shall be very short.
-     Description shall succinctly describe the kind of information.
+     [label] shall be very short.
+     [descr] shall succinctly describe the kind of information.
+     [title] is an optional longer explanation for the kind of information.
      If the optional [enable] function is provided, the information printer is
      only used when [enable ()] returns true.
      The printer is allowed to raise [Not_found] exception when there is no
      information for the localizable.
   *)
   val register :
-    id:string -> label:string -> title:string -> ?enable:(unit -> bool) ->
+    id:string -> label:string -> descr:string -> ?title:string ->
+    ?enable:(unit -> bool) ->
     (Format.formatter -> Printer_tag.localizable -> unit) -> unit
 
   (** Updated information signal *)