Newer
Older
(**************************************************************************)
(* *)
(* This file is part of Frama-Clang *)
(* *)
(* 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
module Inheritance_graph =
Graph.Persistent.Digraph.ConcreteLabeled
(Fclang_datatype.Qualified_name)
(struct
type t = int * access_kind * vkind
let compare = Stdlib.compare
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
let default = (0, Private, VStandard)
end)
module Inheritance_graph_datatype =
Datatype.Make
(struct
include Datatype.Undefined
type t = Inheritance_graph.t
let name = "Inheritance_graph"
let reprs = [ Inheritance_graph.empty ]
let copy = Datatype.identity
let pretty =
let module D = Graph.Graphviz.Dot(
struct
include Inheritance_graph
let graph_attributes _ = []
let default_vertex_attributes _ = []
let vertex_name s =
Pretty_utils.to_string Fclang_datatype.Qualified_name.pretty s
let vertex_attributes _ = []
let get_subgraph _ = None
let default_edge_attributes _ = []
let edge_attributes (_,(o,a,v),_) =
let a = match a with
| Public -> "public"
| Private -> "private"
| Protected -> "protected"
in
let v = match v with
| VVirtual -> ",virtual"
| VStandard -> ""
in
[ `Label (a ^ v ^ "(order: " ^ string_of_int o ^ ")") ]
end
) in
D.fprint_graph
let mem_project = Datatype.never_any_project
end)
module Inheritance_graph_state =
State_builder.Ref
(Inheritance_graph_datatype)
(struct
let name = "FramaClang.Class.Inheritance_graph"
let dependencies = [ Kernel.Files.self ]
let default () = Inheritance_graph.empty
end)
let inheritance_graph_state = Inheritance_graph_state.self
let add_class c =
let g = Inheritance_graph_state.get () in
let g = Inheritance_graph.add_vertex g c
in Inheritance_graph_state.set g
let add_inheritance_relation c b =
let g = Inheritance_graph_state.get () in
let o = Inheritance_graph.out_degree g c + 1 in
let g =
Inheritance_graph.add_edge_e g
(c,(o,b.access,b.is_virtual),(b.base,b.templated_kind))
in
Inheritance_graph_state.set g
let get_bases_list derived =
let g = Inheritance_graph_state.get () in
let create_inheritance ((_, _), (_, access, is_virtual), (base, t)) =
{ base = base; templated_kind = t; access = access;
is_virtual = is_virtual; vmt_position = 0 }
in
let bases =
try
Inheritance_graph.succ_e g derived
with Invalid_argument _ ->
[]
in let bases =
List.sort (fun (_,(o1,_,_),_) (_,(o2,_,_),_) -> compare o1 o2) bases
in
List.map create_inheritance bases
let has_virtual_base_class derived =
let g = Inheritance_graph_state.get () in
let rec has_virtual_base_class_aux derived =
begin
let does_virtual_inherit acc ((_, _), (_, _, is_virtual), (base, t))
= if (acc) then acc
else begin
match (is_virtual) with
| VVirtual -> true
| VStandard -> (has_virtual_base_class_aux (base, t))
end
in let bases =
try
Inheritance_graph.succ_e g derived
with Invalid_argument _ ->
[]
in List.fold_left does_virtual_inherit false bases
end
in has_virtual_base_class_aux derived
let get_virtual_base_classes derived =
let g = Inheritance_graph_state.get () in
let rec get_virtual_base_class_aux derived =
begin
let add_virtual_inherit acc ((_, _), (_, _, is_virtual), (base, t))
= match (is_virtual) with
| VVirtual -> (List.append ((base, t)
:: (get_virtual_base_class_aux (base, t))) acc)
| VStandard -> (List.append
(get_virtual_base_class_aux (base, t)) acc)
in let bases =
try
Inheritance_graph.succ_e g derived
with Invalid_argument _ ->
[]
in List.fold_left add_virtual_inherit [] bases
end
in get_virtual_base_class_aux derived
let dkey = Frama_Clang_option.register_category "inheritance:subtype"
let subtypes base =
Frama_Clang_option.debug ~dkey
"Searching for derived classes of %a"
Fclang_datatype.Qualified_name.pretty base;
let module Op = Graph.Oper.P(Inheritance_graph) in
let module T = Graph.Traverse.Bfs(Inheritance_graph) in
(* the main graph is directed from derived to bases, and we
want to traverse from bases to derived, hence operate on
the mirror of the graph
*)
let rev = Op.mirror (Inheritance_graph_state.get()) in
let res = ref Fclang_datatype.Qualified_name.Set.empty in
let add_elt n =
Frama_Clang_option.debug ~dkey
"Found %a" Fclang_datatype.Qualified_name.pretty n;
if not (Fclang_datatype.Qualified_name.equal n base) then
res := Fclang_datatype.Qualified_name.Set.add n !res
in
T.iter_component add_elt rev base;
!res
let dkey = Frama_Clang_option.register_category "inheritance:mangled"
let class_of_mangled name =
Frama_Clang_option.debug ~dkey "Searching for mangled name %s" name;
let module M =
struct exception Found of Fclang_datatype.Qualified_name.t end
in
try
Inheritance_graph.iter_vertex
(fun qual ->
let mangled = Extlib.uncurry Mangling.mangle qual None in
Frama_Clang_option.debug ~dkey
"Class name: %a; Mangled: %s --> %sfound"
Fclang_datatype.Qualified_name.pretty qual mangled
(if mangled = name then "" else "not ");
if mangled = name then raise (M.Found qual))
(Inheritance_graph_state.get());
None
(* if this is not the name of a known C++ class, it has no derived class. *)
with M.Found base -> Some base
(* NB: is it really useful to maintain a cache of
the possible inheritance paths? *)
module Inheritance_paths =
State_builder.Hashtbl
(Fclang_datatype.Qualified_name.Hashtbl)
(Fclang_datatype.Qualified_name.Map.Make(
Datatype.List(
Datatype.List(
Datatype.Triple
(Fclang_datatype.Qualified_name)
(Datatype.Triple
(Datatype.Int)
(Fclang_datatype.Access_kind)(Fclang_datatype.Vkind))
(Fclang_datatype.Qualified_name)
))))
(struct
let name = "FramaClang.Class.Inheritance_paths"
let dependencies = [ Inheritance_graph_state.self ]
let size = 17
end)
let add_path map base path =
let existing =
try Fclang_datatype.Qualified_name.Map.find base map
with Not_found -> []
in
Fclang_datatype.Qualified_name.Map.add base (path::existing) map
let extend_paths prefix base base_paths map =
let existing =
try Fclang_datatype.Qualified_name.Map.find base map
with Not_found -> []
in
let new_paths = List.map (fun p -> prefix :: p) base_paths in
Fclang_datatype.Qualified_name.Map.add base (existing @ new_paths) map
let find_all_paths derived base =
let rec aux curr_class =
try
Inheritance_paths.find curr_class
with Not_found ->
let direct_bases =
Inheritance_graph.succ_e (Inheritance_graph_state.get()) curr_class
in
let curr_paths =
List.fold_left add_path_direct
Fclang_datatype.Qualified_name.Map.empty direct_bases
in
Inheritance_paths.add curr_class curr_paths;
curr_paths
and add_path_direct acc (_, _, direct as edge) =
let base_inheritance = aux direct in
let direct_path = add_path acc direct [edge] in
Fclang_datatype.Qualified_name.Map.fold
(extend_paths edge) base_inheritance direct_path
in
let all_paths = aux derived in
try
Fclang_datatype.Qualified_name.Map.find base all_paths
with Not_found -> []
let has_unambiguous_path derived base =
match find_all_paths derived base with
| [] -> false
| [_] -> true
| _::_::_ -> false
(* TODO: checks whether some kind of multiple virtual inheritance
should be accepted here. *)
let has_public_path derived base =
let is_public_path p = List.for_all (fun (_,(_,a,_),_) -> a = Public) p in
List.exists is_public_path (find_all_paths derived base)
exception No_path
let inheritance_path derived base =
match find_all_paths derived base with
| [] -> raise No_path
| p :: _ -> List.map (fun (s,(_,k,v),d) -> (s,(k,v),d)) p