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.
13 (** When we get a Class occurrence and a Method occurrence, that means that the
14 user is hovering over an invocation of the constructor, and would therefore only
15 want to see information about the constructor, rather than getting both the
16 class and constructor back in the hover. *)
17 let filter_class_and_constructor results
=
18 let result_is_constructor result
=
19 SymbolOccurrence.is_constructor
(fst result
)
21 let result_is_class result
= SymbolOccurrence.is_class
(fst result
) in
22 let has_class = List.exists results ~f
:result_is_class in
23 let has_constructor = List.exists results ~f
:result_is_constructor in
24 if has_class && has_constructor then
25 List.filter results ~f
:result_is_constructor |> List.map ~f
:snd
27 results
|> List.map ~f
:snd
29 let make_hover_doc_block ctx entry occurrence def_opt
=
32 let base_class_name = SymbolOccurrence.enclosing_class occurrence
in
33 ServerDocblockAt.go_comments_for_symbol_ctx
41 let make_hover_const_definition entry def_opt
=
46 ~content
:(Provider_context.read_file_contents_exn entry
)
47 def
.SymbolDefinition.span
;
51 let make_hover_full_name env_and_ty occurrence def_opt
=
56 | Some def
-> def
.SymbolDefinition.full_name
57 | None
-> occurrence
.name
59 [Printf.sprintf
"Full name: `%s`" (Utils.strip_ns
name)]
62 match (occurrence
, env_and_ty
) with
63 | ({ type_
= Method _
; _
}, Some
(_
, _ty
)) -> found_it ()
64 | ( { type_
= Property _
| ClassConst _
| XhpLiteralAttr _
; _
},
70 (* Return a markdown description of built-in Hack attributes. *)
71 let make_hover_attr_docs name =
73 | "__AcceptDisposable" ->
75 "Allows passing values that implement `IDisposable` or `IAsyncDisposable`."
76 ^
" Normally these values cannot be passed to functions."
77 ^
"\n\nYou cannot save references to `__AcceptDisposable` parameters, to ensure they are disposed at the end of their using block.";
79 | "__ALWAYS_INLINE" ->
81 "Instructs HHVM to always inline this function."
82 ^
" Only used for testing HHVM."
83 ^
"\n\nSee also `__NEVER_INLINE`.";
85 | "__ConsistentConstruct" ->
87 "Requires all child classes to have the same constructor signature. "
88 ^
" This allows `new static(...)` and `new $the_class_name(...)`.";
92 "Marks a class or property as immutable."
93 ^
" When applied to a class, all the properties are considered `__Const`."
94 ^
" `__Const` properties can only be set in the constructor.";
98 "Mark a function/method as deprecated. "
99 ^
" The type checker will show an error at call sites, and a runtime warning is logged if this function/method is called."
100 ^
"\n\nThe optional second argument specifies a rate limit for warning logs."
101 ^
" If the rate limit is 100, a warning is only issued every 1/100 calls.";
103 | "__DynamicallyCallable" ->
105 "Allows this function/method to be called dynamically, based on a string of its name. "
106 ^
" HHVM will warn or error (depending on settings) on dynamic calls to functions without this attribute."
107 ^
"\n\nSee also `HH\\dynamic_fun()` and `HH\\dynamic_fun()`.";
109 | "__DynamicallyConstructible" ->
111 "Allows this class to be instantiated dynamically, based on a string of its name."
112 ^
" HHVM will warn or error (depending on settings) on dynamic instantiations without this attribute.";
116 "Ensures that this type is enforceable."
117 ^
" Enforceable types can be used with `is` and `as`."
118 ^
" This forbids usage of function types and erased (not reified) generics.";
122 "Execution of the program will start here."
123 ^
" This only applies in the first file executed, `__EntryPoint` in required or autoloaded files has no effect.";
127 "Requires callers to explicitly specify this type."
128 ^
"\n\nNormally Hack allows generics to be inferred at the call site.";
130 | "__HasReifiedParent" ->
132 "Marks a class as extending a class that uses reified generics."
133 ^
" This is an internal attribute used for byte compilation, and is banned in user code.";
137 "Marks this function can be constant-folded if all arguments are constants."
142 "Marks a property as late initialized."
143 ^
" Normally properties are required to be initialized in the constructor.";
147 "Marks this property as implicitly redeclared on all subclasses."
148 ^
" This ensures each subclass has its own value for the property.";
152 "Allows subclasses of final classes and overriding of final methods."
153 ^
" This is useful for writing mock classes."
154 ^
"\n\nYou cannot use this to subclass `vec`, `keyset`, `dict`, `Vector`, `Map` or `Set`.";
158 "Cache the return values from this function/method."
159 ^
" Calls with the same arguments will return the cached value."
160 ^
"\n\nCaching is per-request and shared between subclasses (see also `__MemoizeLSB`).";
164 "Cache the return values from this method."
165 ^
" Calls with the same arguments will return the cached value."
166 ^
"\n\nCaching is per-request and has Late Static Binding, so subclasses do not share the cache.";
170 "Declares a native function."
171 ^
" This declares the signature, the implementation will be in an HHVM extension (usually C++).";
175 "Associates this class with a native data type (usually a C++ class)."
176 ^
" When instantiating this class, the corresponding native object will also be allocated.";
180 "Ensures the class can be constructed."
181 ^
"\n\nThis forbids abstract classes, and ensures that the constructor has a consistent signature."
182 ^
" Classes must use `__ConsistentConstruct` or be final.";
186 "Instructs hhbbc to never inline this trait into classes that use it."
187 ^
" Used for testing hhbbc optimizations.";
189 | "__NEVER_INLINE" ->
191 "Instructs HHVM to never inline this function."
192 ^
" Only used for testing HHVM."
193 ^
"\n\nSee also `__ALWAYS_INLINE`.";
195 | "__Override" -> ["Ensures there's a parent method being overridden."]
198 "Ignore this built-in function or class, so the type checker errors if code uses it."
199 ^
" This only applies to code in .hhi files by default, but can apply everywhere with `deregister_php_stdlib`.";
201 | "__ProvenanceSkipFrame" ->
203 "Don't track Hack arrays created by this function."
204 ^
" This is useful when migrating code from PHP arrays to Hack arrays.";
208 "Requires this type to be reifiable."
209 ^
" This bans PHP arrays (varray and darray).";
213 "Marks a function as taking reified generics."
214 ^
" This is an internal attribute used for byte compilation, and is banned in user code.";
216 | "__ReturnDisposable" ->
218 "Allows a function/method to return a value that implements `IDisposable` or `IAsyncDisposable`."
219 ^
" The function must return a fresh disposable value by either instantiating a class or "
220 ^
" returning a value from another method/function marked `__ReturnDisposable`.";
224 "Only the named classes can extend this class or interface."
225 ^
" Child classes may still be extended unless they are marked `final`.";
229 "A runtime type mismatch on this parameter/property will not throw a TypeError/Error."
230 ^
" This is useful for migrating partial code where you're unsure about the type."
231 ^
"\n\nThe type checker will ignore this attribute, so your code will still get type checked."
232 ^
" If the type is wrong at runtime, a warning will be logged and code execution will continue.";
236 "Ensures that incorrect reified types are a warning rather than error."
237 ^
"\n\nThis is intended to help gradually migrate code to reified types.";
241 let keyword_info (khi
: SymbolOccurrence.keyword_with_hover_docs
) : string =
242 let await_explanation =
243 "\n\nThis does not give you threads. Only one function is running at any point in time."
244 ^
" Instead, the runtime may switch to another function at an `await` expression, and come back to this function later."
245 ^
"\n\nThis allows data fetching (e.g. database requests) to happen in parallel."
249 | SymbolOccurrence.FinalOnClass
->
250 "A `final` class cannot be extended by other classes.\n\nTo restrict which classes can extend this, use `<<__Sealed()>>`."
251 | SymbolOccurrence.FinalOnMethod
->
252 "A `final` method cannot be overridden in child classes."
253 | SymbolOccurrence.AbstractOnClass
->
254 "An `abstract` class can only contain `static` methods and `abstract` instance methods.\n\n"
255 ^
"`abstract` classes cannot be instantiated directly. You can only use `new` on child classes that aren't `abstract`."
256 | SymbolOccurrence.AbstractOnMethod
->
257 "An `abstract` method has a signature but no body. Child classes must provide an implementation."
258 | SymbolOccurrence.ExtendsOnClass
->
259 "Extending a class allows your class to inherit methods from another class."
260 ^
"\n\nInheritance allows your class to:"
261 ^
"\n * Reuse methods from the parent class"
262 ^
"\n * Call `protected` methods on the parent class"
263 ^
"\n * Be passed as a parameter whenever an instance of the parent class is expected"
264 ^
"\n\nHack does not support multiple inheritance on classes. If you need to share functionality between"
265 ^
" unrelated classes, use traits."
266 | SymbolOccurrence.ExtendsOnInterface
->
267 "Extending an interface allows your interface to include methods from other interfaces."
268 ^
"\n\nAn interface can extend multiple interfaces."
269 | SymbolOccurrence.ReadonlyOnMethod
->
270 "A `readonly` method treats `$this` as `readonly`."
271 | SymbolOccurrence.ReadonlyOnExpression
272 | SymbolOccurrence.ReadonlyOnParameter
->
273 "A `readonly` value is a reference that cannot modify the underlying value."
274 | SymbolOccurrence.ReadonlyOnReturnType
->
275 "This function/method may return a `readonly` value."
276 | SymbolOccurrence.Async
->
277 "An `async` function can use `await` to get results from other `async` functions. You may still return plain values, e.g. `return 1;` is permitted in an `Awaitable<int>` function."
279 | SymbolOccurrence.AsyncBlock
->
280 "An `async` block is syntactic sugar for an `async` lambda that is immediately called."
282 ^
"\n$f = async { return 1; };"
283 ^
"\n// Equivalent to:"
284 ^
"\n$f = (async () ==> { return 1; })();"
286 ^
"\n\nThis is useful when building more complex async expressions."
289 ^
"\n $group_name = await async {"
290 ^
"\n return $group is null ? '' : await $group->genName();"
294 ^
"\n await gen_log_request();"
295 ^
"\n } catch (LogRequestFailed $_) {}"
299 | SymbolOccurrence.Await
->
300 "`await` waits for the result of an `Awaitable<_>` value."
302 | SymbolOccurrence.Concurrent
->
303 "`concurrent` allows you to `await` multiple values at once. This is similar to `Vec\\map_async`, but `concurrent` allows awaiting unrelated values of different types."
305 let make_hover_info ctx env_and_ty entry occurrence def_opt
=
309 match (occurrence
, env_and_ty
) with
310 | ({ name; _
}, None
) -> Utils.strip_hh_lib_ns
name
311 | ({ type_
= Method
(ClassName classname
, name); _
}, Some
(env
, ty
))
312 when String.equal
name Naming_special_names.Members.__construct
->
315 Decl_provider.get_class ctx classname
>>= fun c
->
316 fst
(Decl_provider.Class.construct c
) >>| fun elt
->
317 let ty = Lazy.force_val elt
.ce_type
in
318 Tast_env.print_ty_with_identity env
(DeclTy
ty) occurrence def_opt
)
321 match snippet_opt with
324 Tast_env.print_ty_with_identity env
(LoclTy
ty) occurrence def_opt
326 | (occurrence
, Some
(env
, ty)) ->
327 Tast_env.print_ty_with_identity env
(LoclTy
ty) occurrence def_opt
330 match occurrence
with
331 | { name; type_
= Attribute _
; _
} ->
334 make_hover_attr_docs name;
335 make_hover_doc_block ctx entry occurrence def_opt
;
337 | { type_
= GConst
; _
} ->
340 make_hover_doc_block ctx entry occurrence def_opt
;
341 make_hover_const_definition entry def_opt
;
343 | { type_
= Keyword info
; _
} -> [keyword_info info
]
347 make_hover_doc_block ctx entry occurrence def_opt
;
348 make_hover_full_name env_and_ty occurrence def_opt
;
352 { snippet; addendum; pos
= Some occurrence
.SymbolOccurrence.pos
}))
354 let make_hover_info_with_fallback results
=
357 (List.filter results ~f
:(fun (_
, _
, _
, occurrence
, _
) ->
358 SymbolOccurrence.is_class occurrence
))
361 ~f
:(fun (ctx
, env_and_ty
, entry
, occurrence
, def_opt
) ->
363 SymbolOccurrence.is_constructor occurrence
364 && List.is_empty
(make_hover_doc_block ctx entry occurrence def_opt
)
366 (* Case where constructor docblock is empty. *)
368 make_hover_info ctx env_and_ty entry occurrence def_opt
370 match class_fallback with
371 | Some
(ctx
, _
, entry
, class_occurrence
, def_opt
) ->
372 let fallback_doc_block =
373 make_hover_doc_block ctx entry class_occurrence def_opt
378 snippet = hover_info.snippet;
379 addendum = List.concat
[fallback_doc_block; hover_info.addendum];
380 pos
= hover_info.pos
;
382 | None
-> (occurrence
, hover_info)
384 (occurrence
, make_hover_info ctx env_and_ty entry occurrence def_opt
))
388 ~
(ctx
: Provider_context.t
)
389 ~
(entry
: Provider_context.entry
)
391 ~
(column
: int) : HoverService.result
=
393 ServerIdentifyFunction.go_quarantined ~ctx ~entry ~line ~column
395 let { Tast_provider.Compute_tast.tast
; _
} =
396 Tast_provider.compute_tast_quarantined ~ctx ~entry
398 let env_and_ty = ServerInferType.expanded_type_at_pos ctx tast line column
in
399 (* There are legitimate cases where we expect to have no identities returned,
400 so just format the type. *)
401 match identities with
404 match env_and_ty with
406 [{ snippet = Tast_env.print_ty env
ty; addendum = []; pos
= None
}]
411 |> List.map ~f
:(fun (occurrence
, def_opt
) ->
413 match occurrence
.SymbolOccurrence.type_
with
414 | SymbolOccurrence.TypeVar
-> None
419 |> Option.map ~f
:(fun def
-> def
.SymbolDefinition.pos
)
420 |> Option.map ~f
:Pos.filename
421 |> Option.value ~default
:entry
.Provider_context.path
424 Provider_context.add_entry_if_missing ~ctx ~
path
426 (ctx
, env_and_ty, entry
, occurrence
, def_opt
))
427 |> make_hover_info_with_fallback
428 |> filter_class_and_constructor
429 |> List.remove_consecutive_duplicates ~equal
:equal_hover_info