Add type annotations to `clientConnect.ml`
[hiphop-php.git] / hphp / hack / src / server / serverIdeUtils.ml
blob1c706424217fa080f7f62764aeabee5267d81ff2
1 (**
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
8 *)
10 open Hh_core
12 let make_local_changes () =
13 Errors.set_allow_errors_in_default_path true;
14 SharedMem.allow_hashtable_writes_by_current_process false;
15 Fixmes.HH_FIXMES.LocalChanges.push_stack();
16 Fixmes.DECL_HH_FIXMES.LocalChanges.push_stack();
17 File_heap.FileHeap.LocalChanges.push_stack();
18 Parser_heap.ParserHeap.LocalChanges.push_stack();
20 Ide_parser_cache.activate ();
22 Naming_heap.FunPosHeap.LocalChanges.push_stack();
23 Naming_heap.FunCanonHeap.LocalChanges.push_stack();
24 Naming_heap.TypeIdHeap.LocalChanges.push_stack();
25 Naming_heap.TypeCanonHeap.LocalChanges.push_stack();
26 Naming_heap.ConstPosHeap.LocalChanges.push_stack();
28 Decl_heap.Funs.LocalChanges.push_stack();
29 Decl_heap.Constructors.LocalChanges.push_stack();
30 Decl_heap.Props.LocalChanges.push_stack();
31 Decl_heap.StaticProps.LocalChanges.push_stack();
32 Decl_heap.Methods.LocalChanges.push_stack();
33 Decl_heap.StaticMethods.LocalChanges.push_stack();
34 Decl_heap.Classes.LocalChanges.push_stack();
35 Decl_heap.Typedefs.LocalChanges.push_stack();
36 Decl_heap.GConsts.LocalChanges.push_stack();
39 let revert_local_changes () =
40 Errors.set_allow_errors_in_default_path false;
41 SharedMem.allow_hashtable_writes_by_current_process true;
42 Fixmes.HH_FIXMES.LocalChanges.pop_stack();
43 Fixmes.DECL_HH_FIXMES.LocalChanges.pop_stack();
44 File_heap.FileHeap.LocalChanges.pop_stack();
45 Parser_heap.ParserHeap.LocalChanges.pop_stack();
47 Ide_parser_cache.deactivate ();
49 Naming_heap.FunPosHeap.LocalChanges.pop_stack();
50 Naming_heap.FunCanonHeap.LocalChanges.pop_stack();
51 Naming_heap.TypeIdHeap.LocalChanges.pop_stack();
52 Naming_heap.TypeCanonHeap.LocalChanges.pop_stack();
53 Naming_heap.ConstPosHeap.LocalChanges.pop_stack();
55 Decl_heap.Funs.LocalChanges.pop_stack();
56 Decl_heap.Constructors.LocalChanges.pop_stack();
57 Decl_heap.Props.LocalChanges.pop_stack();
58 Decl_heap.StaticProps.LocalChanges.pop_stack();
59 Decl_heap.Methods.LocalChanges.pop_stack();
60 Decl_heap.StaticMethods.LocalChanges.pop_stack();
61 Decl_heap.Classes.LocalChanges.pop_stack();
62 Decl_heap.Typedefs.LocalChanges.pop_stack();
63 Decl_heap.GConsts.LocalChanges.pop_stack();
65 SharedMem.invalidate_caches ();
68 (** Surrounds f() with make and revert, but resilient to f throwing. Reraises
69 * the exception thrown and ensures revert is always done. *)
70 let make_then_revert_local_changes f () =
71 make_local_changes ();
72 let result = try f () with
73 | e ->
74 revert_local_changes ();
75 raise e
77 revert_local_changes ();
78 result
80 let path = Relative_path.default
82 let declare_and_check_ast ?(path=path) ?content ~make_ast ~f tcopt =
83 let tcopt = TypecheckerOptions.make_permissive tcopt in
84 Autocomplete.auto_complete := false;
85 Errors.do_ @@ make_then_revert_local_changes begin fun () ->
86 Fixmes.HH_FIXMES.(remove_batch @@ KeySet.singleton path);
87 Fixmes.DECL_HH_FIXMES.(remove_batch @@ KeySet.singleton path);
88 let ast = make_ast () in
89 let funs, classes, typedefs, consts =
90 List.fold_left ast ~f:begin fun (funs, classes, typedefs, consts) def ->
91 match def with
92 | Ast.Fun { Ast.f_name; _ } ->
93 (FileInfo.pos_full f_name)::funs, classes, typedefs, consts
94 | Ast.Class { Ast.c_name; _ } ->
95 funs, (FileInfo.pos_full c_name)::classes, typedefs, consts
96 | Ast.Typedef { Ast.t_id; _ } ->
97 funs, classes, (FileInfo.pos_full t_id)::typedefs, consts
98 | Ast.Constant { Ast.cst_name; _ } ->
99 funs, classes, typedefs, (FileInfo.pos_full cst_name)::consts
100 | _ -> funs, classes, typedefs, consts
101 end ~init:([], [], [], []) in
103 let file_info = { FileInfo.empty_t with
104 FileInfo.funs; classes; typedefs; consts;
105 } in
106 let { FileInfo.n_funs; n_classes; n_types; n_consts; } =
107 FileInfo.simplify file_info in
108 Parser_heap.ParserHeap.add path (ast, Parser_heap.Full);
109 NamingGlobal.remove_decls
110 ~funs:n_funs
111 ~classes:n_classes
112 ~typedefs:n_types
113 ~consts:n_consts;
114 NamingGlobal.make_env tcopt ~funs ~classes ~typedefs ~consts;
116 (* Decl is not necessary to run typing, since typing would get
117 * whatever it needs using lazy decl, but we run it anyway in order to
118 * ensure that hooks attached to decl phase are executed. *)
119 Decl.name_and_declare_types_program tcopt ast;
121 let make_tast () =
122 let nast = Naming.program tcopt ast in
123 Typing.nast_to_tast tcopt nast
126 let tast = match content with
127 | None -> make_tast ()
128 | Some content -> Ide_tast_cache.get path content make_tast
130 f path file_info tast
134 (* This will parse, declare and check all functions and classes in content
135 * buffer.
137 * Declaring will overwrite definitions on shared heap, so before doing this,
138 * the function will also "shelve" them (see functions above and
139 * SharedMem.S.shelve_batch) - after working with local content is done,
140 * original definitions can (and should) be restored using "unshelve".
142 let declare_and_check ?(path=path) content ~f tcopt =
143 let make_ast () =
144 if Ide_parser_cache.is_enabled () then
145 (Ide_parser_cache.get_ast tcopt path content).Parser_return.ast
146 else
147 (* We need to fail open since IDE services need to be able to run over
148 malformed files. *)
149 (Full_fidelity_ast.defensive_program
150 ~fail_open:true
151 ~keep_errors:true
152 ~quick:false
153 tcopt
154 path
155 content
156 ).Parser_return.ast
159 declare_and_check_ast ~make_ast ~f ~path ~content tcopt
160 with Decl_class.Decl_heap_elems_bug -> begin
161 Hh_logger.log "%s" content;
162 Exit_status.(exit Decl_heap_elems_bug)
165 let get_errors path content tcopt =
166 fst (declare_and_check content tcopt ~f:(fun _ _ _ -> ()) ~path)
168 let declare_and_check content ~f tcopt = snd (declare_and_check content ~f tcopt)
170 let recheck tcopt filetuple_l =
171 SharedMem.invalidate_caches();
172 List.map filetuple_l begin fun (fn, defs) ->
173 fn, fst @@ Typing_check_utils.type_file tcopt fn defs
176 let check_file_input tcopt files_info fi =
177 match fi with
178 | ServerCommandTypes.FileContent content ->
179 declare_and_check content ~f:(fun path _ tast -> path, tast) tcopt
180 | ServerCommandTypes.FileName fn ->
181 let path = Relative_path.create Relative_path.Root fn in
182 match Relative_path.Map.get files_info path with
183 | Some fileinfo ->
184 let wrapper = if Ide_parser_cache.is_enabled () then
185 (* Protect shared memory with local changes when using Ide_parser_cache *)
186 fun f -> make_then_revert_local_changes f ()
187 else
188 fun f -> f ()
190 wrapper (fun () -> List.hd_exn (recheck tcopt [(path, fileinfo)]))
191 | None -> path, []
193 let check_fileinfo tcopt path fileinfo =
194 let (_path, tast) = List.hd_exn (recheck tcopt [(path, fileinfo)]) in
195 tast
197 let check_ast tcopt ast =
198 snd @@ declare_and_check_ast ~make_ast:(fun () -> ast) ~f:(fun _ _ tast -> tast) tcopt