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)
177 File_provider.get_contents
178 ~force_read_disk
:ignore_file_content_caches
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
186 let popt = Provider_context.get_popt ctx
in
187 let opts = DeclParserOptions.from_parser_options
popt in
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
->
199 Naming_special_names.UserAttributes.uaPHPStdLib
200 (snd a
.Typing_defs_core.ua_name
))
203 if not
deregister_php_stdlib then
206 let open Shallow_decl_defs
in
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
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;
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 }
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
242 let result = direct_decl_parse ctx file
in
244 | Some
parsed_file -> cache_decls ctx file
parsed_file.pfh_decls
248 let decls_to_fileinfo = Direct_decl_parser.decls_to_fileinfo