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.
11 type parsed_file_with_hashes
= Direct_decl_parser.parsed_file_with_hashes
= {
12 pfh_mode
: FileInfo.mode
option;
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
->
28 | (name
, Typedef _
) ->
29 if String.Table.mem
seen_types name
then
32 let () = String.Table.add_exn
seen_types ~key
:name ~data
:() in
35 if String.Table.mem
seen_funs name
then
38 let () = String.Table.add_exn
seen_funs ~key
:name ~data
:() in
41 if String.Table.mem
seen_consts name
then
44 let () = String.Table.add_exn
seen_consts ~key
:name ~data
:() in
47 if String.Table.mem
seen_modules name
then
50 let () = String.Table.add_exn
seen_modules ~key
:name ~data
:() in
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
62 let remove_naming_conflict_losers ctx file decls
=
63 let open Shallow_decl_defs
in
64 Sequence.filter decls ~f
:(fun decl
->
67 | (name
, Typedef _
) ->
68 (match Naming_provider.get_type_path ctx name
with
69 | Some nfile
-> Relative_path.equal nfile file
72 (match Naming_provider.get_fun_path ctx name
with
73 | Some nfile
-> Relative_path.equal nfile file
76 (match Naming_provider.get_const_path ctx name
with
77 | Some nfile
-> Relative_path.equal nfile file
80 (match Naming_provider.get_module_path ctx name
with
81 | Some nfile
-> Relative_path.equal nfile file
84 let cache_decls ctx file decls
=
85 let open Shallow_decl_defs
in
86 let open Typing_defs
in
89 |> List.rev_map
(* direct decl parser produces reverse of syntactic order *)
90 ~f
:(fun (name
, decl
, _hash
) -> (name
, decl
))
93 |> remove_naming_conflict_losers ctx file
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 *)
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
)
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
124 (Provider_backend.Shallow_decl_cache_entry.Shallow_class_decl
126 ~default
:(fun () -> Some decl
)
129 | (name
, Fun decl
) ->
130 let (_
: fun_elt
option) =
131 Provider_backend.Decl_cache.find_or_add
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
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
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
157 ~key
:(Provider_backend.Decl_cache_entry.Module_decl name
)
158 ~default
:(fun () -> Some decl
)
161 | Provider_backend.Decl_service _
->
163 "Direct_decl_utils.cache_file_decls not implemented for Decl_service"
165 let get_file_contents ~ignore_file_content_caches ctx filename
=
167 if ignore_file_content_caches
then
170 Relative_path.Map.find_opt
(Provider_context.get_entries ctx
) filename
172 match from_entries with
174 let source_text = Ast_provider.compute_source_text ~entry
in
175 Some
(Full_fidelity_source_text.text
source_text)
178 (not ignore_file_content_caches
)
179 && TypecheckerOptions.enable_disk_heap
(Provider_context.get_tcopt ctx
)
181 File_provider.get_contents
182 ~force_read_disk
:ignore_file_content_caches
183 ~writeback_disk_contents_in_shmem_provider
:write_to_cache
186 let direct_decl_parse ?
(ignore_file_content_caches
= false) ctx file
=
187 Counters.count
Counters.Category.Get_decl
@@ fun () ->
188 match get_file_contents ~ignore_file_content_caches ctx file
with
191 let popt = Provider_context.get_popt ctx
in
192 let opts = DeclParserOptions.from_parser_options
popt in
194 Direct_decl_parser.parse_and_hash_decls
opts file contents
196 let deregister_php_stdlib =
197 Relative_path.is_hhi
(Relative_path.prefix file
)
198 && ParserOptions.deregister_php_stdlib popt
200 let is_stdlib_fun fun_decl
= fun_decl
.Typing_defs.fe_php_std_lib
in
201 let is_stdlib_class c
=
202 List.exists c
.Shallow_decl_defs.sc_user_attributes ~f
:(fun a
->
204 Naming_special_names.UserAttributes.uaPHPStdLib
205 (snd a
.Typing_defs_core.ua_name
))
208 if not
deregister_php_stdlib then
211 let open Shallow_decl_defs
in
213 List.filter_map
parsed_file.pfh_decls ~f
:(function
214 | (_
, Fun f
, _
) when is_stdlib_fun f
-> None
215 | (_
, Class c
, _
) when is_stdlib_class c
-> None
216 | (name
, Class c
, hash
) ->
217 let keep_prop sp
= not
(sp_php_std_lib sp
) in
218 let keep_meth sm
= not
(sm_php_std_lib sm
) in
222 sc_props
= List.filter
c.sc_props ~f
:keep_prop;
223 sc_sprops
= List.filter
c.sc_sprops ~f
:keep_prop;
224 sc_methods
= List.filter
c.sc_methods ~f
:keep_meth;
226 List.filter
c.sc_static_methods ~f
:keep_meth;
229 Some
(name
, Class
c, hash
)
230 | name_decl_and_hash
-> Some name_decl_and_hash
)
232 { parsed_file with pfh_decls
= decls }
236 let direct_decl_parse_and_cache ctx file
=
237 match Provider_context.get_backend ctx
with
238 | Provider_backend.Rust_provider_backend backend
->
239 Counters.count
Counters.Category.Get_decl
@@ fun () ->
240 get_file_contents ~ignore_file_content_caches
:false ctx file
241 |> Option.map ~f
:(fun contents
->
242 Rust_provider_backend.Decl.direct_decl_parse_and_cache
247 let result = direct_decl_parse ctx file
in
249 | Some
parsed_file -> cache_decls ctx file
parsed_file.pfh_decls
253 let decls_to_fileinfo = Direct_decl_parser.decls_to_fileinfo