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 open ServerCommandTypes
14 let remove_dead_warning name
=
15 "hh_server was started without '--no-load', which is required when removing dead "
18 ^
"Please run 'hh_client restart --no-load' to restart it."
20 let take_max_errors max_errors error_list
=
23 let (error_list
, dropped_errors
) = List.split_n error_list max_errors
in
24 (error_list
, List.length dropped_errors
)
25 | None
-> (error_list
, 0)
27 let single_ctx env path file_input
=
30 | ServerCommandTypes.FileName path
-> Sys_utils.cat path
31 | ServerCommandTypes.FileContent
contents -> contents
33 let ctx = Provider_utils.ctx_from_server_env env
in
34 Provider_context.add_or_overwrite_entry_contents ~
ctx ~path ~
contents
36 let single_ctx_path env path
=
39 (Relative_path.create_detect_prefix path
)
40 (ServerCommandTypes.FileName path
)
42 let log_check_response env
=
43 HackEventLogger.check_response
44 (Errors.get_error_list env
.errorl
45 |> List.map ~f
:(fun { User_error.code
; _
} -> code
))
47 (* Might raise {!Naming_table.File_info_not_found} *)
48 let handle : type a
. genv
-> env
-> is_stale
:bool -> a t
-> env
* a
=
49 fun genv env ~is_stale
-> function
50 | STATUS
{ max_errors
; _
} ->
51 log_check_response env
;
52 let error_list = Errors.sort_and_finalize env
.errorl
in
53 let (error_list, dropped_count
) = take_max_errors max_errors
error_list in
60 let last_recheck_stats =
61 match env
.ServerEnv.last_recheck_loop_stats_for_actual_work
with
63 | Some recheck_stats
->
65 (ServerEnv.RecheckLoopStats.to_user_telemetry recheck_stats
66 |> Telemetry.string_ ~key
:"init_id" ~
value:env
.init_env
.init_id
)
69 { Server_status.liveness; error_list; dropped_count
; last_recheck_stats }
72 { file_names
; max_errors
; preexisting_warnings
; return_expanded_tast
} ->
73 let ctx = Provider_utils.ctx_from_server_env env
in
74 let (errors
, tasts
) = ServerStatusSingle.go file_names
ctx in
77 |> ServerTypeCheck.filter_out_mergebase_warnings env ~preexisting_warnings
78 |> Errors.get_sorted_error_list
79 |> List.map ~f
:User_error.to_absolute
80 |> take_max_errors max_errors
82 (* Unforced lazy values are closures which make serialization over RPC fail. *)
84 if return_expanded_tast
then
86 (Relative_path.Map.map
89 (Tast_with_dynamic.map ~f
:(fun tast
->
91 |> Tast_expand.expand_program
ctx
92 |> Tast.force_lazy_values
)))
96 (env
, (errors, tasts))
97 | INFER_TYPE
(file_input
, line
, column
) ->
100 | FileName fn
-> Relative_path.create_detect_prefix fn
101 | FileContent _
-> Relative_path.create_detect_prefix
""
103 let (ctx, entry
) = single_ctx env
path file_input
in
105 Provider_utils.respect_but_quarantine_unsaved_changes ~
ctx ~f
:(fun () ->
106 ServerInferType.go_ctx ~
ctx ~entry ~line ~column
)
109 | INFER_TYPE_BATCH positions
->
110 (env
, ServerInferTypeBatch.go genv
.workers positions env
)
111 | IS_SUBTYPE stdin
-> (env
, ServerIsSubtype.check genv
.workers stdin env
)
112 | TAST_HOLES
(file_input
, hole_filter
) ->
114 match file_input
with
115 | FileName fn
-> Relative_path.create_detect_prefix fn
116 | FileContent _
-> Relative_path.create_detect_prefix
""
118 let (ctx, entry
) = single_ctx env
path file_input
in
120 Provider_utils.respect_but_quarantine_unsaved_changes ~
ctx ~f
:(fun () ->
121 ServerCollectTastHoles.go_ctx ~
ctx ~entry ~hole_filter
)
124 | TAST_HOLES_BATCH files
->
125 (env
, ServerTastHolesBatch.go genv
.workers files env
)
126 | INFER_TYPE_ERROR
(file_input
, line
, column
) ->
128 match file_input
with
129 | FileName fn
-> Relative_path.create_detect_prefix fn
130 | FileContent _
-> Relative_path.create_detect_prefix
""
132 let (ctx, entry
) = single_ctx env
path file_input
in
134 Provider_utils.respect_but_quarantine_unsaved_changes ~
ctx ~f
:(fun () ->
135 ServerInferTypeError.go_ctx ~
ctx ~entry ~line ~column
)
138 (* TODO: edit this to look for classname *)
139 | XHP_AUTOCOMPLETE_SNIPPET cls
->
140 let ctx = Provider_utils.ctx_from_server_env env
in
141 let tast_env = Tast_env.empty
ctx in
142 let cls = Utils.add_ns
cls in
143 (env
, AutocompleteService.get_snippet_for_xhp_classname
cls ctx tast_env)
144 | IDENTIFY_SYMBOL arg
->
145 let module SO
= SymbolOccurrence
in
146 let ctx = Provider_utils.ctx_from_server_env env
in
147 let get_def_opt type_ name
=
148 ServerSymbolDefinition.go
151 SO.{ type_
; name
; is_declaration
= false; pos
= Pos.none
}
153 |> List.map ~f
:SymbolDefinition.to_absolute
155 let arg = Str.split
(Str.regexp
"::") arg in
156 (* The following are all the different named entities I could think of in Hack. *)
159 | [c_name
; member
] ->
160 let c_name = Utils.add_ns
c_name in
163 get_def_opt (SO.Method
(SO.ClassName
c_name, member
)) "";
164 get_def_opt (SO.Property
(SO.ClassName
c_name, member
)) "";
165 get_def_opt (SO.XhpLiteralAttr
(c_name, member
)) "";
166 get_def_opt (SO.ClassConst
(SO.ClassName
c_name, member
)) "";
167 get_def_opt (SO.Typeconst
(c_name, member
)) "";
170 let name = Utils.add_ns
name in
173 get_def_opt (SO.Class
SO.ClassId
) name;
174 (* SO.Record and Class find the same things *)
175 get_def_opt SO.Function
name;
176 get_def_opt SO.GConst
name;
181 | IDENTIFY_FUNCTION
(filename
, file_input
, line
, column
) ->
183 single_ctx env
(Relative_path.create_detect_prefix filename
) file_input
186 Provider_utils.respect_but_quarantine_unsaved_changes ~
ctx ~f
:(fun () ->
187 ServerIdentifyFunction.go_quarantined_absolute
194 | METHOD_JUMP
(class_
, filter
, find_children
) ->
195 Printf.printf
"%s" class_
;
196 let ctx = Provider_utils.ctx_from_server_env env
in
198 MethodJumps.get_inheritance
205 | METHOD_JUMP_BATCH
(classes
, filter
) ->
206 let ctx = Provider_utils.ctx_from_server_env env
in
207 (env
, ServerMethodJumpsBatch.go
ctx genv
.workers classes filter
)
208 | FIND_REFS find_refs_action
->
209 let ctx = Provider_utils.ctx_from_server_env env
in
210 Provider_utils.respect_but_quarantine_unsaved_changes ~
ctx ~f
:(fun () ->
211 let open Done_or_retry
in
212 let include_defs = false in
222 |> map_env ~f
:to_absolute
))
223 | GO_TO_IMPL go_to_impl_action
->
225 ServerGoToImpl.go ~action
:go_to_impl_action ~genv ~env
226 |> map_env ~f
:ServerFindRefs.to_absolute
)
227 | IDE_FIND_REFS_BY_SYMBOL
229 FindRefsWireFormat.CliArgs.symbol_name
= _
;
235 List.map hint_suffixes ~f
:(fun suffix
-> Relative_path.from_root ~suffix
)
237 let ctx = Provider_utils.ctx_from_server_env env
in
238 Provider_utils.respect_but_quarantine_unsaved_changes ~
ctx ~f
:(fun () ->
239 let open Done_or_retry
in
240 let include_defs = false in
242 ~f
:ServerFindRefs.to_absolute
251 | IDE_GO_TO_IMPL_BY_SYMBOL
252 { FindRefsWireFormat.CliArgs.symbol_name
= _
; action
; _
} ->
253 let ctx = Provider_utils.ctx_from_server_env env
in
254 Provider_utils.respect_but_quarantine_unsaved_changes ~
ctx ~f
:(fun () ->
255 let open Done_or_retry
in
257 ~f
:ServerFindRefs.to_absolute
258 (ServerGoToImpl.go ~action ~genv ~env
))
259 | RENAME rename_action
->
260 let ctx = Provider_utils.ctx_from_server_env env
in
261 Provider_utils.respect_but_quarantine_unsaved_changes ~
ctx ~f
:(fun () ->
262 let definition_for_wrapper =
263 match rename_action
with
264 | ServerRenameTypes.ClassRename _
265 | ServerRenameTypes.ClassConstRename _
266 | ServerRenameTypes.LocalVarRename _
->
268 | ServerRenameTypes.MethodRename
{ class_name
; old_name
; _
} ->
269 ServerSymbolDefinition.go
273 SymbolOccurrence.name = "unused for lookup";
275 SymbolOccurrence.Method
276 ( SymbolOccurrence.ClassName
(Utils.add_ns class_name
),
278 is_declaration
= false;
281 | ServerRenameTypes.FunctionRename
{ old_name
; _
} ->
282 ServerSymbolDefinition.go
286 SymbolOccurrence.name = Utils.add_ns old_name
;
287 type_
= SymbolOccurrence.Function
;
288 is_declaration
= false;
292 ServerRename.go
ctx rename_action genv env ~
definition_for_wrapper)
293 | IDE_RENAME_BY_SYMBOL
(action
, new_name
, symbol_definition
) ->
294 let ctx = Provider_utils.ctx_from_server_env env
in
295 Provider_utils.respect_but_quarantine_unsaved_changes ~
ctx ~f
:(fun () ->
296 let open Done_or_retry
in
298 ServerRename.go_ide_with_find_refs_action
300 ~find_refs_action
:action
306 | Error e
-> (env
, Done
(Error e
))
307 | Ok r
-> map_env r ~f
:(fun x
-> Ok x
))
308 | REMOVE_DEAD_FIXMES codes
->
309 if genv
.ServerEnv.options
|> ServerArgs.no_load
then (
310 log_check_response env
;
311 (env
, `Ok
(ServerRename.get_fixme_patches codes env
))
313 (env
, `Error
(remove_dead_warning "fixme"))
314 | REMOVE_DEAD_UNSAFE_CASTS
->
315 if genv
.ServerEnv.options
|> ServerArgs.no_load
then (
316 log_check_response env
;
317 (env
, `Ok
(ServerRename.get_dead_unsafe_cast_patches env
))
319 (env
, `Error
(remove_dead_warning "unsafe cast"))
320 | REWRITE_LAMBDA_PARAMETERS files
->
321 let ctx = Provider_utils.ctx_from_server_env env
in
322 (env
, ServerRename.get_lambda_parameter_rewrite_patches
ctx files
)
323 | DUMP_SYMBOL_INFO file_list
->
324 (env
, SymbolInfoService.go genv
.workers file_list env
)
325 | IN_MEMORY_DEP_TABLE_SIZE
->
326 (* TODO(hverr): Clean up 32-bit/migrate *)
328 | SAVE_NAMING filename
->
329 (env
, SaveStateService.go_naming env
.naming_table filename
)
330 | SAVE_STATE
(filename
, gen_saved_ignore_type_errors
) ->
331 if Errors.is_empty env
.errorl
|| gen_saved_ignore_type_errors
then
332 (env
, SaveStateService.go env filename
)
334 (env
, Error
"There are typecheck errors; cannot generate saved state.")
336 (* This is for the client to know "is the server available to process requests?" *)
339 let ctx = Provider_utils.ctx_from_server_env env
in
340 (env
, ServerLint.go genv
ctx fnl
)
341 | LINT_STDIN
{ filename
; contents } ->
342 let ctx = Provider_utils.ctx_from_server_env env
in
343 (env
, ServerLint.go_stdin
ctx ~filename ~
contents)
345 let ctx = Provider_utils.ctx_from_server_env env
in
346 (env
, ServerLint.lint_all genv
ctx code
)
347 | STATS
-> (env
, Stats.get_stats
())
348 | FORMAT
(content
, from
, to_
) ->
349 let legacy_format_options =
350 { Lsp.DocumentFormatting.tabSize
= 2; insertSpaces
= true }
352 (env
, ServerFormat.go ~content from to_
legacy_format_options)
353 | DUMP_FULL_FIDELITY_PARSE file
-> (env
, FullFidelityParseService.go file
)
354 | RAGE
-> (env
, ServerRage.go genv env
)
355 | CST_SEARCH
{ sort_results
; input
; files_to_search
} -> begin
357 (env
, CstSearchService.go genv env ~sort_results ~files_to_search input
)
359 | MultiThreadedCall.Coalesced_failures failures
->
362 |> List.map ~f
:WorkerController.failure_to_string
363 |> String.concat ~sep
:"\n"
368 "Worker failures - check the logs for more details:\n%s\n"
371 let e = Exception.wrap exn
in
372 (env
, Error
(Exception.to_string
e))
374 | NO_PRECHECKED_FILES
-> (ServerPrecheckedFiles.expand_all env
, ())
375 | FUN_DEPS_BATCH positions
->
376 (env
, ServerFunDepsBatch.go genv
.workers positions env
)
377 | LIST_FILES_WITH_ERRORS
-> (env
, ServerEnv.list_files env
)
378 | FILE_DEPENDENTS filenames
->
379 let files = ServerFileDependents.go genv env filenames
in
381 | IDENTIFY_TYPES
(labelled_file
, line
, column
) ->
382 let (path, file_input
) =
383 ServerCommandTypesUtils.extract_labelled_file labelled_file
385 let (ctx, entry
) = single_ctx env
path file_input
in
387 ServerTypeDefinition.go_quarantined ~
ctx ~entry ~line ~column
392 Hh_logger.Level.set_min_level
Hh_logger.Level.Debug
394 Hh_logger.Level.set_min_level
395 genv
.local_config
.ServerLocalConfig.min_log_level
;
397 | DEPS_OUT_BATCH positions
->
398 let ctx = Provider_utils.ctx_from_server_env env
in
399 (env
, ServerDepsOutBatch.go
ctx positions
)
400 | DEPS_IN_BATCH positions
->
401 let ctx = Provider_utils.ctx_from_server_env env
in
402 (env
, ServerDepsInBatch.go ~
ctx ~genv ~env positions
)