Remove enable_disk_heap setting
[hiphop-php.git] / hphp / hack / src / providers / direct_decl_utils.ml
blob48e36b495849aafad2d0fa86aba76ebbaea93786
1 (*
2 * Copyright (c) Facebook, Inc. and its affiliates.
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the "hack" directory of this source tree.
7 *)
9 open Hh_prelude
11 type parsed_file_with_hashes = Direct_decl_parser.parsed_file_with_hashes = {
12 pfh_mode: FileInfo.mode option;
13 pfh_hash: Int64.t;
14 pfh_decls: (string * Shallow_decl_defs.decl * Int64.t) list;
17 (* If any decls in the list have the same name, retain only the first
18 declaration of each symbol in the sequence. *)
19 let dedup_decls decls =
20 let open Shallow_decl_defs in
21 let seen_types = String.Table.create () in
22 let seen_funs = String.Table.create () in
23 let seen_consts = String.Table.create () in
24 let seen_modules = String.Table.create () in
25 Sequence.filter decls ~f:(fun decl ->
26 match decl with
27 | (name, Class _)
28 | (name, Typedef _) ->
29 if String.Table.mem seen_types name then
30 false
31 else
32 let () = String.Table.add_exn seen_types ~key:name ~data:() in
33 true
34 | (name, Fun _) ->
35 if String.Table.mem seen_funs name then
36 false
37 else
38 let () = String.Table.add_exn seen_funs ~key:name ~data:() in
39 true
40 | (name, Const _) ->
41 if String.Table.mem seen_consts name then
42 false
43 else
44 let () = String.Table.add_exn seen_consts ~key:name ~data:() in
45 true
46 | (name, Module _) ->
47 if String.Table.mem seen_modules name then
48 false
49 else
50 let () = String.Table.add_exn seen_modules ~key:name ~data:() in
51 true)
53 (* If a symbol was also declared in another file, and that file was determined
54 to be the winner in the naming table, remove its decl from the list.
56 Do not remove decls if there is no entry for them in the naming table. This
57 ensures that this path can populate the decl heap during full inits. This may
58 result in the decl heap containing an incorrect decl in the event of a naming
59 conflict, which might be confusing. But the user will be obligated to fix the
60 naming conflict, and this behavior is limited to full inits, so maybe we can
61 live with it. *)
62 let remove_naming_conflict_losers ctx file decls =
63 let open Shallow_decl_defs in
64 Sequence.filter decls ~f:(fun decl ->
65 match decl with
66 | (name, Class _)
67 | (name, Typedef _) ->
68 (match Naming_provider.get_type_path ctx name with
69 | Some nfile -> Relative_path.equal nfile file
70 | None -> true)
71 | (name, Fun _) ->
72 (match Naming_provider.get_fun_path ctx name with
73 | Some nfile -> Relative_path.equal nfile file
74 | None -> true)
75 | (name, Const _) ->
76 (match Naming_provider.get_const_path ctx name with
77 | Some nfile -> Relative_path.equal nfile file
78 | None -> true)
79 | (name, Module _) ->
80 (match Naming_provider.get_module_path ctx name with
81 | Some nfile -> Relative_path.equal nfile file
82 | None -> true))
84 let cache_decls ctx file decls =
85 let open Shallow_decl_defs in
86 let open Typing_defs in
87 let decls =
88 decls
89 |> List.rev_map (* direct decl parser produces reverse of syntactic order *)
90 ~f:(fun (name, decl, _hash) -> (name, decl))
91 |> Sequence.of_list
92 |> dedup_decls
93 |> remove_naming_conflict_losers ctx file
94 |> Sequence.to_list
96 match Provider_context.get_backend ctx with
97 | Provider_backend.Pessimised_shared_memory _ ->
98 (* We must never perform caching here. Otherwise, we may overwrite earlier
99 pessimisation results with unpessimised types *)
100 failwith "invalid"
101 | Provider_backend.Analysis
102 | Provider_backend.Shared_memory ->
103 List.iter decls ~f:(function
104 | (name, Class decl) ->
105 Shallow_classes_heap.Classes.add name decl;
107 TypecheckerOptions.shallow_class_decl
108 (Provider_context.get_tcopt ctx)
109 then
110 Shallow_classes_heap.MemberFilters.add decl
111 | (name, Fun decl) -> Decl_store.((get ()).add_fun name decl)
112 | (name, Typedef decl) -> Decl_store.((get ()).add_typedef name decl)
113 | (name, Const decl) -> Decl_store.((get ()).add_gconst name decl)
114 | (name, Module decl) -> Decl_store.((get ()).add_module name decl))
115 | Provider_backend.Rust_provider_backend backend ->
116 Rust_provider_backend.Decl.add_shallow_decls backend decls
117 | Provider_backend.(Local_memory { decl_cache; shallow_decl_cache; _ }) ->
118 List.iter decls ~f:(function
119 | (name, Class decl) ->
120 let (_ : shallow_class option) =
121 Provider_backend.Shallow_decl_cache.find_or_add
122 shallow_decl_cache
123 ~key:
124 (Provider_backend.Shallow_decl_cache_entry.Shallow_class_decl
125 name)
126 ~default:(fun () -> Some decl)
129 | (name, Fun decl) ->
130 let (_ : fun_elt option) =
131 Provider_backend.Decl_cache.find_or_add
132 decl_cache
133 ~key:(Provider_backend.Decl_cache_entry.Fun_decl name)
134 ~default:(fun () -> Some decl)
137 | (name, Typedef decl) ->
138 let (_ : typedef_type option) =
139 Provider_backend.Decl_cache.find_or_add
140 decl_cache
141 ~key:(Provider_backend.Decl_cache_entry.Typedef_decl name)
142 ~default:(fun () -> Some decl)
145 | (name, Const decl) ->
146 let (_ : const_decl option) =
147 Provider_backend.Decl_cache.find_or_add
148 decl_cache
149 ~key:(Provider_backend.Decl_cache_entry.Gconst_decl name)
150 ~default:(fun () -> Some decl)
153 | (name, Module decl) ->
154 let (_ : module_decl option) =
155 Provider_backend.Decl_cache.find_or_add
156 decl_cache
157 ~key:(Provider_backend.Decl_cache_entry.Module_decl name)
158 ~default:(fun () -> Some decl)
161 | Provider_backend.Decl_service _ ->
162 failwith
163 "Direct_decl_utils.cache_file_decls not implemented for Decl_service"
165 let get_file_contents ~ignore_file_content_caches ctx filename =
166 let from_entries =
167 if ignore_file_content_caches then
168 None
169 else
170 Relative_path.Map.find_opt (Provider_context.get_entries ctx) filename
172 match from_entries with
173 | Some entry ->
174 let source_text = Ast_provider.compute_source_text ~entry in
175 Some (Full_fidelity_source_text.text source_text)
176 | None ->
177 File_provider.get_contents
178 ~force_read_disk:ignore_file_content_caches
179 filename
181 let direct_decl_parse ?(ignore_file_content_caches = false) ctx file =
182 Counters.count Counters.Category.Get_decl @@ fun () ->
183 match get_file_contents ~ignore_file_content_caches ctx file with
184 | None -> None
185 | Some contents ->
186 let popt = Provider_context.get_popt ctx in
187 let opts = DeclParserOptions.from_parser_options popt in
188 let parsed_file =
189 Direct_decl_parser.parse_and_hash_decls opts file contents
191 let deregister_php_stdlib =
192 Relative_path.is_hhi (Relative_path.prefix file)
193 && ParserOptions.deregister_php_stdlib popt
195 let is_stdlib_fun fun_decl = fun_decl.Typing_defs.fe_php_std_lib in
196 let is_stdlib_class c =
197 List.exists c.Shallow_decl_defs.sc_user_attributes ~f:(fun a ->
198 String.equal
199 Naming_special_names.UserAttributes.uaPHPStdLib
200 (snd a.Typing_defs_core.ua_name))
202 let parsed_file =
203 if not deregister_php_stdlib then
204 parsed_file
205 else
206 let open Shallow_decl_defs in
207 let decls =
208 List.filter_map parsed_file.pfh_decls ~f:(function
209 | (_, Fun f, _) when is_stdlib_fun f -> None
210 | (_, Class c, _) when is_stdlib_class c -> None
211 | (name, Class c, hash) ->
212 let keep_prop sp = not (sp_php_std_lib sp) in
213 let keep_meth sm = not (sm_php_std_lib sm) in
214 let c =
216 c with
217 sc_props = List.filter c.sc_props ~f:keep_prop;
218 sc_sprops = List.filter c.sc_sprops ~f:keep_prop;
219 sc_methods = List.filter c.sc_methods ~f:keep_meth;
220 sc_static_methods =
221 List.filter c.sc_static_methods ~f:keep_meth;
224 Some (name, Class c, hash)
225 | name_decl_and_hash -> Some name_decl_and_hash)
227 { parsed_file with pfh_decls = decls }
229 Some parsed_file
231 let direct_decl_parse_and_cache ctx file =
232 match Provider_context.get_backend ctx with
233 | Provider_backend.Rust_provider_backend backend ->
234 Counters.count Counters.Category.Get_decl @@ fun () ->
235 get_file_contents ~ignore_file_content_caches:false ctx file
236 |> Option.map ~f:(fun contents ->
237 Rust_provider_backend.Decl.direct_decl_parse_and_cache
238 backend
239 file
240 contents)
241 | _ ->
242 let result = direct_decl_parse ctx file in
243 (match result with
244 | Some parsed_file -> cache_decls ctx file parsed_file.pfh_decls
245 | None -> ());
246 result
248 let decls_to_fileinfo = Direct_decl_parser.decls_to_fileinfo