~ubuntu-branches/debian/sid/frama-c/sid

« back to all changes in this revision

Viewing changes to src/slicing/register_gui.R1.29.ml

  • Committer: Bazaar Package Importer
  • Author(s): Mehdi Dogguy
  • Date: 2009-06-03 08:19:25 UTC
  • Revision ID: james.westby@ubuntu.com-20090603081925-kihvxvt0wy3zc4ar
Tags: upstream-20081201.dfsg
ImportĀ upstreamĀ versionĀ 20081201.dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
(**************************************************************************)
 
2
(*                                                                        *)
 
3
(*  This file is part of Frama-C.                                         *)
 
4
(*                                                                        *)
 
5
(*  Copyright (C) 2007-2008                                               *)
 
6
(*    CEA   (Commissariat ļæ½ l'ļæ½nergie Atomique)                           *)
 
7
(*    INRIA (Institut National de Recherche en Informatique et en         *)
 
8
(*           Automatique)                                                 *)
 
9
(*                                                                        *)
 
10
(*  you can redistribute it and/or modify it under the terms of the GNU   *)
 
11
(*  Lesser General Public License as published by the Free Software       *)
 
12
(*  Foundation, version 2.1.                                              *)
 
13
(*                                                                        *)
 
14
(*  It is distributed in the hope that it will be useful,                 *)
 
15
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
 
16
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
 
17
(*  GNU Lesser General Public License for more details.                   *)
 
18
(*                                                                        *)
 
19
(*  See the GNU Lesser General Public License version v2.1                *)
 
20
(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
 
21
(*                                                                        *)
 
22
(**************************************************************************)
 
23
 
 
24
(*i $Id: register_gui.ml,v 1.29 2008/10/17 12:50:56 uid527 Exp $ i*)
 
25
open Cil_types
 
26
open Cilutil 
 
27
 
 
28
module Enabled=
 
29
  Computation.Ref
 
30
    (struct include Datatype.Bool let default () = true end)
 
31
    (struct let name = "SlicingGui.Enabled" let dependencies = [] end)
 
32
 
 
33
let set_enabled b =
 
34
  Enabled.set b
 
35
    
 
36
let get_enabled () =
 
37
  Enabled.get ()
 
38
    
 
39
(* for slicing callback *)
 
40
let mk_selection fselect = fselect (!Db.Slicing.Select.empty_selects ())
 
41
  
 
42
(* for slicing callback *)
 
43
let mk_selection_cad fselect =
 
44
  mk_selection fselect (!Db.Slicing.Mark.make ~ctrl:true ~addr:true ~data:true)
 
45
    
 
46
(* for slicing callback *)
 
47
let mk_selection_all fselect =
 
48
  mk_selection fselect ~spare:false
 
49
    
 
50
(* for slicing callback *)
 
51
let mk_slice selection =
 
52
  let n = string_of_int (1 + List.length (!Db.Slicing.Project.get_all ())) in
 
53
  let project = !Db.Slicing.Project.mk_project ("Slicing "^ n) in
 
54
    !Db.Slicing.Request.add_persistent_selection project selection ;
 
55
    !Db.Slicing.Request.apply_all_internal project;          
 
56
    if Cmdline.Slicing.Mode.Callers.get () then
 
57
      !Db.Slicing.Slice.remove_uncalled project;
 
58
    let new_project = !Db.Slicing.Project.extract ((!Db.Slicing.Project.get_name project)^ " export") project in
 
59
      !Db.Slicing.Project.set_project (Some (project)) ;
 
60
      new_project
 
61
 
 
62
(* To add a sensitive/unsensitive menu item to a [factory] *)
 
63
let add_item (factory:GMenu.menu GMenu.factory) ~callback name arg_opt =
 
64
    match arg_opt with
 
65
      | None -> (* add the menu item, but it isn't sensitive *)
 
66
          let item = factory#add_item name ~callback:(fun () -> ())
 
67
          in item#misc#set_sensitive false
 
68
      | Some arg -> (* add the menu item with its callback *)
 
69
          ignore (factory#add_item name ~callback:(fun () -> callback arg))
 
70
 
 
71
       
 
72
let gui_annot_info (main_ui:Design.main_window_extension_points) ~level txt =
 
73
  if (Cmdline.Slicing.Mode.Verbose.get () >= level) then
 
74
    begin
 
75
      main_ui#annot_window#buffer#insert ((txt ()) ^ ".\n")
 
76
    end
 
77
      
 
78
let gui_annot_action (main_ui:Design.main_window_extension_points) txt =
 
79
  if (Cmdline.Slicing.Mode.Verbose.get () >= 0) then
 
80
    begin
 
81
      let tag_style_italic = Gtk_helper.make_tag main_ui#annot_window#buffer ~name:"slicing:style italic" [`STYLE `ITALIC] in
 
82
        main_ui#annot_window#buffer#insert ~tags:[tag_style_italic] ((txt ()) ^ "\n")
 
83
    end
 
84
      
 
85
let gui_annot_error (main_ui:Design.main_window_extension_points) txt =
 
86
  let tag_style_italic = Gtk_helper.make_tag main_ui#annot_window#buffer ~name:"slicing:style italic" [`STYLE `OBLIQUE  ; ] in
 
87
    main_ui#annot_window#buffer#insert ~tags:[tag_style_italic] (txt ^ ".\n")
 
88
      
 
89
let gui_mk_slice main_ui selection ~info =
 
90
  let already_locked =
 
91
    gui_annot_action main_ui info;
 
92
    main_ui#lock () in (* lock the gui while ... *)
 
93
  let new_project = mk_slice selection in (* ... slicing computation *)
 
94
    main_ui#unlock already_locked ;
 
95
    gui_annot_action main_ui (fun () -> "Slice exported to project: " ^ (Project.name new_project));
 
96
    main_ui#rehighlight ()
 
97
        
 
98
let gui_compute_values (main_ui:Design.main_window_extension_points) =
 
99
  if not (Db.Value.is_computed ()) then
 
100
    begin
 
101
      gui_annot_action main_ui (fun () -> "Activating slicing plugin by running value analysis first");
 
102
      let already_locked = main_ui#lock () in
 
103
        (try !Db.Value.compute ();
 
104
         with Globals.No_such_entry_point msg -> gui_annot_error main_ui msg);
 
105
        main_ui#unlock already_locked
 
106
    end
 
107
      
 
108
let gui_apply_action (main_ui:Design.main_window_extension_points) f x ~info =
 
109
  f x ;
 
110
  gui_annot_action main_ui info
 
111
 
 
112
let get_setting_option_text txt = "Setting option " ^ txt ^ " for the current project"
 
113
  
 
114
let gui_toggle_slice_undef (main_ui:Design.main_window_extension_points) =
 
115
  let slice_undef = not (Cmdline.Slicing.Mode.SliceUndef.get ()) in
 
116
    gui_apply_action main_ui Cmdline.Slicing.Mode.SliceUndef.set slice_undef
 
117
      ~info:(fun () ->
 
118
               
 
119
               if slice_undef then (get_setting_option_text "-slice-undef-functions" )^
 
120
                 ". Allow the use of the slicing level for calls to undefined functions"
 
121
               else (get_setting_option_text "-no-slice-undef-functions") ^
 
122
                 ". Forbid the slicing of prototypes of undefined functions")
 
123
    
 
124
let gui_incr_verbose (main_ui:Design.main_window_extension_points) incr =
 
125
  let v = (Cmdline.Slicing.Mode.Verbose.get ()) + incr in
 
126
    gui_apply_action main_ui Cmdline.Slicing.Mode.Verbose.set v
 
127
      ~info:(fun () -> get_setting_option_text ("-slicing-debug \"-debug " ^ (string_of_int v) ^ "\""))
 
128
    
 
129
let gui_incr_level (main_ui:Design.main_window_extension_points) incr =
 
130
  let v = (Cmdline.Slicing.Mode.Calls.get ()) + incr in
 
131
    gui_apply_action main_ui Cmdline.Slicing.Mode.Calls.set v
 
132
      ~info:(fun () -> get_setting_option_text ("-slicing-level " ^ (string_of_int v)))
 
133
    
 
134
let gui_toggle_enabled (main_ui:Design.main_window_extension_points) =
 
135
  let enabled = not (get_enabled ()) in
 
136
    gui_compute_values main_ui ;
 
137
    gui_apply_action main_ui set_enabled enabled
 
138
      ~info:(fun () ->
 
139
         if enabled then "Enabling slicing requests"
 
140
         else "Disabling slicing requests") ;
 
141
    main_ui#rehighlight ()
 
142
 
 
143
let gui_set_project (main_ui:Design.main_window_extension_points) proj_opt =
 
144
  gui_apply_action main_ui !Db.Slicing.Project.set_project proj_opt
 
145
    ~info:(fun () ->
 
146
             Extlib.may_map ~dft:"Clear slicing highlighting"
 
147
               (fun project -> ("Highlighting for " ^ (!Db.Slicing.Project.get_name project)))
 
148
               proj_opt) ;
 
149
  main_ui#rehighlight ()
 
150
      
 
151
let slicing_selector (popup_factory:GMenu.menu GMenu.factory)
 
152
    (main_ui:Design.main_window_extension_points) ~button localizable = 
 
153
  if not (Db.Value.is_computed ()) then
 
154
    ignore (popup_factory#add_item "Activate _Slicing"
 
155
              ~callback:(fun () -> gui_compute_values main_ui ))
 
156
  else if not (get_enabled ()) then
 
157
    ignore (popup_factory#add_item "Enable _Slicing menu"
 
158
              ~callback:(fun () -> gui_toggle_enabled main_ui))
 
159
  else
 
160
    let slicing_project = !Db.Slicing.Project.get_project () in
 
161
      if button = 1 then
 
162
        begin let level = 0 in
 
163
        let slicing_view project =
 
164
          gui_annot_info main_ui ~level (fun () -> "Highlighting for " ^ (!Db.Slicing.Project.get_name project))
 
165
        in 
 
166
          Extlib.may slicing_view slicing_project;
 
167
          if Cmdline.Slicing.Mode.Verbose.get () > level then begin
 
168
            let slicing_mark project =
 
169
              let slicing_mark kf get_mark =
 
170
                (* use -slicing-debug -verbose to get slicing mark information *)
 
171
                let add_mark_info txt = gui_annot_info ~level main_ui (fun () -> "Tag: " ^ (txt ())) in
 
172
                let slices = !Db.Slicing.Slice.get_all project kf in
 
173
                  match slices with
 
174
                    | [] -> (* No slice for this kf *)
 
175
                        add_mark_info (fun () ->
 
176
                                         if !Db.Slicing.Project.is_called project kf
 
177
                                         then (* but the source function is called *)
 
178
                                           (Cil.fprintf_to_string "<src>%a"
 
179
                                              !Db.Slicing.Mark.pretty (!Db.Slicing.Mark.get_from_src_func project kf))
 
180
                                         else
 
181
                                           "<   ><   >")
 
182
                    | slices ->
 
183
                        if !Db.Slicing.Project.is_called project kf
 
184
                        then begin (* The source function is also called *)
 
185
                          assert (not (kf == fst (Globals.entry_point ()))) ;
 
186
                          add_mark_info (fun () ->
 
187
                                           Cil.fprintf_to_string "<src>%a"
 
188
                                             !Db.Slicing.Mark.pretty (!Db.Slicing.Mark.get_from_src_func project kf))
 
189
                        end ;
 
190
                        let mark_slice slice =
 
191
                          add_mark_info (fun () -> Cil.fprintf_to_string "%a" !Db.Slicing.Mark.pretty (get_mark slice))
 
192
                        in List.iter mark_slice slices
 
193
              in match localizable with
 
194
                | Pretty_source.PTermLval(Some kf,(Kstmt ki),_) (* as for the statement *)
 
195
                | Pretty_source.PLval (Some kf,(Kstmt ki),_) (* as for the statement *)
 
196
                | Pretty_source.PStmt (kf,ki) -> slicing_mark kf (fun slice -> !Db.Slicing.Slice.get_mark_from_stmt slice ki)
 
197
                | Pretty_source.PVDecl (Some kf,vi) -> slicing_mark kf (fun slice -> !Db.Slicing.Slice.get_mark_from_local_var slice vi)
 
198
                | _ -> ()
 
199
            in Extlib.may slicing_mark slicing_project
 
200
          end 
 
201
        end 
 
202
      else if button = 3 then begin
 
203
        let submenu = popup_factory#add_submenu "Slicing" in
 
204
        let slicing_factory = new GMenu.factory submenu in
 
205
          (* definitions for slicing plug-in *)        
 
206
        let add_slicing_item name = add_item slicing_factory name in
 
207
        let mk_slice = gui_mk_slice main_ui in
 
208
        let add_slice_menu kf_opt kf_ki_opt =
 
209
          
 
210
          add_slicing_item "Slice calls to"
 
211
            kf_opt
 
212
            ~callback:(fun kf ->
 
213
                         mk_slice
 
214
                           ~info:(fun () -> Cil.fprintf_to_string "Request for slicing effects of function %a"
 
215
                                    Kernel_function.pretty_name kf)
 
216
                           ((mk_selection_all !Db.Slicing.Select.select_func_calls_to) kf));
 
217
          add_slicing_item "Slice calls into"
 
218
            kf_opt
 
219
            ~callback:(fun kf -> 
 
220
                         mk_slice
 
221
                           ~info:(fun () -> Cil.fprintf_to_string "Request for slicing entrance into function %a"
 
222
                                    Kernel_function.pretty_name kf)
 
223
                           ((mk_selection_all !Db.Slicing.Select.select_func_calls_into) kf));
 
224
          add_slicing_item "Slice result"
 
225
            (Extlib.opt_filter (fun kf ->
 
226
                                  let is_not_void_kf x =
 
227
                                    match x.Cil_types.vtype with
 
228
                                      | Cil_types.TFun (Cil_types.TVoid (_),_,_,_) -> false
 
229
                                      | _ -> true
 
230
                                  in is_not_void_kf (Kernel_function.get_vi kf))
 
231
               kf_opt)
 
232
            ~callback:(fun kf ->
 
233
                         mk_slice
 
234
                           ~info:(fun () -> Cil.fprintf_to_string "Request for returned value of function %a"
 
235
                                    Kernel_function.pretty_name kf)
 
236
                           ((mk_selection_all !Db.Slicing.Select.select_func_return) kf));
 
237
          add_slicing_item "Slice stmt"
 
238
            kf_ki_opt
 
239
            ~callback:(fun (kf, ki) ->
 
240
                         mk_slice
 
241
                           ~info:(fun () -> Cil.fprintf_to_string "Request for slicing effects of statement %d"
 
242
                                    ki.sid)
 
243
                           ((mk_selection_all !Db.Slicing.Select.select_stmt) ki kf));
 
244
          add_slicing_item "Slice lval"
 
245
            kf_ki_opt
 
246
            ~callback:(fun (kf, ki) ->
 
247
                         let do_with_txt txt =
 
248
                           try
 
249
                             let lval_str = Cilutil.StringSet.add txt Cilutil.StringSet.empty in
 
250
                               mk_slice
 
251
                                 ~info:(fun () -> Cil.fprintf_to_string "Request for slicing Lvalue %s before statement %d"
 
252
                                          txt
 
253
                                          ki.sid)
 
254
                                 ((mk_selection_cad !Db.Slicing.Select.select_stmt_lval)
 
255
                                    lval_str ~before:true ki ~scope:ki ~eval:ki kf)
 
256
                           with e -> main_ui#error "Invalid expression: %s" (Printexc.to_string e)
 
257
                         in
 
258
                         let txt =
 
259
                           GToolbox.input_string
 
260
                             ~title:"Input a pure Lvalue expression to slice before current statement"
 
261
                             ""
 
262
                         in Extlib.may do_with_txt txt);
 
263
          add_slicing_item "Slice rd"
 
264
            kf_ki_opt
 
265
            ~callback:(fun (kf, ki) ->
 
266
                         let do_with_txt txt =
 
267
                           try
 
268
                             let lval_str = Cilutil.StringSet.add txt Cilutil.StringSet.empty in
 
269
                               mk_slice
 
270
                                 ~info:(fun () -> Cil.fprintf_to_string "Request for slicing read accesses to Lvalue %s"
 
271
                                          txt)
 
272
                                 ((mk_selection_cad !Db.Slicing.Select.select_func_lval_rw)
 
273
                                    ~rd:lval_str ~wr:Cilutil.StringSet.empty ~scope:ki ~eval:ki kf)
 
274
                           with e -> main_ui#error "Invalid expression: %s" (Printexc.to_string e)
 
275
                         in
 
276
                         let txt =
 
277
                           GToolbox.input_string
 
278
                             ~title:"Input a pure Lvalue expression to slice read accesses"
 
279
                             ""
 
280
                         in Extlib.may do_with_txt txt);
 
281
          add_slicing_item "Slice wr"
 
282
            kf_ki_opt
 
283
            ~callback:(fun (kf, ki) ->
 
284
                         let do_with_txt txt =
 
285
                           try
 
286
                             let lval_str = Cilutil.StringSet.add txt Cilutil.StringSet.empty in
 
287
                               mk_slice
 
288
                                 ~info:(fun () -> Cil.fprintf_to_string "Request for slicing writen accesses to Lvalue %s"
 
289
                                          txt)
 
290
                                 ((mk_selection_cad !Db.Slicing.Select.select_func_lval_rw)
 
291
                                    ~rd:Cilutil.StringSet.empty ~wr:lval_str ~scope:ki ~eval:ki kf)
 
292
                           with e -> main_ui#error "Invalid expression: %s" (Printexc.to_string e)
 
293
                         in
 
294
                         let txt =
 
295
                           GToolbox.input_string
 
296
                             ~title:"Input a pure Lvalue expression to slice read accesses"
 
297
                             ""
 
298
                         in Extlib.may do_with_txt txt);
 
299
          add_slicing_item "Slice ctrl"
 
300
            kf_ki_opt
 
301
            ~callback:(fun (kf, ki) ->
 
302
                         mk_slice
 
303
                           ~info:(fun () -> Cil.fprintf_to_string "Request for slicing accessibility to statement %d"
 
304
                                    ki.sid)
 
305
                           ((mk_selection_all !Db.Slicing.Select.select_stmt_ctrl) ki kf))
 
306
        in
 
307
        let some_kf_from_vi vi = 
 
308
          try let kf = Globals.Functions.get vi in
 
309
            if (get_enabled ())
 
310
              && (!Db.Value.is_called kf) then Some kf else None
 
311
          with Not_found -> None in
 
312
        let some_kf_from_lv  lv = 
 
313
          match lv with
 
314
            | Var vi,_ -> some_kf_from_vi vi
 
315
            | _ -> None in
 
316
        let some_kf_ki kf ki = 
 
317
          if (get_enabled ())
 
318
            && (!Db.Value.is_called kf)
 
319
            && (Db.Value.is_accessible (Cil_types.Kstmt ki))
 
320
          then Some (kf, ki) else None in
 
321
          begin  (* add menu for slicing and scope plug-in *)
 
322
            match localizable with
 
323
              | Pretty_source.PLval (Some kf,(Kstmt stmt),lv) ->
 
324
                  add_slice_menu (some_kf_from_lv lv) (some_kf_ki kf stmt)
 
325
              | Pretty_source.PTermLval(Some kf,(Kstmt ki),_) (* as for the statement *)
 
326
              | Pretty_source.PStmt (kf,ki) ->
 
327
                  add_slice_menu None (some_kf_ki kf ki)
 
328
              | Pretty_source.PVDecl (_,vi) ->
 
329
                  add_slice_menu (some_kf_from_vi vi) None
 
330
              | _  ->
 
331
                  add_slice_menu None None
 
332
          end;
 
333
          let projects = !Db.Slicing.Project.get_all() in
 
334
            ignore (slicing_factory#add_separator ());
 
335
            add_slicing_item "_Disable"
 
336
              (Some ())
 
337
              ~callback:(fun () -> gui_toggle_enabled main_ui);
 
338
            add_slicing_item "_Clear"
 
339
              (if slicing_project = None then None else Some ())
 
340
              ~callback:(fun () -> gui_set_project main_ui None) ;
 
341
            List.iter
 
342
              (fun proj ->
 
343
                 let add_highlight_menu sensitive =
 
344
                   add_slicing_item
 
345
                     ("Highlight " ^ (Pretty_utils.escape_underscores (!Db.Slicing.Project.get_name proj)))
 
346
                     sensitive
 
347
                     ~callback:(fun () -> gui_set_project main_ui (Some proj))
 
348
                 in match slicing_project with
 
349
                   | Some project -> add_highlight_menu (if (proj == project) then None else Some ())
 
350
                   | None -> add_highlight_menu (Some()))
 
351
              projects;
 
352
      end
 
353
        
 
354
let slicing_highlighter 
 
355
    (buffer:GSourceView.source_buffer) localizable ~start ~stop =
 
356
  if (get_enabled ()) then begin
 
357
    (* Definition for highlight 'Slicing' *)
 
358
    let highlight project =
 
359
      let ki = match localizable with 
 
360
        | Pretty_source.PStmt (_,stmt) -> Kstmt stmt
 
361
        | Pretty_source.PLval (_,ki,_) | Pretty_source.PTermLval(_,ki,_) -> ki
 
362
        | Pretty_source.PVDecl _ -> Kglobal
 
363
      in
 
364
      if Db.Value.is_accessible ki then 
 
365
        let unused_code_area = 
 
366
          Gtk_helper.make_tag buffer ~name:"slicing_unused" [`STRIKETHROUGH true ] in
 
367
        let spare_code_area = 
 
368
          Gtk_helper.make_tag buffer ~name:"slicing_spare" [`UNDERLINE `LOW] in
 
369
        let necessary_code_area = 
 
370
          Gtk_helper.make_tag buffer ~name:"slicing_necessary" [`BACKGROUND "green"] in
 
371
        let apply_on_one_project_and_merge_slices kf pb pe mark_of_slice =
 
372
          let apply_mark mark =
 
373
            if Cmdline.Debug.get () > 0 then
 
374
              Format.printf "Got mark: %a@." !Db.Slicing.Mark.pretty mark;
 
375
            if !Db.Slicing.Mark.is_bottom mark then
 
376
              Gtk_helper.apply_tag buffer unused_code_area pb pe;
 
377
            if !Db.Slicing.Mark.is_spare mark then
 
378
              Gtk_helper.apply_tag buffer spare_code_area pb pe;
 
379
            if (!Db.Slicing.Mark.is_ctrl mark
 
380
                || !Db.Slicing.Mark.is_data mark
 
381
                || !Db.Slicing.Mark.is_addr mark)
 
382
            then
 
383
              Gtk_helper.apply_tag buffer necessary_code_area pb pe
 
384
          in
 
385
          let slices = !Db.Slicing.Slice.get_all project kf in
 
386
          begin
 
387
            match slices with
 
388
            | [] ->
 
389
                (* No slice for this kf *)
 
390
                if !Db.Slicing.Project.is_called project kf
 
391
                then begin
 
392
                  if Cmdline.Debug.get () > 0 then 
 
393
                    Format.printf "Got source code@." ;
 
394
                  apply_mark (!Db.Slicing.Mark.get_from_src_func project kf)
 
395
                end
 
396
                else
 
397
                  Gtk_helper.apply_tag buffer unused_code_area pb pe
 
398
            | slices ->
 
399
                if !Db.Slicing.Project.is_called project kf
 
400
                then begin
 
401
                  assert (not (kf == fst (Globals.entry_point ()))) ;
 
402
                  if Cmdline.Debug.get () > 0 then 
 
403
                    Format.printf "Got source code@." ;
 
404
                  apply_mark (!Db.Slicing.Mark.get_from_src_func project kf)
 
405
                end ;
 
406
                if Cmdline.Debug.get () > 0 then begin
 
407
                  let l = List.length slices in
 
408
                  if l >=2 then
 
409
                    Format.printf "Got %d slices@."
 
410
                      (List.length slices)
 
411
                end;
 
412
                let mark_slice slice =
 
413
                  let mark = mark_of_slice project slice in
 
414
                  apply_mark mark
 
415
                in List.iter mark_slice slices
 
416
          end
 
417
        in
 
418
        let tag_stmt kf stmt pb pe =
 
419
          assert (Db.Value.is_accessible (Kstmt stmt)) ;
 
420
          apply_on_one_project_and_merge_slices
 
421
            kf
 
422
            pb
 
423
            pe
 
424
            (fun _ slice -> !Db.Slicing.Slice.get_mark_from_stmt slice stmt)
 
425
        in
 
426
        let tag_vdecl kf vi pb pe =
 
427
          if not vi.vglob then
 
428
            apply_on_one_project_and_merge_slices
 
429
              kf
 
430
              pb
 
431
              pe
 
432
              (fun _ slice -> !Db.Slicing.Slice.get_mark_from_local_var slice vi)
 
433
        in
 
434
        match localizable with 
 
435
        | Pretty_source.PStmt (kf,stmt) -> tag_stmt kf stmt start stop
 
436
        | Pretty_source.PVDecl (Some kf,vi) -> tag_vdecl kf vi start stop 
 
437
        | Pretty_source.PVDecl (None,_)
 
438
        | Pretty_source.PLval _
 
439
        | Pretty_source.PTermLval _ -> ()
 
440
    in 
 
441
    let slicing_project = !Db.Slicing.Project.get_project () in
 
442
    (* 2. Highlights the 'Slicing' *)
 
443
    Extlib.may highlight slicing_project         
 
444
  end
 
445
 
 
446
let none_text = "<i>None</i>"
 
447
  
 
448
let refresh_combo_box ((combo_box, (model, _column)) as combo_box_text) slicing_project sensitive =
 
449
  model#clear () ;
 
450
  GEdit.text_combo_add combo_box_text none_text;
 
451
  let offset_elts = 1 in (* offset for the entry "None" *)
 
452
  let nb_combo_elts = model#iter_n_children None in
 
453
  let projects = !Db.Slicing.Project.get_all() in
 
454
  let i = ref offset_elts in
 
455
  let nth_proj = ref 0 in
 
456
    List.iter (fun proj ->
 
457
                 Extlib.may (fun slicing_proj ->
 
458
                               if (proj == slicing_proj) then  nth_proj := !i;)
 
459
                   slicing_project;
 
460
                 if (!i >= nb_combo_elts)
 
461
                 then (* add new entry into the [combo_box] *)
 
462
                   GEdit.text_combo_add combo_box_text (!Db.Slicing.Project.get_name proj) ;
 
463
                 i := !i + 1 ;
 
464
              )
 
465
      projects;
 
466
    (* activate the entry of the [combo_box] relative to the [slicing_project]  *)
 
467
    combo_box#set_active !nth_proj ;
 
468
    combo_box#misc#set_sensitive sensitive
 
469
 
 
470
    
 
471
let slicing_panel main_ui =
 
472
  let unsensitive_pressed_button (button:GButton.button) callback =
 
473
    ignore (button#connect#pressed (fun () -> button #misc#set_sensitive false ; callback ())) in
 
474
  let refreshing = ref false (* to forbide flashes while refresh actions *) in
 
475
  let w = GPack.vbox  () in
 
476
  let hbox1 = GPack.hbox
 
477
    ~packing:w#pack () in
 
478
  let activate_button = GButton.button ~label:"Activate"
 
479
    ~packing:hbox1#pack () in
 
480
  let ((combo_box, (_model, column)) as combo_box_text) =
 
481
    GEdit.combo_box_text ~strings:[ none_text ] ~wrap_width:3 ~use_markup:true
 
482
      ~packing:(hbox1#pack ~expand:true ~fill:true) () in
 
483
  let hbox2 = GPack.hbox ~packing:w#pack () in
 
484
    (* [enabled_button] to give slicing menu available *)    
 
485
  let enabled_button =
 
486
    GButton.check_button 
 
487
      ~label:"Enable"
 
488
      ~active:(get_enabled ())
 
489
      ~packing:(hbox2#pack ~expand:true ~fill:true) () in
 
490
  let _verbose_text = GMisc.label ~xalign:0.0 ~text:"Verbose: " 
 
491
    ~packing:(hbox2#pack ~expand:false) () in
 
492
  let verbose_decr =
 
493
    GButton.button 
 
494
      ~label:"-"
 
495
      ~packing:hbox2#pack () in
 
496
  let verbose_box = GMisc.label ~xalign:0.0 ~text:(string_of_int (Cmdline.Slicing.Mode.Verbose.get ()))
 
497
    ~packing:hbox2#pack () in
 
498
  let verbose_incr =
 
499
    GButton.button 
 
500
      ~label:"+" 
 
501
      ~packing:hbox2#pack () in
 
502
  let hbox3 = GPack.hbox ~packing:w#pack () in
 
503
    (* [slice_undef_button] related to -slice-undef option *)    
 
504
  let slice_undef_button =
 
505
    GButton.check_button 
 
506
      ~label:"Libraries"
 
507
      ~active:(get_enabled ())
 
508
      ~packing:(hbox3#pack ~expand:true ~fill:true) () in
 
509
  let _level_text = GMisc.label ~xalign:0.0 ~text:"Level: " 
 
510
    ~packing:(hbox3#pack ~expand:false) () in
 
511
  let level_decr =
 
512
    GButton.button 
 
513
      ~label:"-"
 
514
      ~packing:hbox3#pack () in
 
515
  let level_box =
 
516
    GMisc.label ~xalign:0.0 ~text:(string_of_int (Cmdline.Slicing.Mode.Calls.get ()))
 
517
      ~packing:hbox3#pack () in
 
518
  let level_incr =
 
519
    GButton.button 
 
520
      ~label:"+" 
 
521
      ~packing:hbox3#pack () in
 
522
    combo_box#set_active 0 ;
 
523
    ignore (combo_box#connect#changed
 
524
              (fun () -> if not !refreshing then
 
525
                 match combo_box#active_iter with
 
526
                   | None -> ()
 
527
                   | Some row -> 
 
528
                       let slicing_project_name =
 
529
                         (* get the text entry related to the current slicing project *)
 
530
                         Extlib.may_map !Db.Slicing.Project.get_name ~dft:none_text (!Db.Slicing.Project.get_project ())
 
531
                       and selected_name = combo_box#model#get ~row ~column in
 
532
                         if (selected_name != slicing_project_name) then
 
533
                           let proj_opt =
 
534
                             try Some (List.find (fun proj -> selected_name = !Db.Slicing.Project.get_name proj) (!Db.Slicing.Project.get_all ()))
 
535
                             with Not_found -> None
 
536
                           in
 
537
                             gui_set_project main_ui proj_opt));
 
538
    ignore (activate_button#connect#pressed
 
539
              (fun () -> gui_compute_values main_ui ));
 
540
    ignore (enabled_button#connect#toggled 
 
541
              ~callback:
 
542
              (fun () -> (* can be called by the refresh *)
 
543
                 if (not !refreshing) then
 
544
                   gui_toggle_enabled main_ui ;));
 
545
    ignore (slice_undef_button#connect#toggled 
 
546
              ~callback:
 
547
              (fun () -> (* can be called by the refresh *)
 
548
                 if (not !refreshing) then
 
549
                   gui_toggle_slice_undef main_ui ;));
 
550
    (* Some buttons have to be instantatly unsensitive when pressed,
 
551
       otherwise, when they are pressed twice quickly, global invariants can be broken.
 
552
       Their sensitivity will be updated by the [refresh] function. *)
 
553
    unsensitive_pressed_button verbose_incr (fun () -> gui_incr_verbose main_ui 1);
 
554
    unsensitive_pressed_button verbose_decr (fun () -> gui_incr_verbose main_ui (-1));
 
555
    unsensitive_pressed_button level_incr (fun () -> gui_incr_level main_ui 1);
 
556
    unsensitive_pressed_button level_decr (fun () -> gui_incr_level main_ui (-1));
 
557
    let refresh () =
 
558
      let verbose = Cmdline.Slicing.Mode.Verbose.get () in
 
559
      let level = Cmdline.Slicing.Mode.Calls.get () in
 
560
      let value_is_computed = Db.Value.is_computed () in
 
561
      let slicing_project = !Db.Slicing.Project.get_project () in
 
562
      let enabled = get_enabled () in
 
563
        verbose_decr#misc#set_sensitive (verbose > 0) ;
 
564
        verbose_incr#misc#set_sensitive (verbose < 2) ;
 
565
        verbose_box#set_label (string_of_int verbose) ;
 
566
        
 
567
        level_decr#misc#set_sensitive (level > 0) ;
 
568
        level_incr#misc#set_sensitive (level < 3) ;
 
569
        level_box#set_label (string_of_int level) ;
 
570
        
 
571
        activate_button#misc#set_sensitive (not value_is_computed) ;
 
572
        
 
573
        enabled_button#misc#set_sensitive value_is_computed ;
 
574
        
 
575
        slice_undef_button#misc#set_sensitive enabled ;
 
576
        
 
577
        (* to forbide flashes while refresh actions
 
578
           execute the related callback using [!refreshing] *)
 
579
        refreshing := true ;
 
580
        enabled_button#set_active enabled ;
 
581
        slice_undef_button#set_active (Cmdline.Slicing.Mode.SliceUndef.get ()) ;
 
582
        ignore (refresh_combo_box combo_box_text slicing_project (enabled && value_is_computed)) ;
 
583
        refreshing := false ;
 
584
    in refresh () ;
 
585
      "Slicing",w#coerce,Some refresh
 
586
        
 
587
let file_tree_decorate (file_tree:Filetree.t) = 
 
588
  file_tree#append_pixbuf_column 
 
589
    "Slicing"  
 
590
    (fun globs -> 
 
591
       Extlib.may_map
 
592
         (fun project ->
 
593
            if (List.exists
 
594
                  (fun glob -> match glob with 
 
595
                     | GFun ({svar = vi},_ ) ->
 
596
                         begin
 
597
                           try
 
598
                             let kf = Globals.Functions.get vi
 
599
                             in (!Db.Slicing.Project.is_called project kf)
 
600
                                || ( [] != (!Db.Slicing.Slice.get_all project kf))
 
601
                           with Not_found -> false
 
602
                         end
 
603
                     |  _ -> false) 
 
604
                  globs) then
 
605
              [`STOCK_ID "gtk-yes"]
 
606
            else
 
607
              [`STOCK_ID ""])
 
608
         ~dft:[`STOCK_ID ""]
 
609
         (!Db.Slicing.Project.get_project ()))
 
610
 
 
611
let main (main_ui:Design.main_window_extension_points) =
 
612
  main_ui#register_source_selector slicing_selector;
 
613
  main_ui#register_source_highlighter slicing_highlighter;
 
614
  main_ui#register_panel slicing_panel;
 
615
  file_tree_decorate main_ui#file_tree
 
616
 
 
617
let () = Design.register_extension main
 
618
 
 
619
(*
 
620
Local Variables:
 
621
compile-command: "LC_ALL=C make -C ../.. -j"
 
622
End:
 
623
*)
 
624
 
 
625