2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
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
74 revert_local_changes ();
77 revert_local_changes ();
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
->
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
;
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
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;
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
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 =
144 if Ide_parser_cache.is_enabled
() then
145 (Ide_parser_cache.get_ast
tcopt path content
).Parser_return.ast
147 (* We need to fail open since IDE services need to be able to run over
149 (Full_fidelity_ast.defensive_program
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
=
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
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
()
190 wrapper (fun () -> List.hd_exn
(recheck tcopt [(path, fileinfo
)]))
193 let check_fileinfo tcopt path fileinfo
=
194 let (_path
, tast) = List.hd_exn
(recheck tcopt [(path, fileinfo
)]) in
197 let check_ast tcopt ast =
198 snd
@@ declare_and_check_ast ~
make_ast:(fun () -> ast) ~f
:(fun _ _
tast -> tast) tcopt