dce.ml 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. (*
  2. * Copyright (C)2005-2013 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. *)
  22. open Ast
  23. open Common
  24. open Type
  25. type dce = {
  26. com : context;
  27. full : bool;
  28. std_dirs : string list;
  29. debug : bool;
  30. follow_expr : dce -> texpr -> unit;
  31. mutable added_fields : (tclass * tclass_field * bool) list;
  32. mutable marked_fields : tclass_field list;
  33. mutable marked_maybe_fields : tclass_field list;
  34. mutable t_stack : t list;
  35. mutable ts_stack : t list;
  36. mutable features : (string,(tclass * tclass_field * bool) list) Hashtbl.t;
  37. }
  38. (* checking *)
  39. (* check for @:keepSub metadata, which forces @:keep on child classes *)
  40. let rec super_forces_keep c =
  41. Meta.has Meta.KeepSub c.cl_meta || match c.cl_super with
  42. | Some (csup,_) -> super_forces_keep csup
  43. | _ -> false
  44. let is_std_file dce file =
  45. List.exists (ExtString.String.starts_with file) dce.std_dirs
  46. (* check if a class is kept entirely *)
  47. let keep_whole_class dce c =
  48. Meta.has Meta.Keep c.cl_meta
  49. || not (dce.full || is_std_file dce c.cl_module.m_extra.m_file || has_meta Meta.Dce c.cl_meta)
  50. || super_forces_keep c
  51. || (match c with
  52. | { cl_path = ([],("Math"|"Array"))} when dce.com.platform = Js -> false
  53. | { cl_extern = true }
  54. | { cl_path = ["flash";"_Boot"],"RealBoot" } -> true
  55. | { cl_path = [],"String" }
  56. | { cl_path = [],"Array" } -> not (dce.com.platform = Js)
  57. | _ -> false)
  58. let keep_whole_enum dce en =
  59. Meta.has Meta.Keep en.e_meta
  60. || not (dce.full || is_std_file dce en.e_module.m_extra.m_file || has_meta Meta.Dce en.e_meta)
  61. (* check if a field is kept *)
  62. let keep_field dce cf =
  63. Meta.has Meta.Keep cf.cf_meta
  64. || Meta.has Meta.Used cf.cf_meta
  65. || cf.cf_name = "__init__"
  66. (* marking *)
  67. let rec check_feature dce s =
  68. try
  69. let l = Hashtbl.find dce.features s in
  70. List.iter (fun (c,cf,stat) ->
  71. mark_field dce c cf stat
  72. ) l;
  73. Hashtbl.remove dce.features s;
  74. with Not_found ->
  75. ()
  76. (* mark a field as kept *)
  77. and mark_field dce c cf stat =
  78. let add cf =
  79. if not (Meta.has Meta.Used cf.cf_meta) then begin
  80. cf.cf_meta <- (Meta.Used,[],cf.cf_pos) :: cf.cf_meta;
  81. dce.added_fields <- (c,cf,stat) :: dce.added_fields;
  82. dce.marked_fields <- cf :: dce.marked_fields;
  83. check_feature dce (Printf.sprintf "%s.%s" (s_type_path c.cl_path) cf.cf_name);
  84. end
  85. in
  86. if cf.cf_name = "new" then begin
  87. let rec loop c = match c.cl_super with
  88. | None -> ()
  89. | Some (csup,_) ->
  90. begin match csup.cl_constructor with
  91. | None -> ()
  92. | Some cf -> add cf
  93. end;
  94. loop csup
  95. in
  96. loop c
  97. end;
  98. if not (PMap.mem cf.cf_name (if stat then c.cl_statics else c.cl_fields)) then begin
  99. match c.cl_super with
  100. | None -> add cf
  101. | Some (c,_) -> mark_field dce c cf stat
  102. end else
  103. add cf
  104. let rec update_marked_class_fields dce c =
  105. (* mark all :?used fields as surely :used now *)
  106. List.iter (fun cf ->
  107. if Meta.has Meta.MaybeUsed cf.cf_meta then mark_field dce c cf true
  108. ) c.cl_ordered_statics;
  109. List.iter (fun cf ->
  110. if Meta.has Meta.MaybeUsed cf.cf_meta then mark_field dce c cf false
  111. ) c.cl_ordered_fields;
  112. (* we always have to keep super classes and implemented interfaces *)
  113. (match c.cl_init with None -> () | Some init -> dce.follow_expr dce init);
  114. List.iter (fun (c,_) -> mark_class dce c) c.cl_implements;
  115. (match c.cl_super with None -> () | Some (csup,pl) -> mark_class dce csup)
  116. (* mark a class as kept. If the class has fields marked as @:?keep, make sure to keep them *)
  117. and mark_class dce c = if not (Meta.has Meta.Used c.cl_meta) then begin
  118. c.cl_meta <- (Meta.Used,[],c.cl_pos) :: c.cl_meta;
  119. update_marked_class_fields dce c;
  120. end
  121. let rec mark_enum dce e = if not (Meta.has Meta.Used e.e_meta) then begin
  122. e.e_meta <- (Meta.Used,[],e.e_pos) :: e.e_meta;
  123. PMap.iter (fun _ ef -> mark_t dce ef.ef_pos ef.ef_type) e.e_constrs;
  124. end
  125. and mark_abstract dce a = if not (Meta.has Meta.Used a.a_meta) then
  126. a.a_meta <- (Meta.Used,[],a.a_pos) :: a.a_meta
  127. (* mark a type as kept *)
  128. and mark_t dce p t =
  129. if not (List.exists (fun t2 -> Type.fast_eq t t2) dce.t_stack) then begin
  130. dce.t_stack <- t :: dce.t_stack;
  131. begin match follow t with
  132. | TInst({cl_kind = KTypeParameter tl} as c,pl) ->
  133. if not (Meta.has Meta.Used c.cl_meta) then begin
  134. c.cl_meta <- (Meta.Used,[],c.cl_pos) :: c.cl_meta;
  135. List.iter (mark_t dce p) tl;
  136. end;
  137. List.iter (mark_t dce p) pl
  138. | TInst(c,pl) ->
  139. mark_class dce c;
  140. List.iter (mark_t dce p) pl
  141. | TFun(args,ret) ->
  142. List.iter (fun (_,_,t) -> mark_t dce p t) args;
  143. mark_t dce p ret
  144. | TEnum(e,pl) ->
  145. mark_enum dce e;
  146. List.iter (mark_t dce p) pl
  147. | TAbstract(a,pl) when Meta.has Meta.MultiType a.a_meta ->
  148. begin try
  149. mark_t dce p (snd (Codegen.Abstract.find_multitype_specialization a pl p))
  150. with Typecore.Error _ ->
  151. ()
  152. end
  153. | TAbstract(a,pl) ->
  154. mark_abstract dce a;
  155. List.iter (mark_t dce p) pl
  156. | TLazy _ | TDynamic _ | TAnon _ | TType _ | TMono _ -> ()
  157. end;
  158. dce.t_stack <- List.tl dce.t_stack
  159. end
  160. let mark_mt dce mt = match mt with
  161. | TClassDecl c ->
  162. mark_class dce c;
  163. | TEnumDecl e ->
  164. mark_enum dce e
  165. | TAbstractDecl a ->
  166. (* abstract 'feature' is defined as the abstract type beeing used as a value, not as a type *)
  167. if not (Meta.has Meta.ValueUsed a.a_meta) then a.a_meta <- (Meta.ValueUsed,[],a.a_pos) :: a.a_meta;
  168. mark_abstract dce a
  169. | TTypeDecl _ ->
  170. ()
  171. (* find all dependent fields by checking implementing/subclassing types *)
  172. let rec mark_dependent_fields dce csup n stat =
  173. List.iter (fun mt -> match mt with
  174. | TClassDecl c when is_parent csup c ->
  175. let rec loop c =
  176. (try
  177. let cf = PMap.find n (if stat then c.cl_statics else c.cl_fields) in
  178. (* if it's clear that the class is kept, the field has to be kept as well. This is also true for
  179. extern interfaces because we cannot remove fields from them *)
  180. if Meta.has Meta.Used c.cl_meta || (csup.cl_interface && csup.cl_extern) then mark_field dce c cf stat
  181. (* otherwise it might be kept if the class is kept later, so mark it as :?used *)
  182. else if not (Meta.has Meta.MaybeUsed cf.cf_meta) then begin
  183. cf.cf_meta <- (Meta.MaybeUsed,[],cf.cf_pos) :: cf.cf_meta;
  184. dce.marked_maybe_fields <- cf :: dce.marked_maybe_fields;
  185. end
  186. with Not_found ->
  187. (* if the field is not present on current class, it might come from a base class *)
  188. (match c.cl_super with None -> () | Some (csup,_) -> loop csup))
  189. in
  190. loop c
  191. | _ -> ()
  192. ) dce.com.types
  193. (* expr and field evaluation *)
  194. let opt f e = match e with None -> () | Some e -> f e
  195. let rec to_string dce t = match t with
  196. | TInst(c,tl) ->
  197. field dce c "toString" false;
  198. | TType(tt,tl) ->
  199. if not (List.exists (fun t2 -> Type.fast_eq t t2) dce.ts_stack) then begin
  200. dce.ts_stack <- t :: dce.ts_stack;
  201. to_string dce (apply_params tt.t_types tl tt.t_type)
  202. end
  203. | TAbstract({a_impl = Some c} as a,tl) ->
  204. if Meta.has Meta.CoreType a.a_meta then
  205. field dce c "toString" false
  206. else
  207. to_string dce (Codegen.Abstract.get_underlying_type a tl)
  208. | TMono r ->
  209. (match !r with
  210. | Some t -> to_string dce t
  211. | _ -> ())
  212. | TLazy f ->
  213. to_string dce (!f())
  214. | TDynamic t ->
  215. if t == t_dynamic then
  216. ()
  217. else
  218. to_string dce t
  219. | TEnum _ | TFun _ | TAnon _ | TAbstract({a_impl = None},_) ->
  220. (* if we to_string these it does not imply that we need all its sub-types *)
  221. ()
  222. and field dce c n stat =
  223. let find_field n =
  224. if n = "new" then match c.cl_constructor with
  225. | None -> raise Not_found
  226. | Some cf -> cf
  227. else PMap.find n (if stat then c.cl_statics else c.cl_fields)
  228. in
  229. (try
  230. let cf = find_field n in
  231. mark_field dce c cf stat;
  232. with Not_found -> try
  233. (* me might have a property access on an interface *)
  234. let l = String.length n - 4 in
  235. if l < 0 then raise Not_found;
  236. let prefix = String.sub n 0 4 in
  237. let pn = String.sub n 4 l in
  238. let cf = find_field pn in
  239. let keep () =
  240. mark_dependent_fields dce c n stat;
  241. field dce c pn stat
  242. in
  243. (match prefix,cf.cf_kind with
  244. | "get_",Var {v_read = AccCall} when "get_" ^ cf.cf_name = n -> keep()
  245. | "set_",Var {v_write = AccCall} when "set_" ^ cf.cf_name = n -> keep()
  246. | _ -> raise Not_found
  247. );
  248. raise Not_found
  249. with Not_found -> try
  250. if c.cl_interface then begin
  251. let rec loop cl = match cl with
  252. | [] -> raise Not_found
  253. | (c,_) :: cl ->
  254. try field dce c n stat with Not_found -> loop cl
  255. in
  256. loop c.cl_implements
  257. end else match c.cl_super with Some (csup,_) -> field dce csup n stat | None -> raise Not_found
  258. with Not_found -> try
  259. match c.cl_kind with
  260. | KTypeParameter tl ->
  261. let rec loop tl = match tl with
  262. | [] -> raise Not_found
  263. | TInst(c,_) :: cl ->
  264. (try field dce c n stat with Not_found -> loop cl)
  265. | t :: tl ->
  266. loop tl
  267. in
  268. loop tl
  269. | _ -> raise Not_found
  270. with Not_found ->
  271. if dce.debug then prerr_endline ("[DCE] Field " ^ n ^ " not found on " ^ (s_type_path c.cl_path)) else ())
  272. and expr dce e =
  273. mark_t dce e.epos e.etype;
  274. match e.eexpr with
  275. | TNew(c,pl,el) ->
  276. mark_class dce c;
  277. field dce c "new" false;
  278. List.iter (expr dce) el;
  279. List.iter (mark_t dce e.epos) pl;
  280. | TVar (v,e1) ->
  281. opt (expr dce) e1;
  282. mark_t dce e.epos v.v_type;
  283. | TCast(e, Some mt) ->
  284. check_feature dce "typed_cast";
  285. mark_mt dce mt;
  286. expr dce e;
  287. | TTypeExpr mt ->
  288. mark_mt dce mt
  289. | TTry(e, vl) ->
  290. expr dce e;
  291. List.iter (fun (v,e) ->
  292. if v.v_type != t_dynamic then check_feature dce "typed_catch";
  293. expr dce e;
  294. mark_t dce e.epos v.v_type;
  295. ) vl;
  296. | TCall ({eexpr = TLocal ({v_name = "__define_feature__"})},[{eexpr = TConst (TString ft)};e]) ->
  297. Common.add_feature dce.com ft;
  298. check_feature dce ft;
  299. expr dce e
  300. (* keep toString method when the class is argument to Std.string or haxe.Log.trace *)
  301. | TCall ({eexpr = TField({eexpr = TTypeExpr (TClassDecl ({cl_path = (["haxe"],"Log")} as c))},FStatic (_,{cf_name="trace"}))} as ef, ((e2 :: el) as args))
  302. | TCall ({eexpr = TField({eexpr = TTypeExpr (TClassDecl ({cl_path = ([],"Std")} as c))},FStatic (_,{cf_name="string"}))} as ef, ((e2 :: el) as args)) ->
  303. mark_class dce c;
  304. to_string dce e2.etype;
  305. begin match el with
  306. | [{eexpr = TObjectDecl fl}] ->
  307. begin try
  308. begin match List.assoc "customParams" fl with
  309. | {eexpr = TArrayDecl el} ->
  310. List.iter (fun e -> to_string dce e.etype) el
  311. | _ ->
  312. ()
  313. end
  314. with Not_found ->
  315. ()
  316. end
  317. | _ ->
  318. ()
  319. end;
  320. expr dce ef;
  321. List.iter (expr dce) args;
  322. | TCall ({eexpr = TConst TSuper} as e,el) ->
  323. mark_t dce e.epos e.etype;
  324. List.iter (expr dce) el;
  325. | TField(e,fa) ->
  326. begin match fa with
  327. | FStatic(c,cf) ->
  328. mark_class dce c;
  329. mark_field dce c cf true;
  330. | FInstance(c,cf) ->
  331. mark_class dce c;
  332. mark_field dce c cf false;
  333. | _ ->
  334. let n = field_name fa in
  335. begin match follow e.etype with
  336. | TInst(c,_) ->
  337. mark_class dce c;
  338. field dce c n false;
  339. | TAnon a ->
  340. (match !(a.a_status) with
  341. | Statics c ->
  342. mark_class dce c;
  343. field dce c n true;
  344. | _ -> ())
  345. | _ -> ()
  346. end;
  347. end;
  348. expr dce e;
  349. | TThrow e ->
  350. to_string dce e.etype;
  351. expr dce e
  352. | _ ->
  353. Type.iter (expr dce) e
  354. let run com main full =
  355. let dce = {
  356. com = com;
  357. full = full;
  358. std_dirs = if full then [] else List.map Common.unique_full_path com.std_path;
  359. debug = Common.defined com Define.DceDebug;
  360. added_fields = [];
  361. follow_expr = expr;
  362. marked_fields = [];
  363. marked_maybe_fields = [];
  364. t_stack = [];
  365. ts_stack = [];
  366. features = Hashtbl.create 0;
  367. } in
  368. begin match main with
  369. | Some {eexpr = TCall({eexpr = TField(e,(FStatic(c,cf)))},_)} ->
  370. cf.cf_meta <- (Meta.Keep,[],cf.cf_pos) :: cf.cf_meta
  371. | _ ->
  372. ()
  373. end;
  374. List.iter (fun m ->
  375. List.iter (fun (s,v) ->
  376. if Hashtbl.mem dce.features s then Hashtbl.replace dce.features s (v :: Hashtbl.find dce.features s)
  377. else Hashtbl.add dce.features s [v]
  378. ) m.m_extra.m_features;
  379. ) com.modules;
  380. (* first step: get all entry points, which is the main method and all class methods which are marked with @:keep *)
  381. List.iter (fun t -> match t with
  382. | TClassDecl c ->
  383. let keep_class = keep_whole_class dce c && (not c.cl_extern || c.cl_interface) in
  384. let loop stat cf =
  385. if keep_class || keep_field dce cf then mark_field dce c cf stat
  386. in
  387. List.iter (loop true) c.cl_ordered_statics;
  388. List.iter (loop false) c.cl_ordered_fields;
  389. begin match c.cl_constructor with
  390. | Some cf -> loop false cf
  391. | None -> ()
  392. end
  393. | TEnumDecl en when keep_whole_enum dce en ->
  394. mark_enum dce en
  395. | _ ->
  396. ()
  397. ) com.types;
  398. if dce.debug then begin
  399. List.iter (fun (c,cf,_) -> match cf.cf_expr with
  400. | None -> ()
  401. | Some _ -> print_endline ("[DCE] Entry point: " ^ (s_type_path c.cl_path) ^ "." ^ cf.cf_name)
  402. ) dce.added_fields;
  403. end;
  404. (* second step: initiate DCE passes and keep going until no new fields were added *)
  405. let rec loop () =
  406. match dce.added_fields with
  407. | [] -> ()
  408. | cfl ->
  409. dce.added_fields <- [];
  410. (* extend to dependent (= overriding/implementing) class fields *)
  411. List.iter (fun (c,cf,stat) -> mark_dependent_fields dce c cf.cf_name stat) cfl;
  412. (* mark fields as used *)
  413. List.iter (fun (c,cf,stat) ->
  414. mark_class dce c;
  415. mark_field dce c cf stat;
  416. mark_t dce cf.cf_pos cf.cf_type
  417. ) cfl;
  418. (* follow expressions to new types/fields *)
  419. List.iter (fun (_,cf,_) ->
  420. opt (expr dce) cf.cf_expr;
  421. List.iter (fun cf -> if cf.cf_expr <> None then opt (expr dce) cf.cf_expr) cf.cf_overloads
  422. ) cfl;
  423. loop ()
  424. in
  425. loop ();
  426. (* third step: filter types *)
  427. let rec loop acc types =
  428. match types with
  429. | (TClassDecl c) as mt :: l when keep_whole_class dce c ->
  430. loop (mt :: acc) l
  431. | (TClassDecl c) as mt :: l ->
  432. let check_property cf stat =
  433. let add_accessor_metadata cf =
  434. if not (Meta.has Meta.Accessor cf.cf_meta) then cf.cf_meta <- (Meta.Accessor,[],c.cl_pos) :: cf.cf_meta
  435. in
  436. begin match cf.cf_kind with
  437. | Var {v_read = AccCall} ->
  438. begin try
  439. add_accessor_metadata (PMap.find ("get_" ^ cf.cf_name) (if stat then c.cl_statics else c.cl_fields))
  440. with Not_found ->
  441. ()
  442. end
  443. | _ ->
  444. ()
  445. end;
  446. begin match cf.cf_kind with
  447. | Var {v_write = AccCall} ->
  448. begin try
  449. add_accessor_metadata (PMap.find ("set_" ^ cf.cf_name) (if stat then c.cl_statics else c.cl_fields))
  450. with Not_found ->
  451. ()
  452. end
  453. | _ ->
  454. ()
  455. end;
  456. in
  457. (* add :keep so subsequent filter calls do not process class fields again *)
  458. c.cl_meta <- (Meta.Keep,[],c.cl_pos) :: c.cl_meta;
  459. c.cl_ordered_statics <- List.filter (fun cf ->
  460. let b = keep_field dce cf in
  461. if not b then begin
  462. if dce.debug then print_endline ("[DCE] Removed field " ^ (s_type_path c.cl_path) ^ "." ^ (cf.cf_name));
  463. check_property cf true;
  464. c.cl_statics <- PMap.remove cf.cf_name c.cl_statics;
  465. end;
  466. b
  467. ) c.cl_ordered_statics;
  468. c.cl_ordered_fields <- List.filter (fun cf ->
  469. let b = keep_field dce cf in
  470. if not b then begin
  471. if dce.debug then print_endline ("[DCE] Removed field " ^ (s_type_path c.cl_path) ^ "." ^ (cf.cf_name));
  472. check_property cf false;
  473. c.cl_fields <- PMap.remove cf.cf_name c.cl_fields;
  474. end;
  475. b
  476. ) c.cl_ordered_fields;
  477. (match c.cl_constructor with Some cf when not (keep_field dce cf) -> c.cl_constructor <- None | _ -> ());
  478. (* we keep a class if it was used or has a used field *)
  479. if Meta.has Meta.Used c.cl_meta || c.cl_ordered_statics <> [] || c.cl_ordered_fields <> [] then loop (mt :: acc) l else begin
  480. (match c.cl_init with
  481. | Some f when Meta.has Meta.KeepInit c.cl_meta ->
  482. (* it means that we only need the __init__ block *)
  483. c.cl_extern <- true;
  484. loop (mt :: acc) l
  485. | _ ->
  486. if dce.debug then print_endline ("[DCE] Removed class " ^ (s_type_path c.cl_path));
  487. loop acc l)
  488. end
  489. | (TEnumDecl en) as mt :: l when Meta.has Meta.Used en.e_meta || en.e_extern || keep_whole_enum dce en ->
  490. loop (mt :: acc) l
  491. | TEnumDecl e :: l ->
  492. if dce.debug then print_endline ("[DCE] Removed enum " ^ (s_type_path e.e_path));
  493. loop acc l
  494. | mt :: l ->
  495. loop (mt :: acc) l
  496. | [] ->
  497. acc
  498. in
  499. com.types <- loop [] (List.rev com.types);
  500. (* extra step to adjust properties that had accessors removed (required for Php and Cpp) *)
  501. List.iter (fun mt -> match mt with
  502. | (TClassDecl c) ->
  503. let rec has_accessor c n stat =
  504. PMap.mem n (if stat then c.cl_statics else c.cl_fields)
  505. || match c.cl_super with Some (csup,_) -> has_accessor csup n stat | None -> false
  506. in
  507. let check_prop stat cf =
  508. (match cf.cf_kind with
  509. | Var {v_read = AccCall; v_write = a} ->
  510. let s = "get_" ^ cf.cf_name in
  511. cf.cf_kind <- Var {v_read = if has_accessor c s stat then AccCall else AccNever; v_write = a}
  512. | _ -> ());
  513. (match cf.cf_kind with
  514. | Var {v_write = AccCall; v_read = a} ->
  515. let s = "set_" ^ cf.cf_name in
  516. cf.cf_kind <- Var {v_write = if has_accessor c s stat then AccCall else AccNever; v_read = a}
  517. | _ -> ())
  518. in
  519. List.iter (check_prop true) c.cl_ordered_statics;
  520. List.iter (check_prop false) c.cl_ordered_fields;
  521. | _ -> ()
  522. ) com.types;
  523. (* remove "override" from fields that do not override anything anymore *)
  524. List.iter (fun mt -> match mt with
  525. | TClassDecl c ->
  526. c.cl_overrides <- List.filter (fun s ->
  527. let rec loop c =
  528. match c.cl_super with
  529. | Some (csup,_) when PMap.mem s.cf_name csup.cl_fields -> true
  530. | Some (csup,_) -> loop csup
  531. | None -> false
  532. in
  533. loop c
  534. ) c.cl_overrides;
  535. | _ -> ()
  536. ) com.types;
  537. (* cleanup added fields metadata - compatibility with compilation server *)
  538. let rec remove_meta m = function
  539. | [] -> []
  540. | (m2,_,_) :: l when m = m2 -> l
  541. | x :: l -> x :: remove_meta m l
  542. in
  543. List.iter (fun cf -> cf.cf_meta <- remove_meta Meta.Used cf.cf_meta) dce.marked_fields;
  544. List.iter (fun cf -> cf.cf_meta <- remove_meta Meta.MaybeUsed cf.cf_meta) dce.marked_maybe_fields;