Option to disallow return-by-ref
[hiphop-php.git] / hphp / hack / src / server / serverConfig.ml
blob3d288ce20675bdc4dc4cc8d8cac186b6b627af18
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 (**
11 * Parses and gathers information from the .hhconfig in the repo.
14 open Hh_core
15 open Config_file.Getters
16 open Reordered_argument_collections
18 type t = {
19 version : string option;
21 load_script : Path.t option;
22 load_script_timeout : int; (* in seconds *)
24 (** Script to call to prefetch a saved state. Expected invocation is:
25 * state_prefetcher_script <svn revision number>
27 * Which is expected to put a saved state into the correct place which the
28 * above load_script will be able to use.
30 state_prefetcher_script : Path.t option;
32 (* Configures only the workers. Workers can have more relaxed GC configs as
33 * they are short-lived processes *)
34 gc_control : Gc.control;
35 sharedmem_config : SharedMem.config;
36 tc_options : TypecheckerOptions.t;
37 parser_options : ParserOptions.t;
38 formatter_override : Path.t option;
39 config_hash : string option;
40 (* A list of regexps for paths to ignore *)
41 ignored_paths : string list;
42 (* A list of extra paths to search for declarations *)
43 extra_paths : Path.t list;
45 (* what version of the typechecker is targetted *)
46 forward_compatibility_level : ForwardCompatibilityLevel.t;
49 let filename = Relative_path.from_root Config_file.file_path_relative_to_repo_root
51 let is_compatible c1 c2 =
52 (* This comparison can eventually be made more complex; we may not always
53 * need to restart hh_server, e.g. changing the path to the load script
54 * is immaterial*)
55 c1 = c2
57 let make_gc_control config =
58 let {Gc.minor_heap_size; space_overhead; _} = GlobalConfig.gc_control in
59 let minor_heap_size =
60 int_ "gc_minor_heap_size" ~default:minor_heap_size config in
61 let space_overhead =
62 int_ "gc_space_overhead" ~default:space_overhead config in
63 { GlobalConfig.gc_control with Gc.minor_heap_size; space_overhead; }
65 let make_sharedmem_config config options local_config =
66 let { SharedMem.
67 global_size;
68 heap_size;
69 shm_min_avail;
71 } = GlobalConfig.default_sharedmem_config in
72 let shm_dirs = local_config.ServerLocalConfig.shm_dirs in
74 let global_size = int_ "sharedmem_global_size" ~default:global_size config in
75 let heap_size = int_ "sharedmem_heap_size" ~default:heap_size config in
76 let dep_table_pow = int_ "sharedmem_dep_table_pow" ~default:17 config in
77 let hash_table_pow = int_ "sharedmem_hash_table_pow" ~default:18 config in
78 let log_level = int_ "sharedmem_log_level" ~default:0 config in
79 let shm_dirs = string_list
80 ~delim:(Str.regexp ",")
81 "sharedmem_dirs"
82 ~default:shm_dirs
83 config in
84 let shm_min_avail =
85 int_ "sharedmem_minimum_available" ~default:shm_min_avail config in
87 let global_size, heap_size, dep_table_pow, hash_table_pow =
88 match ServerArgs.ai_mode options with
89 | None -> global_size, heap_size, dep_table_pow, hash_table_pow
90 | Some ai_options ->
91 Ai.modify_shared_mem_sizes
92 global_size
93 heap_size
94 dep_table_pow
95 hash_table_pow
96 ai_options in
98 { SharedMem.
99 global_size;
100 heap_size;
101 dep_table_pow;
102 hash_table_pow;
103 log_level;
104 shm_dirs;
105 shm_min_avail;
108 let config_list_regexp = (Str.regexp "[, \t]+")
110 let config_user_attributes config =
111 match SMap.get config "user_attributes" with
112 | None -> None
113 | Some s ->
114 let custom_attrs = Str.split config_list_regexp s in
115 Some (List.fold_left custom_attrs ~f:SSet.add ~init:SSet.empty)
117 let process_experimental sl =
118 match List.map sl String.lowercase_ascii with
119 | ["false"] -> SSet.empty
120 | ["true"] -> TypecheckerOptions.experimental_all
121 | features -> List.fold_left features ~f:SSet.add ~init:SSet.empty
123 let config_experimental_tc_features config =
124 match SMap.get config "enable_experimental_tc_features" with
125 | None -> SSet.empty
126 | Some s ->
127 let sl = Str.split config_list_regexp s in
128 process_experimental sl
130 let process_migration_flags sl =
131 match sl with
132 | ["false"] -> SSet.empty
133 | ["true"] -> TypecheckerOptions.migration_flags_all
134 | flags ->
135 begin
136 List.iter flags ~f:(fun s ->
137 if not (SSet.mem TypecheckerOptions.migration_flags_all s)
138 then failwith ("invalid migration flag: " ^ s));
139 List.fold_left flags ~f:SSet.add ~init:SSet.empty
142 let config_tc_migration_flags config =
143 SMap.get config "enable_tc_migration_flags"
144 |> Option.value_map ~f:(Str.split config_list_regexp) ~default:[]
145 |> List.map ~f:String.lowercase_ascii
146 |> process_migration_flags
149 let convert_ignored_paths str =
150 let json = Hh_json.json_of_string ~strict:true str in
151 let l = Hh_json.get_array_exn json in
152 List.filter_map ~f:(fun s ->
153 match s with
154 | Hh_json.JSON_String path -> Some path
155 | _ -> None
159 let process_ignored_paths config =
160 SMap.get config "ignored_paths"
161 |> Option.value_map ~f:convert_ignored_paths ~default:[]
163 let process_forward_compatibility_level config =
164 SMap.get config "forward_compatibility_level"
165 |> Option.value_map ~f:ForwardCompatibilityLevel.from_string ~default:ForwardCompatibilityLevel.HEAD
167 let maybe_relative_path fn =
168 (* Note: this is not the same as calling realpath; the cwd is not
169 * necessarily the same as hh_server's root!!! *)
170 Path.make begin
171 if Filename.is_relative fn
172 then Relative_path.(to_absolute (from_root fn))
173 else fn
176 let process_extra_paths config =
177 match SMap.get config "extra_paths" with
178 | Some s -> Str.split config_list_regexp s |> List.map ~f:maybe_relative_path
179 | _ -> []
181 let extract_auto_namespace_element ns_map element =
182 match element with
183 | (source, Hh_json.JSON_String target) ->
184 (source, target)::ns_map
185 | _ -> ns_map (* This means the JSON we received is incorrect *)
187 let convert_auto_namespace_to_map map =
188 let json = Hh_json.json_of_string ~strict:true map in
189 let pairs = Hh_json.get_object_exn json in
190 (* We do a fold instead of a map to filter
191 * out the incorrect entrie as we look at each item *)
192 List.fold_left ~init:[] ~f:extract_auto_namespace_element pairs
194 let prepare_auto_namespace_map config =
195 Option.value_map
196 (SMap.get config "auto_namespace_map")
197 ~default:[]
198 ~f:convert_auto_namespace_to_map
200 let prepare_ignored_fixme_codes config =
201 SMap.get config "ignored_fixme_codes"
202 |> Option.value_map ~f:(Str.split config_list_regexp) ~default:[]
203 |> List.map ~f:int_of_string
204 |> List.fold_right ~init:Errors.default_ignored_fixme_codes ~f:ISet.add
206 let load config_filename options =
207 let config_hash, config = Config_file.parse (Relative_path.to_absolute config_filename) in
208 let local_config = ServerLocalConfig.load ~silent:false in
209 let version = SMap.get config "version" in
210 let ignored_paths = process_ignored_paths config in
211 let extra_paths = process_extra_paths config in
212 let load_script =
213 Option.map (SMap.get config "load_script") maybe_relative_path in
214 (* Since we use the unix alarm() for our timeouts, a timeout value of 0 means
215 * to wait indefinitely *)
216 let load_script_timeout = int_ "load_script_timeout" ~default:0 config in
217 let state_prefetcher_script =
218 Option.map (SMap.get config "state_prefetcher_script") maybe_relative_path in
219 let formatter_override =
220 Option.map (SMap.get config "formatter_override") maybe_relative_path in
221 let forward_compat_level = process_forward_compatibility_level config in
222 let global_opts = GlobalOptions.make
223 (bool_ "assume_php" ~default:true config)
224 (bool_ "safe_array" ~default:true config)
225 (bool_ "safe_vector_array" ~default:true config)
226 (bool_ "deregister_php_stdlib" ~default:false config)
227 (* Although it's locally configured, the use_full_fidelity_parser flag needs
228 * to end up in the parser options to reach all consumers of it.
230 local_config.ServerLocalConfig.use_full_fidelity_parser
231 (config_user_attributes config)
232 (config_experimental_tc_features config)
233 (config_tc_migration_flags config)
234 false (* typechecker dynamic_view option to set Tany as Tdynamic, off by default *)
235 (bool_ "disallow_unsafe_comparisons" ~default:false config)
236 (bool_ "disallow_non_arraykey_keys" ~default:false config)
237 (bool_ "disallow_array_as_tuple" ~default:false config)
238 (prepare_auto_namespace_map config)
239 (bool_ "disallow_ambiguous_lambda" ~default:false config)
240 (bool_ "disallow_array_typehint" ~default:false config)
241 (bool_ "disallow_array_literal" ~default:false config)
242 (bool_ "disallow_return_by_ref" ~default:false config)
243 (bool_ "language_feature_logging" ~default:false config)
244 (bool_ "unsafe_rx" ~default:true config)
245 (bool_ "disallow_elvis_space" ~default:false config)
246 (prepare_ignored_fixme_codes config)
247 forward_compat_level
249 Errors.ignored_fixme_codes :=
250 (GlobalOptions.ignored_fixme_codes global_opts);
252 version = version;
253 load_script = load_script;
254 load_script_timeout = load_script_timeout;
255 state_prefetcher_script = state_prefetcher_script;
256 gc_control = make_gc_control config;
257 sharedmem_config = make_sharedmem_config config options local_config;
258 tc_options = global_opts;
259 parser_options = global_opts;
260 formatter_override = formatter_override;
261 config_hash = config_hash;
262 ignored_paths = ignored_paths;
263 extra_paths = extra_paths;
264 forward_compatibility_level = forward_compat_level;
265 }, local_config
267 (* useful in testing code *)
268 let default_config = {
269 version = None;
270 load_script = None;
271 load_script_timeout = 0;
272 state_prefetcher_script = None;
273 gc_control = GlobalConfig.gc_control;
274 sharedmem_config = GlobalConfig.default_sharedmem_config;
275 tc_options = TypecheckerOptions.default;
276 parser_options = ParserOptions.default;
277 formatter_override = None;
278 config_hash = None;
279 ignored_paths = [];
280 extra_paths = [];
281 forward_compatibility_level = ForwardCompatibilityLevel.HEAD;
284 let set_parser_options config popt = { config with parser_options = popt }
285 let set_tc_options config tcopt = { config with tc_options = tcopt }
286 let gc_control config = config.gc_control
287 let sharedmem_config config = config.sharedmem_config
288 let state_prefetcher_script config = config.state_prefetcher_script
289 let typechecker_options config = config.tc_options
290 let parser_options config = config.parser_options
291 let formatter_override config = config.formatter_override
292 let config_hash config = config.config_hash
293 let ignored_paths config = config.ignored_paths
294 let extra_paths config = config.extra_paths
295 let version config = config.version
296 let forward_compatibility_level config = config.forward_compatibility_level