Newer
Older
(**************************************************************************)
(* *)
(* This file is part of Frama-Clang *)
(* *)
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
(* CEA (Commissariat à l'énergie atomique et aux énergies *)
(* alternatives) *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License as published by the Free Software *)
(* Foundation, version 2.1. *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)
(* GNU Lesser General Public License for more details. *)
(* *)
(* See the GNU Lesser General Public License version 2.1 *)
(* for more details (enclosed in the file LICENSE). *)
(* *)
(**************************************************************************)
open Intermediate_format
type aggregate_info =
{ fields: (string * qual_type) list;
has_virtual: bool;
default_constructor: (qualified_name * signature) option;
default_constructor_base: (qualified_name * signature) option;
copy_constructor: (qualified_name * signature) option;
copy_constructor_base: (qualified_name * signature) option;
move_constructor: (qualified_name * signature) option;
move_constructor_base: (qualified_name * signature) option;
assign_operator: (qualified_name * signature) option;
assign_operator_base: (qualified_name * signature) option;
move_operator: (qualified_name * signature) option;
move_operator_base: (qualified_name * signature) option;
destructor: bool;
destructor_base: bool;
}
type env =
{ namespace: qualification list list;
location: Cabs.cabsloc;
local_vars: typ Datatype.String.Map.t;
captured_vars: bool Datatype.String.Map.t list;
global_vars: (bool * typ) Fclang_datatype.Qualified_name.Map.t;
is_extern_c: bool;
is_ghost: bool;
current_func_name: qualified_name;
current_return_type: typ;
current_class: Fclang_datatype.Qualified_name.t list;
typedefs: qual_type Fclang_datatype.Qualified_name.Map.t;
structs: aggregate_info Fclang_datatype.Qualified_name.Map.t;
aggregate_kind: (ckind * bool) Fclang_datatype.Qualified_name.Map.t;
c_globals: (bool * Cabs.definition) list;
}
let empty_aggregate_info =
{ fields = [];
default_constructor = None; default_constructor_base = None;
copy_constructor = None; copy_constructor_base = None;
has_virtual = false;
move_constructor = None; move_constructor_base = None;
move_operator = None; move_operator_base = None;
assign_operator = None; assign_operator_base = None;
destructor = false; destructor_base = false;
}
let empty_func_name =
{ prequalification = []; decl_name = "#### Not in a function ####" }
let empty_return_type =
Named ({prequalification=[]; decl_name = "###Illegal type" }, true)
let empty_env =
{ namespace = [];
location = Cil_datatype.Location.unknown;
local_vars = Datatype.String.Map.empty;
captured_vars = [];
global_vars = Fclang_datatype.Qualified_name.Map.empty;
is_extern_c = false;
is_ghost = false;
current_func_name = empty_func_name;
current_return_type = empty_return_type;
typedefs = Fclang_datatype.Qualified_name.Map.empty;
structs = Fclang_datatype.Qualified_name.Map.empty;
aggregate_kind = Fclang_datatype.Qualified_name.Map.empty;
current_class = [];
c_globals = [];
}
let add_c_global env def =
{ env with c_globals = (env.is_ghost, def) :: env.c_globals }
let get_c_globals env = List.rev env.c_globals
let fatal env msg =
let source = fst env.location in
Frama_Clang_option.fatal ~source msg
let get_namespace { namespace } =
match namespace with [] -> [] | inner :: _ -> inner
let add_namespace env n =
let inner_namespace = get_namespace env @ [n] in
{ env with namespace = inner_namespace :: env.namespace }
let set_namespace env n =
{ env with namespace = n.prequalification :: env.namespace }
let set_namespace_from_class env (n,t) =
let inner_namespace =
match t with
| TStandard -> n.prequalification @ [QStructOrClass n.decl_name]
| TTemplateInstance l ->
n.prequalification @ [QTemplateInstance (n.decl_name,l)]
in
{ env with namespace = inner_namespace :: env.namespace }
let reset_namespace env =
match env.namespace with [] -> env | _ :: namespace -> { env with namespace }
let add_local_var env v t =
{ env with
local_vars = Datatype.String.Map.add v t env.local_vars }
let unscope env previous = { env with local_vars = previous.local_vars }
let add_formal_parameters env args =
List.fold_left
(fun env arg -> add_local_var env arg.arg_name arg.arg_type.plain_type)
env args
let add_global_var env v t =
(* Format.printf "add global var %a\n" Fclang_datatype.Qualified_name.pretty (v, TStandard); *)
{ env with
global_vars =
Fclang_datatype.Qualified_name.Map.add
(v,TStandard) (env.is_extern_c,t) env.global_vars }
let get_local_var env v =
try
Datatype.String.Map.find v env.local_vars
with Not_found ->
fatal env "Unknown local variable %s" v
let get_global_var env v =
try
Fclang_datatype.Qualified_name.Map.find (v,TStandard) env.global_vars
with Not_found ->
fatal env "Unknown global variable %a"
Fclang_datatype.Qualified_name.pretty (v,TStandard)
let temp_name env s =
let rec aux i =
let name = s ^ "_" ^ string_of_int i in
if Datatype.String.Map.mem name env.local_vars then aux (i+1) else name
in
if Datatype.String.Map.mem s env.local_vars then aux 0 else s
let set_loc env loc =
let loc = Cil_datatype.Location.of_lexing_loc loc in
Cil.CurrentLoc.set loc; { env with location = loc }
let get_loc env = env.location
let get_clang_loc env = Cil_datatype.Location.to_lexing_loc env.location
let set_extern_c env flag = { env with is_extern_c = flag }
let is_extern_c env = env.is_extern_c
let set_ghost env flag = { env with is_ghost = flag }
let is_ghost env = env.is_ghost
let qualify env n =
let prequalification = get_namespace env in
{ prequalification; decl_name = n }
let get_current_class env =
match env.current_class with [] -> None | hd :: _ -> Some hd
let set_current_class env c =
let env = set_namespace_from_class env c in
{ env with current_class = c :: env.current_class }
let reset_current_class env =
let current_class =
match env.current_class with [] -> [] | _ :: tl -> tl
in
reset_namespace { env with current_class }
let class_name_from_qualifications env l =
let rec aux acc l =
match l with
| [] -> None
| [QStructOrClass n]
-> Some ({ prequalification = List.rev acc; decl_name = n }, TStandard)
| [ QNamespace _ ] -> None
| [ QTemplateInstance(n,tl) ] ->
let name =
({ prequalification = List.rev acc; decl_name = n },
TTemplateInstance tl)
in
if Fclang_datatype.Qualified_name.Map.mem name env.aggregate_kind
then Some name
else None
| a :: l -> aux (a::acc) l
in aux [] l
let set_class_from_qual env name =
match name.prequalification with
| [] -> env
| l ->
(match class_name_from_qualifications env l with
| None -> set_namespace env name
| Some class_name -> set_current_class env class_name)
let reset_class_from_qual env name =
match name.prequalification with
| [] -> env
| l ->
(match class_name_from_qualifications env l with
| None -> reset_namespace env
| Some _ -> reset_current_class env)
let set_current_func_name env name =
let env = { env with current_func_name = name } in
set_class_from_qual env name
let reset_func env =
let new_env =
{ env with
current_func_name = empty_func_name;
current_return_type = empty_return_type }
in
reset_class_from_qual new_env env.current_func_name
let get_current_func_name env = env.current_func_name.decl_name
let set_current_return_type env typ =
{ env with current_return_type = typ }
let get_current_return_type env = env.current_return_type
let add_typedef env name qtype =
{ env with typedefs =
Fclang_datatype.Qualified_name.Map.add (name,TStandard) qtype env.typedefs}
let get_typedef env name =
try
Fclang_datatype.Qualified_name.Map.find (name,TStandard) env.typedefs
with Not_found ->
fatal env "Unknown typedef %a"
Fclang_datatype.Qualified_name.pretty (name,TStandard)
let has_typedef env name =
Fclang_datatype.Qualified_name.Map.mem (name, TStandard) env.typedefs
let rec template_parameter_normalize env tparam = match tparam with
| TPStructOrClass name -> TPStructOrClass
{ name with prequalification
= qualification_list_normalize env name.prequalification }
| TPTypename qtype -> TPTypename (qual_type_normalize env qtype)
| TPConstant _ -> tparam
| TPDeclaration name -> TPDeclaration
{ name with prequalification
= qualification_list_normalize env name.prequalification }
and qualification_normalize env qual = match qual with
| QTemplateInstance (name, params)
-> QTemplateInstance(name, List.map (template_parameter_normalize env) params)
| _ -> qual
and qualification_list_normalize env lqual = match lqual with
| [] -> []
| qual::lqual ->
(qualification_normalize env qual)
:: (qualification_list_normalize env lqual)
and tkind_normalize env tk = match tk with
| TStandard -> tk
| TTemplateInstance ltparams
-> TTemplateInstance (List.map (template_parameter_normalize env) ltparams)
and signature_normalize env sign =
{ result = qual_type_normalize env sign.result;
parameter = qual_type_list_normalize env sign.parameter;
variadic = sign.variadic
}
and pkind_normalize env pk = match pk with
| PDataPointer qtype -> PDataPointer (qual_type_normalize env qtype)
| PFunctionPointer sign -> PFunctionPointer (signature_normalize env sign)
| PStandardMethodPointer (decl, shift)
-> PStandardMethodPointer (signature_normalize env decl, shift)
| PVirtualMethodPointer (decl, index, shift)
-> PVirtualMethodPointer (signature_normalize env decl, index, shift)
and qual_type_normalize env qtype = match qtype.plain_type with
| Pointer kind
-> { qtype with plain_type = Pointer (pkind_normalize env kind) }
| LVReference kind ->
{ qtype with plain_type = LVReference (pkind_normalize env kind) }
| RVReference kind ->
{ qtype with plain_type = RVReference (pkind_normalize env kind) }
| Array kind -> { qtype with plain_type = Array
{ kind with subtype = qual_type_normalize env kind.subtype } }
| Struct (body, tk) -> { qtype with plain_type
= Struct({ body with prequalification
= qualification_list_normalize env body.prequalification },
tkind_normalize env tk) }
| Union (body, tk) -> { qtype with plain_type
= Union({ body with prequalification
= qualification_list_normalize env body.prequalification },
tkind_normalize env tk) }
| Named (qname,is_extern_c) ->
begin
try
let def =
Fclang_datatype.Qualified_name.Map.find (qname,TStandard) env.typedefs
in
let qtype = Cxx_utils.add_qualifiers qtype.qualifier def in
qual_type_normalize env qtype
with Not_found ->
{ qtype with plain_type = Named
({ qname with prequalification
= qualification_list_normalize env qname.prequalification },
is_extern_c) }
end
| _ -> qtype
and qual_type_list_normalize env ltype = match ltype with
| [] -> []
| qtype::ltype ->
(qual_type_normalize env qtype)
:: (qual_type_list_normalize env ltype)
let typedef_normalize env name tk =
{ name with prequalification
= qualification_list_normalize env name.prequalification },
(tkind_normalize env tk)
let add_struct env (name,t) fields =
let info =
try
Fclang_datatype.Qualified_name.Map.find (name,t) env.structs
with Not_found -> empty_aggregate_info
in
let info = { info with fields = fields } in
{ env with structs =
Fclang_datatype.Qualified_name.Map.add (name,t) info env.structs
}
let virtual_struct env (name, t) =
let info =
try
Fclang_datatype.Qualified_name.Map.find (name, t) env.structs
with Not_found -> empty_aggregate_info
in
let info = { info with has_virtual = true } in
{ env with
structs = Fclang_datatype.Qualified_name.Map.add (name, t) info env.structs}
let get_struct env (name,t) =
try
(Fclang_datatype.Qualified_name.Map.find (name,t) env.structs).fields
with Not_found ->
fatal env "Unknown struct %a"
Fclang_datatype.Qualified_name.pretty (name,t)
let struct_has_virtual env full_name =
try
(Fclang_datatype.Qualified_name.Map.find full_name env.structs).has_virtual
with Not_found ->
fatal env "Unknown struct %a"
Fclang_datatype.Qualified_name.pretty full_name
let aggregate_info err env name =
try
Fclang_datatype.Qualified_name.Map.find name env.structs
with Not_found ->
if err then
fatal env "Unknown aggregate_type %a"
Fclang_datatype.Qualified_name.pretty name
else empty_aggregate_info
let force_class_name env quals =
match class_name_from_qualifications env quals with
| None ->
Frama_Clang_option.fatal
"this function must be called inside the scope of a class"
| Some name -> name
let add_default_constructor env name signature =
let full_name = force_class_name env name.prequalification in
let info = aggregate_info false env full_name in
let info =
match info.default_constructor with
| None -> { info with default_constructor = Some (name,signature) }
| Some _ -> info
in
{ env with
structs =
Fclang_datatype.Qualified_name.Map.add full_name info env.structs }
let add_default_constructor_base env name signature =
let full_name = force_class_name env name.prequalification in
let info = aggregate_info false env full_name in
let info =
match info.default_constructor_base with
| None -> { info with default_constructor_base = Some (name,signature) }
| Some _ -> info
in
{ env with
structs =
Fclang_datatype.Qualified_name.Map.add full_name info env.structs }
let get_option_default_constructor env name =
let info = aggregate_info true env name in info.default_constructor
let get_option_default_constructor_base env name =
let info = aggregate_info true env name in info.default_constructor_base
let get_default_constructor env name =
match get_option_default_constructor env name with
| None ->
fatal env "No usable default constructor for %a"
Fclang_datatype.Qualified_name.pretty name
| Some cons -> cons
let add_copy_constructor env name signature =
let full_name = force_class_name env name.prequalification in
let info = aggregate_info false env full_name in
let info =
match info.copy_constructor with
| None -> { info with copy_constructor = Some (name,signature) }
| Some _ -> info
in
{ env
with structs =
Fclang_datatype.Qualified_name.Map.add full_name info env.structs }
let add_copy_constructor_base env name signature =
let full_name = force_class_name env name.prequalification in
let info = aggregate_info false env full_name in
let info =
match info.copy_constructor_base with
| None -> { info with copy_constructor_base = Some (name,signature) }
| Some _ -> info
in
{ env
with structs =
Fclang_datatype.Qualified_name.Map.add full_name info env.structs }
let get_option_copy_constructor env name =
let info = aggregate_info true env name in info.copy_constructor
let get_option_copy_constructor_base env name =
let info = aggregate_info true env name in info.copy_constructor_base
let get_copy_constructor env name =
match get_option_copy_constructor env name with
| Some c -> c
| None ->
fatal env "No usable copy constructor for %a"
Fclang_datatype.Qualified_name.pretty name
let add_move_constructor env name signature =
let full_name = force_class_name env name.prequalification in
let info = aggregate_info false env full_name in
let info =
match info.move_constructor with
| None -> { info with move_constructor = Some (name,signature) }
| Some _ -> info
in
{ env
with structs =
Fclang_datatype.Qualified_name.Map.add full_name info env.structs }
let add_move_constructor_base env name signature =
let full_name = force_class_name env name.prequalification in
let info = aggregate_info false env full_name in
let info =
match info.move_constructor_base with
| None -> { info with move_constructor_base = Some (name,signature) }
| Some _ -> info
in
{ env
with structs =
Fclang_datatype.Qualified_name.Map.add full_name info env.structs }
let get_option_move_constructor env name =
let info = aggregate_info true env name in info.move_constructor
let get_option_move_constructor_base env name =
let info = aggregate_info true env name in info.move_constructor_base
let get_move_constructor env name =
match get_option_move_constructor env name with
| Some c -> c
| None ->
fatal env "No usable move constructor for %a"
Fclang_datatype.Qualified_name.pretty name
let add_destructor env name =
let full_name = force_class_name env name in
let info = aggregate_info false env full_name in
let info =
if not(info.destructor) then { info with destructor = true } else info
in
{ env with
structs =
Fclang_datatype.Qualified_name.Map.add full_name info env.structs }
let add_destructor_base env name =
let full_name = force_class_name env name in
let info = aggregate_info false env full_name in
let info =
if not(info.destructor_base) then
{ info with destructor_base = true }
else info
in
{ env with
structs =
Fclang_datatype.Qualified_name.Map.add full_name info env.structs }
let has_destructor env class_name =
let info = aggregate_info true env class_name in info.destructor
let has_destructor_base env class_name =
let info = aggregate_info true env class_name in info.destructor_base
let add_assign_operator env name signature =
let full_name = force_class_name env name.prequalification in
let info = aggregate_info false env full_name in
let info =
match info.assign_operator with
| None -> { info with assign_operator = Some (name,signature) }
| Some _ -> info
in
{ env with
structs =
Fclang_datatype.Qualified_name.Map.add full_name info env.structs }
let add_assign_operator_base env name signature =
let full_name = force_class_name env name.prequalification in
let info = aggregate_info false env full_name in
let info =
match info.assign_operator_base with
| None -> { info with assign_operator_base = Some (name,signature) }
| Some _ -> info
in
{ env with
structs =
Fclang_datatype.Qualified_name.Map.add full_name info env.structs }
let get_option_assign_operator env name =
let info = aggregate_info true env name in info.assign_operator
let get_option_assign_operator_base env name =
let info = aggregate_info true env name in info.assign_operator_base
let get_assign_operator env name =
match get_option_assign_operator env name with
| None ->
fatal env "No usable assign operator for %a"
Fclang_datatype.Qualified_name.pretty name
| Some a -> a
let add_move_operator env name signature =
let full_name = force_class_name env name.prequalification in
let info = aggregate_info false env full_name in
let info =
match info.move_operator with
| None -> { info with move_operator = Some (name,signature) }
| Some _ -> info
in
{ env
with structs =
Fclang_datatype.Qualified_name.Map.add full_name info env.structs }
let add_move_operator_base env name signature =
let full_name = force_class_name env name.prequalification in
let info = aggregate_info false env full_name in
let info =
match info.move_operator_base with
| None -> { info with move_operator_base = Some (name,signature) }
| Some _ -> info
in
{ env
with structs =
Fclang_datatype.Qualified_name.Map.add full_name info env.structs }
let get_option_move_operator env name =
let info = aggregate_info true env name in info.move_operator
let get_option_move_operator_base env name =
let info = aggregate_info true env name in info.move_operator_base
let get_move_operator env name =
match get_option_move_operator env name with
| None ->
fatal env "No usable move operator for %a"
Fclang_datatype.Qualified_name.pretty name
| Some a -> a
let add_aggregate env name kind tc extern_c =
{ env with aggregate_kind =
Fclang_datatype.Qualified_name.Map.add
(name,tc) (kind,extern_c) env.aggregate_kind }
let get_aggregate env (name,t) =
try
Fclang_datatype.Qualified_name.Map.find (name,t) env.aggregate_kind
with Not_found ->
fatal env "Unknown aggregate type %a"
Fclang_datatype.Qualified_name.pretty (name,t)
let struct_or_union env (name,t) =
match fst (get_aggregate env (name,t)) with
| CStruct | CClass -> Struct (name,t)
| CUnion -> Union (name,t)
let is_extern_c_aggregate env name t = snd (get_aggregate env (name,t))
let class_type_from_qualifications env n =
struct_or_union env (force_class_name env n)
let current_struct_or_union env =
fst (get_aggregate env (List.hd env.current_class))
let is_anonymous env =
let (name,_) = List.hd env.current_class in
let name = name.decl_name in
let prefix = "anonymous_" in (* TODO: get this information from clang *)
let prefix_len = String.length prefix in
if String.length name <= prefix_len then false
else
String.sub name 0 prefix_len = prefix
let unroll_typedef env f typ =
let rec aux typ =
match typ with
| Named (ty, _) when Cxx_utils.is_builtin_qual_type ty ->
fatal env "unroll_typedef on a builtin type"
| Named (ty, _) -> aux (get_typedef env ty).plain_type
| _ -> f env typ
in
aux typ
let get_class_name env typ =
let f env = function
| Struct (name,t) -> (name,t)
| _ -> fatal env "type should be a class"
in
unroll_typedef env f typ
let get_class_name_from_pointer env typ =
let f env = function
| Pointer ( PDataPointer { plain_type } ) -> get_class_name env plain_type
| _ -> fatal env "type should be a pointer to a class"
in
unroll_typedef env f typ
let get_class_name_from_reference env typ =
let f env = function
| Struct (name,t) -> (name,t,false)
| LVReference (PDataPointer { plain_type })
| RVReference (PDataPointer { plain_type }) ->
let (name,t) = get_class_name env plain_type in (name,t,true)
| _ -> fatal env "type should be a class"
in
unroll_typedef env f typ
let rec get_struct_name env t =
let aux env = function
| Struct (s,t) -> (s, t)
| Union (s,t) -> (s, t)
| Pointer (PDataPointer t) -> get_struct_name env t.plain_type
| LVReference (PDataPointer t) | RVReference (PDataPointer t) ->
get_struct_name env t.plain_type
| _ -> fatal env "no struct type information for type"
in
unroll_typedef env aux t
let rec get_signature_type env t =
let aux env = function
| Pointer (PDataPointer t) -> get_signature_type env t.plain_type
| LVReference (PDataPointer t)
| RVReference(PDataPointer t) -> get_signature_type env t.plain_type
| Pointer (PFunctionPointer s) -> s
| LVReference (PFunctionPointer s)
| RVReference (PFunctionPointer s) -> s
| Pointer(PStandardMethodPointer _)
| LVReference (PStandardMethodPointer _)
| RVReference (PStandardMethodPointer _) ->
Frama_Clang_option.not_yet_implemented "pointer to member"
| Pointer(PVirtualMethodPointer _)
| LVReference (PVirtualMethodPointer _)
| RVReference (PVirtualMethodPointer _) ->
Frama_Clang_option.not_yet_implemented "pointer to member"
| Array a -> get_signature_type env a.subtype.plain_type
| _ -> fatal env "no function type information for type"
in
unroll_typedef env aux t
let rec get_struct_name_exp env e =
match e with
| Variable (Local n) ->
get_struct_name env (get_local_var env n.decl_name)
| Variable (Global n) ->
get_struct_name env (snd (get_global_var env n))
| Variable (FunctionParameter n) ->
get_struct_name env (get_local_var env n)
| Dereference e -> get_struct_name_exp env e.econtent
| Address e -> get_struct_name_exp env e.econtent
| PointerCast(target,_,_) -> get_struct_name env target.plain_type
| ShiftPointerCast(target,_,_,_) ->
get_struct_name env target.plain_type
| FieldAccess(e,f) ->
let (s, ts) = (get_struct_name_exp env e.econtent) in
let fields = get_struct env (s,ts) in
get_struct_name
env
(snd (List.find (fun (n,_) -> n = f) fields)).plain_type
| Conditional(_,etrue,_) -> get_struct_name_exp env etrue.econtent
| Static_call(_,signature,_,_,_,_) ->
get_struct_name env signature.result.plain_type
| Virtual_call(_,signature,_,_,_,_,_,_) ->
get_struct_name env signature.result.plain_type
| Dynamic_call(_,ptr,_) ->
let signature = get_dynamic_signature env ptr.econtent in
get_struct_name env signature.result.plain_type
| Temporary(_, ctyp, _, _) -> get_struct_name env ctyp.plain_type
| _ -> fatal env "no struct type information for expression"
and get_dynamic_signature env e =
match e with
| Variable (Local n) ->
get_signature_type env (get_local_var env n.decl_name)
| Variable (Global n) ->
get_signature_type env (snd (get_global_var env n))
| Variable (FunctionParameter n) ->
get_signature_type env (get_local_var env n)
| Variable (CodePointer (_,signature,_,_,_)) -> signature
| Assign(_,e) -> get_dynamic_signature env e.econtent
| Unary_operator(UOCastNoEffect t,_) ->
get_signature_type env t.plain_type
| Dereference e -> get_dynamic_signature env e.econtent
| Address e -> get_dynamic_signature env e.econtent
| PointerCast(target,_,_)
-> get_signature_type env target.plain_type
| ShiftPointerCast(target,_,_,_)
-> get_signature_type env target.plain_type
| FieldAccess(e,f)
-> let (s, ts) = (get_struct_name_exp env e.econtent) in
let fields = get_struct env (s,ts) in
get_signature_type env
(snd (List.find (fun (n, _) -> n = f) fields)).plain_type
| ArrayAccess(a,_) -> get_dynamic_signature env a.econtent
| Conditional(_,etrue,_) ->
get_dynamic_signature env etrue.econtent
| Static_call(_, signature,_,_,_,_) ->
get_signature_type env signature.result.plain_type
| Virtual_call(_,signature,_,_,_,_,_,_) ->
get_signature_type env signature.result.plain_type
| Dynamic_call(_,ptr,_) ->
let signature = get_dynamic_signature env ptr.econtent in
get_signature_type env signature.result.plain_type
| Temporary(_, ctyp, _, _) -> get_signature_type env ctyp.plain_type
| LambdaExpr(result, args, _, _) ->
let parameter = List.map (fun x -> x.arg_type) args in
{ result; parameter; variadic = false }
| _ -> fatal env "no function type information for expression"
let add_closure_info env capture =
let current_capture =
List.fold_left
(fun acc cap ->
let cap_name, is_ref =
match cap with
| Cap_id (s, _, is_ref) -> s, is_ref
| Cap_this is_ref -> "this", is_ref
in
Datatype.String.Map.add cap_name is_ref acc)
Datatype.String.Map.empty
capture
in
let captured_vars = current_capture :: env.captured_vars in
{ env with captured_vars }
let closure_var_kind env name =
match env.captured_vars with
| [] -> None
| map :: _ -> Datatype.String.Map.find_opt name map
let reset_closure env =
match env.captured_vars with
| [] -> env
| _::captured_vars -> { env with captured_vars }