2 * Copyright (c) 2016, 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 module WithSyntax
(Syntax
: Syntax_sig.Syntax_S
) = struct
13 module WithSmartConstructors
(SCI
: SmartConstructors.SmartConstructors_S
14 with type r
= Syntax.t
15 with module Token
= Syntax.Token
20 module SyntaxTree_
= Full_fidelity_syntax_tree
22 module SyntaxTree
= SyntaxTree_.WithSmartConstructors
(SCI
)
24 module Token
= Syntax.Token
25 module SyntaxError
= Full_fidelity_syntax_error
26 module SyntaxKind
= Full_fidelity_syntax_kind
27 module TokenKind
= Full_fidelity_token_kind
29 module SN
= Naming_special_names
37 Option.value ~default
:"<text_extraction_failure>" (Syntax.extract_text node
)
39 let make_location s e
=
40 match position
Relative_path.default s
, position
Relative_path.default e
with
42 let start_offset, _
= Pos.info_raw s
in
43 let _, end_offset
= Pos.info_raw e
in
44 { start_offset ; end_offset
}
46 failwith
"Could not determine positions of parse tree nodes."
48 let make_location_of_node n
=
52 let s = Syntax.position
Relative_path.default n
in
53 let s, _ = Pos.info_raw
(Option.value ~default
:Pos.none
s) in
57 let e = Syntax.position
Relative_path.default n
in
58 let _, e = Pos.info_raw
(Option.value ~default
:Pos.none
e) in
63 | Bracketed
of location
64 | Unbracketed
of location
67 | Name_use
(* `use` construct *)
68 | Name_def
(* definition e.g. `class` or `trait` *)
69 | Name_implicit_use
(* implicit `use` e.g. HH type in type hint *)
71 type first_use_or_def
= {
78 type error_level
= Minimum
| Typical
| Maximum
80 type hhvm_compat_mode
= NoCompat
| HHVMCompat
83 { active_classish
: Syntax.t
option
84 ; active_methodish
: Syntax.t
option
85 ; active_callable
: Syntax.t
option
86 ; active_callable_attr_spec
: Syntax.t
option
87 (* true if active callable is reactive if it is a function or method, or there is a reactive
88 * proper ancestor (including lambdas) but not beyond the enclosing function or method *)
89 ; active_is_rx_or_enclosing_for_lambdas
: bool
90 ; active_const
: Syntax.t
option
91 (* Named (not anonymous) namespaces that the current expression is enclosed within. *)
92 ; nested_namespaces
: Syntax.t list
96 { syntax_tree
: SyntaxTree.t
98 ; hhvm_compat_mode
: hhvm_compat_mode
101 ; parser_options
: ParserOptions.t
107 ?
(hhvm_compat_mode
= NoCompat
)
109 ~
(parser_options
: ParserOptions.t
)
110 (syntax_tree
: SyntaxTree.t
)
115 { active_classish
= None
116 ; active_methodish
= None
117 ; active_callable
= None
118 ; active_callable_attr_spec
= None
119 ; active_is_rx_or_enclosing_for_lambdas
= false
120 ; active_const
= None
121 ; nested_namespaces
= []
132 and is_hhvm_compat env
= env
.hhvm_compat_mode
<> NoCompat
134 let is_typechecker env
= not env
.codegen
136 let global_namespace_name = "\\"
138 let combine_names n1 n2
=
139 let has_leading_slash = String.length n2
> 0 && String.get n2
0 = '
\\'
in
140 let len = String.length n1
in
141 let has_trailing_slash = String.get n1
(len - 1) = '
\\'
in
142 match has_leading_slash, has_trailing_slash with
143 | true, true -> n1 ^
(String.sub n2
1 (String.length n2
- 1))
144 | false, false -> n1 ^
"\\" ^ n2
147 let make_first_use_or_def ~kind ?
(is_method
=false) location namespace_name name
=
149 f_location
= location
;
151 f_name
= combine_names namespace_name name
;
152 f_global
= not is_method
&& namespace_name
= global_namespace_name;
156 | YesCase
of 'a
SMap.t
157 | NoCase
of 'a
LSMap.t
161 t_classes
: first_use_or_def strmap
; (* NoCase *)
162 t_namespaces
: first_use_or_def strmap
; (* NoCase *)
163 t_functions
: first_use_or_def strmap
; (* NoCase *)
164 t_constants
: first_use_or_def strmap
; (* YesCase *)
168 t_classes
= NoCase
LSMap.empty
;
169 t_namespaces
= NoCase
LSMap.empty
;
170 t_functions
= NoCase
LSMap.empty
;
171 t_constants
= YesCase
SMap.empty
;
174 let strmap_mem : string -> 'a strmap
-> bool =
177 | NoCase m
-> LSMap.mem k m
178 | YesCase m
-> SMap.mem k m
181 let strmap_add : string -> 'a
-> 'a strmap
-> 'a strmap
=
184 | NoCase m'
-> NoCase
(LSMap.add k v m'
)
185 | YesCase m'
-> YesCase
(SMap.add k v m'
)
188 let strmap_get : string -> 'a strmap
-> 'a
option =
191 | NoCase m'
-> LSMap.get k m'
192 | YesCase m'
-> SMap.get k m'
195 let strmap_find_first_opt : (string -> bool) -> 'a strmap
-> (string * 'a
) option =
198 | NoCase m'
-> LSMap.find_first_opt k m'
199 | YesCase m'
-> SMap.find_first_opt k m'
202 let strmap_filter : (string -> 'a
-> bool) -> 'a strmap
-> 'a strmap
=
205 | NoCase m'
-> NoCase
(LSMap.filter f m'
)
206 | YesCase m'
-> YesCase
(SMap.filter f m'
)
209 let strmap_union : 'a strmap
-> 'a strmap
-> 'a strmap
=
211 begin match x
, y
with
212 | NoCase x'
, NoCase y'
-> NoCase
(LSMap.union x' y'
)
213 | YesCase x'
, YesCase y'
-> YesCase
(SMap.union x' y'
)
214 | NoCase
_, YesCase
_ -> failwith
"cannot union NoCase and YesCase."
215 | YesCase
_, NoCase
_ -> failwith
"cannot union YesCase and NoCase."
218 let empty_trait_require_clauses = NoCase
LSMap.empty
220 let get_short_name_from_qualified_name name alias
=
221 if String.length alias
<> 0 then alias
222 else match String.rindex name '
\\'
with
223 | Some i
-> String.sub name
(i
+ 1) (String.length name
- i
- 1)
227 errors
: SyntaxError.t list
;
228 namespace_type
: namespace_type
;
229 namespace_name
: string;
231 trait_require_clauses
: TokenKind.t strmap
;
232 is_in_concurrent_block
: bool;
236 acc errors namespace_type names namespace_name trait_require_clauses
237 is_in_concurrent_block
=
238 if phys_equal acc
.errors errors
&&
239 phys_equal acc
.namespace_type namespace_type
&&
240 phys_equal acc
.names names
&&
241 phys_equal acc
.namespace_name namespace_name
&&
242 phys_equal acc
.trait_require_clauses trait_require_clauses
&&
243 acc
.is_in_concurrent_block
= is_in_concurrent_block
249 ; trait_require_clauses
250 ; is_in_concurrent_block
253 let fold_child_nodes ?
(cleanup
= (fun x
-> x
)) env f node parents acc
=
255 |> List.fold_left ~init
:acc ~f
:(fun acc c
-> f env acc c
(node
:: parents
))
258 (* Turns a syntax node into a list of nodes; if it is a separated syntax
259 list then the separators are filtered from the resulting list. *)
260 let syntax_to_list include_separators node
=
261 let rec aux acc syntax_list
=
262 match syntax_list
with
267 | ListItem
{ list_item
; list_separator
} ->
268 let acc = list_item
:: acc in
270 if include_separators
then (list_separator
:: acc ) else acc in
272 | _ -> aux (h
:: acc) t
274 match syntax node
with
276 | SyntaxList
s -> List.rev
(aux [] s)
277 | ListItem
{ list_item
; list_separator
} ->
278 if include_separators
then [ list_item
; list_separator
] else [ list_item
]
281 let syntax_to_list_no_separators = syntax_to_list false
282 let syntax_to_list_with_separators = syntax_to_list true
284 let assert_last_in_list assert_fun node
=
289 | h
:: _ when assert_fun h
-> Some h
291 aux (syntax_to_list_no_separators node
)
293 let is_decorated_expression ~f node
=
294 begin match syntax node
with
295 | DecoratedExpression
{ decorated_expression_decorator
; _ } ->
296 f decorated_expression_decorator
300 let test_decorated_expression_child ~f node
=
301 begin match syntax node
with
302 | DecoratedExpression
{ decorated_expression_expression
; _ } ->
303 f decorated_expression_expression
307 (* Test two levels in case ...& or &... hiding under *)
308 let rec is_reference_expression node
=
309 is_decorated_expression ~f
:is_ampersand node
||
310 test_decorated_expression_child node ~f
:is_reference_expression
312 let rec is_variadic_expression node
=
313 is_decorated_expression ~f
:is_ellipsis node
||
314 test_decorated_expression_child node ~f
:is_variadic_expression
316 let is_reference_variadic node
=
317 is_decorated_expression ~f
:is_ellipsis node
&&
318 test_decorated_expression_child node ~f
:is_reference_expression
320 let is_variadic_reference node
=
321 is_decorated_expression ~f
:is_ampersand node
&&
322 test_decorated_expression_child node ~f
:is_variadic_expression
324 let is_double_variadic node
=
325 is_decorated_expression ~f
:is_ellipsis node
&&
326 test_decorated_expression_child node ~f
:is_variadic_expression
328 let is_double_reference node
=
329 is_decorated_expression ~f
:is_ampersand node
&&
330 test_decorated_expression_child node ~f
:is_reference_expression
332 let is_variadic_parameter_variable node
=
333 (* TODO: This shouldn't be a decorated *expression* because we are not
334 expecting an expression at all. We're expecting a declaration. *)
335 is_variadic_expression node
337 let is_variadic_parameter_declaration node
=
338 begin match syntax node
with
339 | VariadicParameter
_ -> true
340 | ParameterDeclaration
{ parameter_name
; _ } ->
341 is_variadic_parameter_variable parameter_name
345 let misplaced_variadic_param params
=
346 assert_last_in_list is_variadic_parameter_declaration params
348 let misplaced_variadic_arg args
=
349 assert_last_in_list is_variadic_expression args
351 (* If a list ends with a variadic parameter followed by a comma, return it *)
352 let ends_with_variadic_comma params
=
356 | x
:: y
:: [] when is_variadic_parameter_declaration x
&& is_comma y
->
359 aux (syntax_to_list_with_separators params
)
361 (* Extract variadic parameter from a parameter list *)
362 let variadic_param params
=
366 | x
:: _ when is_variadic_parameter_declaration x
-> Some x
368 aux (syntax_to_list_with_separators params
)
370 let is_parameter_with_default_value param
=
371 match syntax param
with
372 | ParameterDeclaration
{ parameter_default_value
; _ } ->
373 not
(is_missing parameter_default_value
)
376 (* test a node is a syntaxlist and that the list contains an element
377 * satisfying a given predicate *)
378 let list_contains_predicate p node
=
379 match syntax node
with
384 let list_first_duplicate node
: Syntax.t
option =
385 let module SyntaxMap
= Caml.Map.Make
(
388 let compare a b
= match syntax a
, syntax b
with
389 | Token x
, Token y
->
390 Token.(compare (kind x
) (kind y
))
391 | _, _ -> Pervasives.compare a b
394 match syntax node
with
396 let check_fun (tbl
, acc) el
=
397 if SyntaxMap.mem el tbl
then (tbl
, Some el
)
398 else (SyntaxMap.add el
() tbl
, acc)
400 let (_, result
) = List.fold_left ~f
:check_fun ~init
:(SyntaxMap.empty
, None
) lst
in
404 let is_empty_list_or_missing node
=
405 match syntax node
with
406 | SyntaxList
[] | Missing
-> true
409 let token_kind node
=
410 match syntax node
with
411 | Token t
-> Some
(Token.kind t
)
414 (* Helper function for common code pattern *)
415 let is_token_kind node kind
=
416 (token_kind node
) = Some kind
418 let active_classish_kind context =
419 Option.value_map
context.active_classish ~default
:None ~f
:(function
420 | { syntax
= ClassishDeclaration cd
; _ } -> token_kind cd
.classish_keyword
423 let modifiers_of_function_decl_header_exn node
=
424 match syntax node
with
425 | FunctionDeclarationHeader
{ function_modifiers
= m
; _ } -> m
426 | _ -> failwith
"expected to get FunctionDeclarationHeader"
428 let get_modifiers_of_declaration node
=
429 match syntax node
with
430 | MethodishDeclaration
{ methodish_function_decl_header
= header
; _ } ->
431 Some
(modifiers_of_function_decl_header_exn header
)
432 | PropertyDeclaration
{ property_modifiers
; _} ->
433 Some
(property_modifiers
)
436 (* tests whether the methodish contains a modifier that satisfies [p] *)
437 let methodish_modifier_contains_helper p node
=
438 get_modifiers_of_declaration node
439 |> Option.exists ~f
:(list_contains_predicate p
)
441 (* test the methodish node contains the Final keyword *)
442 let methodish_contains_final node
=
443 methodish_modifier_contains_helper is_final node
445 (* test the methodish node contains the Abstract keyword *)
446 let methodish_contains_abstract node
=
447 methodish_modifier_contains_helper is_abstract node
449 (* test the methodish node contains the Static keyword *)
450 let methodish_contains_static node
=
451 methodish_modifier_contains_helper is_static node
453 (* test the methodish node contains the Private keyword *)
454 let methodish_contains_private node
=
455 methodish_modifier_contains_helper is_private node
457 let is_visibility x
=
458 is_public x
|| is_private x
|| is_protected x
460 let contains_async_not_last mods
=
461 let mod_list = syntax_to_list_no_separators mods
in
462 List.exists ~f
:is_async
mod_list
463 && not
@@ is_async
@@ List.nth_exn
mod_list (List.length
mod_list - 1)
465 let has_static node
context f
=
467 | FunctionDeclarationHeader node
->
468 let label = node
.function_name
in
470 context.active_methodish
|> Option.exists ~f
:methodish_contains_static
473 (* Given a function declaration header, confirm that it is a constructor
474 * and that the methodish containing it has a static keyword *)
477 String.lowercase
(text label) = SN.SpecialFunctions.clone
479 let class_constructor_has_static node
context =
480 has_static node
context is_construct
482 let class_destructor_cannot_be_static node
context =
483 has_static node
context is_destruct
485 let clone_cannot_be_static node
context =
486 has_static node
context is_clone
488 let promoted_params (params
: Syntax.t list
) : Syntax.t list
=
489 List.filter params
(fun node
->
490 match syntax node
with
491 | ParameterDeclaration
{ parameter_visibility
; _ } ->
492 parameter_visibility
|> is_missing
|> not
495 (* Given a function declaration header, confirm that it is NOT a constructor
496 * and that the header containing it has visibility modifiers in parameters
498 let class_non_constructor_has_visibility_param node _context
=
500 | FunctionDeclarationHeader node
->
501 let params = syntax_to_list_no_separators node
.function_parameter_list
in
502 not
(is_construct node
.function_name
) && promoted_params params <> []
505 (* Don't allow a promoted parameter in a constructor if the class
506 * already has a property with the same name. Return the clashing name found.
508 let class_constructor_param_promotion_clash node
context : string option =
509 let class_elts node
=
510 match Option.map node ~f
:syntax
with
511 | Some
(ClassishDeclaration cd
) -> begin
512 match syntax cd
.classish_body
with
513 | ClassishBody
{ classish_body_elements
; _} ->
514 syntax_to_list_no_separators classish_body_elements
519 (* A property declaration may include multiple property names:
522 let prop_names elt
: string list
=
523 match syntax elt
with
524 | PropertyDeclaration
{ property_declarators
; _} ->
525 let declarators = syntax_to_list_no_separators property_declarators
in
526 let names = List.map
declarators ~f
:(function decl
->
527 match syntax decl
with
528 | PropertyDeclarator
{property_name
; _} ->
529 Some
(text property_name
)
532 List.filter_opt
names
535 let param_names params =
536 let names = List.map
params (fun p
-> match syntax p
with
537 | ParameterDeclaration
{ parameter_name
; _ } ->
538 Some
(text parameter_name
)
541 List.filter_opt
names
545 | FunctionDeclarationHeader node
->
546 if is_construct node
.function_name
then
547 let class_var_names =
548 List.concat_map
(class_elts context.active_classish
) ~f
:prop_names
550 let params = syntax_to_list_no_separators node
.function_parameter_list
in
551 let promoted_param_names = param_names (promoted_params params) in
552 List.find
promoted_param_names ~f
:(fun name
-> List.mem
class_var_names name ~equal
:(=))
557 (* Ban parameter promotion in abstract constructors. *)
558 let abstract_class_constructor_has_visibility_param node _context
=
560 | FunctionDeclarationHeader node
->
561 let label = node
.function_name
in
562 let params = syntax_to_list_no_separators node
.function_parameter_list
in
563 is_construct
label &&
564 list_contains_predicate is_abstract node
.function_modifiers
&&
565 promoted_params params <> []
568 (* Ban parameter promotion in interfaces and traits. *)
569 let interface_or_trait_has_visibility_param node
context =
571 | FunctionDeclarationHeader node
->
572 let is_interface_or_trait =
573 context.active_classish
|> Option.exists ~f
:(fun parent_classish
->
574 match syntax parent_classish
with
575 | ClassishDeclaration cd
->
576 let kind = token_kind cd
.classish_keyword
in
577 kind = Some
TokenKind.Interface
|| kind = Some
TokenKind.Trait
580 let params = syntax_to_list_no_separators node
.function_parameter_list
in
581 promoted_params params <> [] && is_interface_or_trait
584 (* check that a constructor or a destructor is type annotated *)
585 let class_constructor_destructor_has_non_void_type env node _context
=
586 if not
(is_typechecker env
) then false
589 | FunctionDeclarationHeader node
->
590 let label = node
.function_name
in
591 let type_ano = node
.function_type
in
592 let function_colon = node
.function_colon in
593 let is_missing = is_missing type_ano && is_missing function_colon in
594 let is_void = match syntax
type_ano with
595 | SimpleTypeSpecifier spec
->
596 is_void spec
.simple_type_specifier
599 (is_construct
label || is_destruct
label) &&
600 not
(is_missing || is_void)
603 let async_magic_method node _context
=
605 | FunctionDeclarationHeader node
->
606 let name = String.lowercase
@@ text node
.function_name
in
607 begin match name with
608 | _ when name = String.lowercase
SN.Members.__disposeAsync
-> false
609 | _ when SSet.mem
name SN.Members.as_lowercase_set
->
610 list_contains_predicate is_async node
.function_modifiers
615 let call_static_method node _context
=
617 | FunctionDeclarationHeader node
->
618 let name = String.lowercase
@@ text node
.function_name
in
619 name = String.lowercase
SN.Members.__callStatic
622 let clone_destruct_takes_no_arguments _method_name node _context
=
624 | FunctionDeclarationHeader
{ function_parameter_list
= l
; function_name
= name; _} ->
625 let num_params = List.length
(syntax_to_list_no_separators l
) in
626 ((is_clone name) || (is_destruct
name)) && num_params <> 0
629 (* whether a methodish decl has body *)
630 let methodish_has_body node
=
631 match syntax node
with
632 | MethodishDeclaration syntax
->
633 let body = syntax
.methodish_function_body
in
634 not
(is_missing body)
637 (* whether a methodish decl is native *)
638 let methodish_is_native node
=
639 match syntax node
with
640 | MethodishDeclaration
{ methodish_attribute
= {
641 syntax
= AttributeSpecification
{
642 attribute_specification_attributes
= attrs
; _}; _}; _} ->
643 let attrs = syntax_to_list_no_separators attrs in
645 ~f
:(function { syntax
= ConstructorCall
{constructor_call_type
; _}; _} ->
646 String.lowercase
@@ text constructor_call_type
= "__native"
650 (* By checking the third parent of a methodish node, tests whether the methodish
651 * node is inside an interface. *)
652 let methodish_inside_interface context =
653 context.active_classish
|> Option.exists ~f
:(fun parent_classish
->
654 match syntax parent_classish
with
655 | ClassishDeclaration cd
when token_kind cd
.classish_keyword
= Some
TokenKind.Interface
-> true
658 (* Test whether node is a non-abstract method without a body and not native.
659 * Here node is the methodish node
660 * And methods inside interfaces are inherently considered abstract *)
661 let methodish_non_abstract_without_body_not_native env node
_ =
662 let non_abstract = not
(methodish_contains_abstract node
663 || methodish_inside_interface env
.context) in
664 let not_has_body = not
(methodish_has_body node
) in
665 let not_native = not
(methodish_is_native node
) in
666 let not_hhi = not
(env
.hhi_mode
) in
667 not_hhi && non_abstract && not_has_body && not_native
669 (* Test whether node is a method that is both abstract and private
671 let methodish_abstract_conflict_with_private node
=
672 let is_abstract = methodish_contains_abstract node
in
673 let has_private = methodish_contains_private node
in
674 is_abstract && has_private
676 (* Test whether node is a method that is both abstract and final
678 let methodish_abstract_conflict_with_final node
=
679 let is_abstract = methodish_contains_abstract node
in
680 let has_final = methodish_contains_final node
in
681 is_abstract && has_final
683 let methodish_abstract_inside_interface context node
=
684 let is_abstract = methodish_contains_abstract node
in
685 let is_in_interface = methodish_inside_interface context in
686 is_abstract && is_in_interface
688 let using_statement_function_scoped_is_legal parents
=
690 (* using is allowed in the toplevel, and also in toplevel async blocks *)
692 { syntax
= CompoundStatement
_; _ } ::
694 FunctionDeclaration
_ |
695 MethodishDeclaration
_ |
696 AnonymousFunction
_ |
698 AwaitableCreationExpression
_); _ } :: _ -> true
701 let make_error_from_nodes
702 ?
(error_type
=SyntaxError.ParseError
) start_node end_node error
=
703 let s = start_offset start_node
in
704 let e = end_offset end_node
in
705 SyntaxError.make ~error_type
s e error
707 let make_error_from_node ?
(error_type
=SyntaxError.ParseError
) node error
=
708 make_error_from_nodes ~error_type node node error
710 let is_invalid_xhp_attr_enum_item_literal literal_expression
=
711 match syntax literal_expression
with
713 Full_fidelity_token_kind.(match Token.kind t
with
714 | DecimalLiteral
| SingleQuotedStringLiteral
715 | DoubleQuotedStringLiteral
-> false
720 let is_invalid_xhp_attr_enum_item node
=
721 match syntax node
with
722 | LiteralExpression
{literal_expression
} ->
723 is_invalid_xhp_attr_enum_item_literal literal_expression
726 let xhp_errors env node errors
=
727 match syntax node
with
728 | XHPEnumType enumType
when
729 (is_typechecker env
) &&
730 (is_missing enumType
.xhp_enum_values
) ->
731 make_error_from_node enumType
.xhp_enum_values
SyntaxError.error2055
:: errors
732 | XHPEnumType enumType
when
733 (is_typechecker env
) ->
734 let invalid_enum_items = List.filter ~f
:is_invalid_xhp_attr_enum_item
735 (syntax_to_list_no_separators enumType
.xhp_enum_values
) in
736 let mapper errors item
=
737 make_error_from_node item
SyntaxError.error2063
:: errors
in
738 List.fold_left ~f
:mapper ~init
:errors
invalid_enum_items
741 { syntax
= XHPOpen
{ xhp_open_name
; _ }; _ }
743 { syntax
= XHPClose
{ xhp_close_name
; _ }; _ }
744 ; _ } when text xhp_open_name
<> text xhp_close_name
->
745 make_error_from_node node
(SyntaxError.error2070
746 ~open_tag
:(text xhp_open_name
)
747 ~close_tag
:(text xhp_close_name
)) :: errors
750 (* error on 'public private function foo() *)
751 let multiple_visibility_errors modifiers msg errors
=
752 let modifiers = match syntax
modifiers with
753 | SyntaxList lst
-> lst
756 let modifiers = List.filter
modifiers is_visibility in
757 if (List.length
modifiers > 1) then
758 make_error_from_node (List.last_exn
modifiers) msg
:: errors
762 (* error on 'final final function foo() *)
763 let multiple_modifiers_errors modifiers msg errors
=
764 match list_first_duplicate modifiers with
766 make_error_from_node duplicate msg
:: errors
770 (* helper since there are so many kinds of errors *)
771 let produce_error acc check node error error_node
=
773 (make_error_from_node error_node error
) :: acc
776 let produce_error_from_check acc check node error
=
777 match check node
with
779 (make_error_from_node error_node error
) :: acc
782 let produce_error_context acc check node
context error error_node
=
783 if check node
context then
784 (make_error_from_node error_node error
) :: acc
787 let produce_error_for_header acc check node error error_node
=
788 (* use [check] to check properties of function *)
789 let function_header_check_helper check node
= check
(syntax node
) in
790 produce_error_context acc (function_header_check_helper check
) node
794 let cant_be_classish_name name =
795 match String.lowercase
name with
796 | "callable" | "classname" | "darray" | "false" | "null" | "parent" | "self"
797 | "this" | "true" | "varray" -> true
800 (* Given a function_declaration_header node, returns its function_name
801 * as a string opt. *)
802 let extract_function_name header_node
=
803 (* The '_' arm of this match will never be reached, but the type checker
804 * doesn't allow a direct extraction of function_name from
805 * function_declaration_header. *)
806 match syntax header_node
with
807 | FunctionDeclarationHeader fdh
->
808 Syntax.extract_text fdh
.function_name
811 (* Return, as a string opt, the name of the function or method given the context *)
812 let first_parent_function_name context =
813 (* Note: matching on either is sound because functions and/or methods cannot be nested *)
814 match context.active_methodish
with
815 | Some
{ syntax
= FunctionDeclaration
{ function_declaration_header
= header
; _ }; _ }
816 | Some
{ syntax
= MethodishDeclaration
{ methodish_function_decl_header
= header
; _ }; _ }
817 -> extract_function_name header
820 (* Given a particular TokenKind.(Trait/Interface), tests if a given
821 * classish_declaration node is both of that kind and declared abstract. *)
822 let is_classish_kind_declared_abstract _env cd_node
=
823 match syntax cd_node
with
824 | ClassishDeclaration
{ classish_keyword
; classish_modifiers
; _ }
825 when is_token_kind classish_keyword
TokenKind.Trait
826 || is_token_kind classish_keyword
TokenKind.Interface
->
827 list_contains_predicate is_abstract classish_modifiers
830 let is_immediately_in_lambda context =
831 Option.value_map
context.active_callable ~default
:false ~f
:(fun node
->
832 match syntax node
with
833 | AnonymousFunction
_
835 | AwaitableCreationExpression
_ -> true
839 (* Returns the whether the current context is in an active class scope *)
840 let is_in_active_class_scope context = Option.is_some
context.active_classish
842 (* Returns the first ClassishDeclaration node in the given context,
843 * or None if there isn't one or classish_kind does not match. *)
844 let first_parent_classish_node classish_kind
context =
845 Option.value_map
context.active_classish ~default
:None ~f
:(function
846 { syntax
= ClassishDeclaration cd
; _ } as node
->
847 Some
(node
, is_token_kind cd
.classish_keyword classish_kind
)
849 ) |> Option.value_map ~default
:None
850 ~f
:(function (n
, true) -> Some n
| _ -> None
)
852 (* Return, as a string opt, the name of the closest enclosing classish entity in
853 the given context (not just Classes ) *)
854 let active_classish_name context =
855 context.active_classish
|> Option.value_map ~default
:None ~f
:(fun node
->
856 match syntax node
with
857 | ClassishDeclaration cd
-> Syntax.extract_text cd
.classish_name
861 (* Return, as a string opt, the name of the Class in the given context *)
862 let first_parent_class_name context =
863 context.active_classish
|> Option.value_map ~default
:None ~f
:(fun parent_classish
->
864 match syntax parent_classish
with
865 | ClassishDeclaration cd
when token_kind cd
.classish_keyword
= Some
TokenKind.Class
->
866 active_classish_name context
867 | _ -> None
(* This arm is never reached *)
870 (* Given a classish_ or methodish_ declaration node, returns the modifier node
871 from its list of modifiers, or None if there isn't one. *)
872 let extract_keyword modifier declaration_node
=
873 let aux modifiers_list
=
874 List.find ~f
:modifier
(syntax_to_list_no_separators modifiers_list
)
877 match syntax declaration_node
with
878 | ClassishDeclaration
{ classish_modifiers
= modifiers_list
; _ } ->
881 Option.bind
(get_modifiers_of_declaration declaration_node
) aux
883 (* Wrapper function that uses above extract_keyword function to test if node
884 contains is_abstract keyword *)
885 let is_abstract_declaration declaration_node
=
886 not
(Option.is_none
(extract_keyword is_abstract declaration_node
))
888 (* Given a context, tests if the immediate classish parent is an
890 let is_inside_interface context =
891 Option.is_some
(first_parent_classish_node TokenKind.Interface
context)
893 (* Given a context, tests if the immediate classish parent is a
895 let is_inside_trait context =
896 Option.is_some
(first_parent_classish_node TokenKind.Trait
context)
898 (* Returns the 'async'-annotation syntax node from the methodish_declaration
899 * node. The returned node may have syntax kind 'Missing', but it will only be
900 * None if something other than a methodish_declaration node was provided as
902 let extract_async_node md_node
=
903 get_modifiers_of_declaration md_node
904 |> Option.value_map ~default
:[] ~f
:syntax_to_list_no_separators
905 |> List.find ~f
:is_async
907 let is_abstract_and_async_method md_node _context
=
908 let async_node = extract_async_node md_node
in
909 match async_node with
912 is_abstract_declaration md_node
913 && not
(is_missing async_node)
915 let is_interface_and_async_method md_node
context =
916 let async_node = extract_async_node md_node
in
917 match async_node with
920 is_inside_interface context
921 && not
(is_missing async_node)
923 let get_params_for_enclosing_callable context =
924 context.active_callable
|> Option.bind ~f
:(fun callable
->
925 match syntax callable
with
926 | FunctionDeclaration
{ function_declaration_header
= header
; _ }
927 | MethodishDeclaration
{ methodish_function_decl_header
= header
; _ } ->
928 begin match syntax header
with
929 | FunctionDeclarationHeader fdh
->
930 Some fdh
.function_parameter_list
933 | LambdaExpression
{ lambda_signature
; _} ->
934 begin match syntax lambda_signature
with
935 | LambdaSignature
{ lambda_parameters
; _ } ->
936 Some lambda_parameters
942 let first_parent_function_attributes_contains context name =
943 match context.active_methodish
with
944 | Some
{ syntax
= FunctionDeclaration
{ function_attribute_spec
= {
945 syntax
= AttributeSpecification
{
946 attribute_specification_attributes
; _ }; _ }; _ }; _ }
947 | Some
{ syntax
= MethodishDeclaration
{ methodish_attribute
= {
948 syntax
= AttributeSpecification
{
949 attribute_specification_attributes
; _ }; _ }; _ }; _ }
952 syntax_to_list_no_separators attribute_specification_attributes
in
954 ~f
:(function { syntax
= ConstructorCall
{ constructor_call_type
; _}; _} ->
955 text constructor_call_type
= name | _ -> false)
957 let is_parameter_with_callconv param
=
958 match syntax param
with
959 | ParameterDeclaration
{ parameter_call_convention
; _ } ->
960 not
@@ is_missing parameter_call_convention
961 | ClosureParameterTypeSpecifier
{ closure_parameter_call_convention
; _ } ->
962 not
@@ is_missing closure_parameter_call_convention
963 | VariadicParameter
{ variadic_parameter_call_convention
; _ } ->
964 not
@@ is_missing variadic_parameter_call_convention
967 let has_inout_params context =
968 match get_params_for_enclosing_callable context with
969 | Some function_parameter_list
->
970 let params = syntax_to_list_no_separators function_parameter_list
in
971 List.exists
params ~f
:is_parameter_with_callconv
974 let is_inside_async_method context =
975 Option.value_map
context.active_callable ~f
:(fun node
->
976 match syntax node
with
977 | FunctionDeclaration
{ function_declaration_header
= header
; _ }
978 | MethodishDeclaration
{ methodish_function_decl_header
= header
; _ } ->
979 begin match syntax header
with
980 | FunctionDeclarationHeader fdh
->
981 List.exists ~f
:is_async
@@
982 syntax_to_list_no_separators fdh
.function_modifiers
985 | AnonymousFunction
{ anonymous_async_keyword
; _ } ->
986 not
@@ is_missing anonymous_async_keyword
987 | LambdaExpression
{ lambda_async
; _ } ->
988 not
@@ is_missing lambda_async
989 | AwaitableCreationExpression
_ -> true
993 let make_name_already_used_error node
name short_name original_location
995 let name = Utils.strip_ns
name in
996 let original_location_error =
998 original_location
.start_offset
999 original_location
.end_offset
1000 SyntaxError.original_definition
in
1001 let s = start_offset node
in
1002 let e = end_offset node
in
1004 ~child
:(Some
original_location_error) s e (report_error ~
name ~short_name
)
1006 let check_type_name_reference _env name_text location
names errors
=
1007 if not
(Hh_autoimport.is_hh_autoimport name_text
)
1008 || strmap_mem name_text
names.t_classes
1011 let def = make_first_use_or_def ~
kind:Name_implicit_use location
"HH" name_text
in
1012 let names = { names with t_classes
= strmap_add name_text
def names.t_classes
} in
1015 let check_type_hint env node
names errors
=
1016 let rec check (names, errors
) node
=
1018 List.fold_left
(Syntax.children node
) ~f
:check ~init
:(names, errors
) in
1019 match syntax node
with
1020 | SimpleTypeSpecifier
{ simple_type_specifier
= s; _ }
1021 | GenericTypeSpecifier
{ generic_class_type
= s; _ } ->
1022 check_type_name_reference env
(text s) (make_location_of_node node
) names errors
1026 check (names, errors
) node
1028 let extract_callconv_node node
=
1029 match syntax node
with
1030 | ParameterDeclaration
{ parameter_call_convention
; _ } ->
1031 Some parameter_call_convention
1032 | ClosureParameterTypeSpecifier
{ closure_parameter_call_convention
; _ } ->
1033 Some closure_parameter_call_convention
1034 | VariadicParameter
{ variadic_parameter_call_convention
; _ } ->
1035 Some variadic_parameter_call_convention
1038 (* Given a node, checks if it is a abstract ConstDeclaration *)
1039 let is_abstract_const declaration
=
1040 match syntax declaration
with
1041 | ConstDeclaration x
-> not
(is_missing x
.const_abstract
)
1044 (* Given a ConstDeclarator node, test whether it is abstract, but has an
1046 let constant_abstract_with_initializer init
context =
1048 match context.active_const
with
1049 | Some p_const_declaration
1050 when is_abstract_const p_const_declaration
-> true
1053 let has_initializer =
1054 not
(is_missing init
) in
1055 is_abstract && has_initializer
1057 (* Given a node, checks if it is a concrete ConstDeclaration *)
1058 let is_concrete_const declaration
=
1059 match syntax declaration
with
1060 | ConstDeclaration x
-> is_missing x
.const_abstract
1063 (* Given a ConstDeclarator node, test whether it is concrete, but has no
1065 let constant_concrete_without_initializer init
context =
1066 let is_concrete = match context.active_const
with
1067 | Some p_const_declaration
->
1068 is_concrete_const p_const_declaration
1070 is_concrete && is_missing init
1072 (* Given a PropertyDeclaration node, tests whether parent class is abstract
1073 final but child variable is non-static *)
1075 let is_byref_expression node
=
1076 is_decorated_expression ~f
:is_ampersand node
1078 let is_byref_parameter_variable node
=
1079 (* TODO: This shouldn't be a decorated *expression* because we are not
1080 expecting an expression at all. We're expecting a declaration. *)
1081 is_byref_expression node
1083 let is_param_by_ref node
=
1084 match syntax node
with
1085 | ParameterDeclaration
{ parameter_name
; _ } ->
1086 is_byref_parameter_variable parameter_name
1089 let attribute_constructor_name node
=
1090 match syntax node
with
1092 list_item
= { syntax
= ConstructorCall
{ constructor_call_type
; _ }; _ }; _
1093 } -> Syntax.extract_text constructor_call_type
1096 let attribute_specification_contains node
name =
1097 match syntax node
with
1098 | AttributeSpecification
{ attribute_specification_attributes
= attrs; _ } ->
1099 List.exists
(syntax_node_to_list
attrs) ~f
:begin fun n
->
1100 attribute_constructor_name n
= Some
name
1104 let fold_attribute_spec node ~f ~init
=
1105 match syntax node
with
1106 | AttributeSpecification
{ attribute_specification_attributes
= attrs; _ } ->
1107 List.fold
(syntax_node_to_list
attrs) ~init ~f
1110 let methodish_contains_attribute node attribute
=
1112 | MethodishDeclaration
{ methodish_attribute
= attr_spec
; _ } ->
1113 attribute_specification_contains attr_spec attribute
1116 let methodish_memoize_lsb_on_non_static node errors
=
1117 if methodish_contains_attribute (syntax node
) SN.UserAttributes.uaMemoizeLSB
&&
1118 not
(methodish_contains_static node
)
1120 let e = make_error_from_node node
SyntaxError.memoize_lsb_on_non_static
1124 let function_declaration_contains_attribute node attribute
=
1125 match syntax node
with
1126 | FunctionDeclaration
{ function_attribute_spec
= attr_spec
; _ } ->
1127 attribute_specification_contains attr_spec attribute
1130 let methodish_contains_memoize env node _context
=
1131 (is_typechecker env
) && is_inside_interface env
.context
1132 && (methodish_contains_attribute node
SN.UserAttributes.uaMemoize
)
1134 let is_some_reactivity_attribute_name name =
1135 name = SN.UserAttributes.uaReactive
||
1136 name = SN.UserAttributes.uaShallowReactive
||
1137 name = SN.UserAttributes.uaLocalReactive
||
1138 name = SN.UserAttributes.uaNonRx
1140 let attribute_matches_criteria f n
=
1144 syntax
= ConstructorCall
{
1145 constructor_call_type
;
1146 constructor_call_argument_list
= args
; _
1150 begin match Syntax.extract_text constructor_call_type
with
1151 | Some n
when f n
-> Some args
1156 let is_some_reactivity_attribute n
=
1157 attribute_matches_criteria is_some_reactivity_attribute_name n
1160 let attribute_first_reactivity_annotation attr_spec
=
1161 match syntax attr_spec
with
1162 | AttributeSpecification
{ attribute_specification_attributes
= attrs; _ } ->
1163 List.find
(syntax_node_to_list
attrs) ~f
:is_some_reactivity_attribute
1167 let attribute_has_reactivity_annotation attr_spec
=
1168 Option.is_some
(attribute_first_reactivity_annotation attr_spec
)
1170 let attribute_missing_reactivity_for_condition attr_spec
=
1171 let has_attr attr
= attribute_specification_contains attr_spec attr
in
1172 not
(attribute_has_reactivity_annotation attr_spec
) && (
1173 has_attr SN.UserAttributes.uaOnlyRxIfImpl
||
1174 has_attr SN.UserAttributes.uaAtMostRxAsArgs
1177 let error_if_memoize_function_returns_mutable attrs errors
=
1178 let (has_memoize
, mutable_node
, mut_return_node
) =
1179 fold_attribute_spec attrs ~init
:(false, None
, None
) ~f
:(
1180 fun ((has_memoize
, mutable_node
, mut_return_node
) as acc) node
->
1181 match attribute_constructor_name node
with
1182 | Some n
when n
= SN.UserAttributes.uaMutableReturn
->
1183 (has_memoize
, mutable_node
, (Some node
))
1184 | Some n
when n
= SN.UserAttributes.uaMemoize
||
1185 n
= SN.UserAttributes.uaMemoizeLSB
->
1186 (true, mutable_node
, mut_return_node
)
1187 | Some n
when n
= SN.UserAttributes.uaMutable
->
1188 (has_memoize
, Some node
, mut_return_node
)
1194 match mutable_node
with
1196 make_error_from_node
1197 n
(SyntaxError.mutable_parameter_in_memoize_function ~is_this
:true) :: errors
1200 match mut_return_node
with
1202 make_error_from_node n
SyntaxError.mutable_return_in_memoize_function
:: errors
1207 let methodish_missing_reactivity_for_condition node
=
1208 match syntax node
with
1209 | MethodishDeclaration
{ methodish_attribute
= attr_spec
; _ } ->
1210 attribute_missing_reactivity_for_condition attr_spec
1213 let methodish_contains_owned_mutable_attribute node
=
1214 methodish_contains_attribute (syntax node
) SN.UserAttributes.uaOwnedMutable
1216 let check_nonrx_annotation node
errors =
1218 let e = make_error_from_node node
1219 SyntaxError.invalid_non_rx_argument_for_declaration
in
1222 let e = make_error_from_node node
1223 SyntaxError.invalid_non_rx_argument_for_lambda
in
1226 match syntax node
with
1227 | MethodishDeclaration
{ methodish_attribute
= s; _ }
1228 | FunctionDeclaration
{ function_attribute_spec
= s; _ } ->
1229 Some
(syntax
s, true)
1230 | AnonymousFunction
{ anonymous_attribute_spec
= s; _ }
1231 | LambdaExpression
{ lambda_attribute_spec
= s; _ }
1232 | AwaitableCreationExpression
{ awaitable_attribute_spec
= s; _ } ->
1233 Some
(syntax
s, false)
1235 match attr_spec with
1236 | Some
(AttributeSpecification
{ attribute_specification_attributes
= attrs; _ }, is_decl
) ->
1237 (* try find argument list *)
1239 List.find_map
(syntax_node_to_list
attrs)
1240 ~f
:(attribute_matches_criteria ((=)SN.UserAttributes.uaNonRx
)) in
1241 begin match args with
1242 (* __NonRx attribute not found *)
1244 (* __NonRx attribute is found and argument list is empty.
1245 This is ok for lambdas but error for declarations *)
1246 | Some
{ syntax
= Missing
; _ } ->
1247 if is_decl
then err_decl ()
1249 (* __NonRx attribute is found with single string argument.
1250 This is ok for declarations for not allowed for lambdas *)
1251 | Some
{ syntax
= SyntaxList
[
1252 { syntax
= ListItem
{
1253 list_item
= { syntax
= LiteralExpression
{
1254 literal_expression
= { syntax
= Token token
; _ }; _
1257 ]; _ } when Token.kind token
= TokenKind.DoubleQuotedStringLiteral
||
1258 Token.kind token
= TokenKind.SingleQuotedStringLiteral
->
1259 if is_decl
then errors
1261 (* __NonRx attribute is found but argument list is not suitable
1262 nor for declarations, neither for lambdas *)
1264 if is_decl
then err_decl ()
1269 let function_missing_reactivity_for_condition node
=
1270 match syntax node
with
1271 | FunctionDeclaration
{ function_attribute_spec
= attr_spec; _ } ->
1272 attribute_missing_reactivity_for_condition attr_spec
1275 let function_declaration_contains_only_rx_if_impl_attribute node
=
1276 function_declaration_contains_attribute node
SN.UserAttributes.uaOnlyRxIfImpl
1278 let function_declaration_contains_owned_mutable_attribute node
=
1279 function_declaration_contains_attribute node
SN.UserAttributes.uaOwnedMutable
1281 let attribute_multiple_reactivity_annotations attr_spec =
1282 let rec check l seen
=
1285 | x
:: xs
when is_some_reactivity_attribute x
->
1286 if seen
then true else check xs
true
1287 | _ :: xs
-> check xs seen
in
1288 match syntax
attr_spec with
1289 | AttributeSpecification
{ attribute_specification_attributes
= attrs; _ } ->
1290 check (syntax_node_to_list
attrs) false
1293 let methodish_multiple_reactivity_annotations node
=
1294 match syntax node
with
1295 | MethodishDeclaration
{ methodish_attribute
= attr_spec; _ } ->
1296 attribute_multiple_reactivity_annotations attr_spec
1299 let function_multiple_reactivity_annotations node
=
1300 match syntax node
with
1301 | FunctionDeclaration
{ function_attribute_spec
= attr_spec; _ } ->
1302 attribute_multiple_reactivity_annotations attr_spec
1305 let function_declaration_header_memoize_lsb context errors =
1306 match context.active_methodish
, context.active_classish
with
1307 | Some node
, None
(* a function, not a method *)
1308 when function_declaration_contains_attribute node
SN.UserAttributes.uaMemoizeLSB
->
1309 let e = make_error_from_node node
SyntaxError.memoize_lsb_on_non_method
1313 let special_method_param_errors node
context errors =
1314 match syntax node
with
1315 | FunctionDeclarationHeader
{function_name
; function_parameter_list
; _}
1316 when SSet.mem
(String.lowercase
@@ text function_name
)
1317 SN.Members.as_lowercase_set
->
1318 let params = syntax_to_list_no_separators function_parameter_list
in
1319 let len = List.length
params in
1320 let name = text function_name
in
1321 let full_name = match first_parent_class_name context with
1323 | Some c_name
-> c_name ^
"::" ^
name ^
"()"
1325 let s = String.lowercase
name in
1328 | _ when s = SN.Members.__call
&& len <> 2 -> Some
2
1329 | _ when s = SN.Members.__get
&& len <> 1 -> Some
1
1330 | _ when s = SN.Members.__set
&& len <> 2 -> Some
2
1331 | _ when s = SN.Members.__isset
&& len <> 1 -> Some
1
1332 | _ when s = SN.Members.__unset
&& len <> 1 -> Some
1
1335 let errors = match num_args_opt with
1338 make_error_from_node
1339 node
(SyntaxError.invalid_number_of_args
full_name n
) :: errors
1341 let errors = if (s = SN.Members.__call
1342 || s = SN.Members.__get
1343 || s = SN.Members.__set
1344 || s = SN.Members.__isset
1345 || s = SN.Members.__unset
)
1346 && List.exists ~f
:is_param_by_ref params then
1347 make_error_from_node
1348 node
(SyntaxError.invalid_args_by_ref
full_name) :: errors
1354 let is_in_reified_class context =
1355 match context.active_classish
with
1356 | Some
{ syntax
= ClassishDeclaration
{
1357 classish_type_parameters
= {
1358 syntax
= TypeParameters
{
1359 type_parameters_parameters
= l
; _ }; _}; _ }; _ } ->
1360 syntax_to_list_no_separators l
1361 |> List.exists ~f
:(fun p
->
1363 | TypeParameter
{ type_reified
; _} -> not
@@ is_missing type_reified
1368 let methodish_errors env node
errors =
1369 match syntax node
with
1370 (* TODO how to narrow the range of error *)
1371 | FunctionDeclarationHeader
{ function_parameter_list
; function_type
; _} ->
1373 produce_error_for_header errors
1374 (class_constructor_destructor_has_non_void_type env
)
1375 node env
.context SyntaxError.error2018 function_type
in
1377 produce_error_for_header errors class_non_constructor_has_visibility_param
1378 node env
.context SyntaxError.error2010 function_parameter_list
in
1380 match class_constructor_param_promotion_clash (syntax node
) env
.context with
1381 | Some clashing_name
->
1382 let class_name = Option.value (active_classish_name env
.context) ~default
:"" in
1383 let error_msg = SyntaxError.error2025
class_name clashing_name
in
1384 let error = (make_error_from_node function_parameter_list
error_msg) in
1389 produce_error_for_header errors abstract_class_constructor_has_visibility_param
1390 node env
.context SyntaxError.error2023 function_parameter_list
in
1392 produce_error_for_header errors interface_or_trait_has_visibility_param
1393 node env
.context SyntaxError.error2024 function_parameter_list
in
1395 function_declaration_header_memoize_lsb env
.context errors in
1397 | FunctionDeclaration fd
->
1398 let function_attrs = fd
.function_attribute_spec
in
1400 produce_error errors
1401 function_multiple_reactivity_annotations node
1402 SyntaxError.multiple_reactivity_annotations
function_attrs in
1404 error_if_memoize_function_returns_mutable function_attrs errors in
1406 produce_error errors
1407 function_declaration_contains_only_rx_if_impl_attribute node
1408 SyntaxError.functions_cannot_implement_reactive
function_attrs in
1410 check_nonrx_annotation node
errors in
1412 produce_error errors
1413 function_missing_reactivity_for_condition node
1414 SyntaxError.missing_reactivity_for_condition
function_attrs in
1416 produce_error errors
1417 function_declaration_contains_owned_mutable_attribute node
1418 SyntaxError.misplaced_owned_mutable
function_attrs in
1420 | MethodishDeclaration md
->
1421 let header_node = md
.methodish_function_decl_header
in
1422 let modifiers = modifiers_of_function_decl_header_exn header_node in
1423 let class_name = Option.value (active_classish_name env
.context)
1425 let method_name = Option.value (extract_function_name
1426 md
.methodish_function_decl_header
) ~default
:"" in
1427 let method_attrs = md
.methodish_attribute
in
1429 error_if_memoize_function_returns_mutable method_attrs errors in
1431 produce_error_for_header errors
1432 (methodish_contains_memoize env
)
1433 node env
.context SyntaxError.interface_with_memoize
header_node in
1435 produce_error_for_header errors
1436 (class_constructor_has_static) header_node
1437 env
.context (SyntaxError.error2009
class_name method_name) modifiers in
1439 produce_error_for_header errors
1440 (class_destructor_cannot_be_static)
1441 header_node env
.context
1442 (SyntaxError.class_destructor_cannot_be_static class_name method_name) modifiers in
1444 produce_error_for_header errors async_magic_method header_node env
.context
1445 (SyntaxError.async_magic_method ~
name:method_name) modifiers in
1447 produce_error_for_header errors call_static_method header_node env
.context
1448 (SyntaxError.call_static_method) modifiers in
1450 produce_error_for_header errors
1451 (clone_destruct_takes_no_arguments method_name) header_node env
.context
1452 (SyntaxError.clone_destruct_takes_no_arguments class_name method_name) modifiers in
1454 produce_error_for_header errors (clone_cannot_be_static) header_node env
.context
1455 (SyntaxError.clone_cannot_be_static class_name method_name) modifiers in
1457 multiple_visibility_errors modifiers SyntaxError.error2017
errors in
1459 multiple_modifiers_errors modifiers SyntaxError.error2013
errors in
1461 if methodish_contains_static node
&& (
1462 attribute_specification_contains method_attrs SN.UserAttributes.uaMutable
||
1463 attribute_specification_contains method_attrs SN.UserAttributes.uaMaybeMutable
1465 then make_error_from_node node
1466 SyntaxError.mutability_annotation_on_static_method
:: errors
1469 if String.lowercase
method_name = SN.Members.__construct
&& (
1470 attribute_specification_contains method_attrs SN.UserAttributes.uaMutable
||
1471 attribute_specification_contains method_attrs SN.UserAttributes.uaMaybeMutable
||
1472 attribute_specification_contains method_attrs SN.UserAttributes.uaMutableReturn
1474 then make_error_from_node node
1475 SyntaxError.mutability_annotation_on_constructor
:: errors
1477 let fun_semicolon = md
.methodish_semicolon
in
1479 produce_error errors
1480 (methodish_non_abstract_without_body_not_native env node
) ()
1481 (SyntaxError.error2015
class_name method_name) fun_semicolon in
1483 produce_error errors
1484 methodish_abstract_conflict_with_private
1485 node
(SyntaxError.error2016
class_name method_name) modifiers in
1487 produce_error errors
1488 methodish_abstract_conflict_with_final
1489 node
(SyntaxError.error2019
class_name method_name) modifiers in
1491 produce_error errors
1492 (methodish_abstract_inside_interface env
.context)
1493 node
SyntaxError.error2045
modifiers in
1495 methodish_memoize_lsb_on_non_static node
errors in
1496 let async_annotation = Option.value (extract_async_node node
) ~default
:node
in
1498 produce_error errors
1499 (is_interface_and_async_method node
) env
.context
1500 (SyntaxError.error2046
"a method in an interface") async_annotation in
1502 produce_error errors
1503 (is_abstract_and_async_method node
) env
.context
1504 (SyntaxError.error2046
"an abstract method") async_annotation in
1506 if is_typechecker env
1507 then produce_error errors
1508 contains_async_not_last
1509 modifiers SyntaxError.async_not_last
modifiers
1512 special_method_param_errors
1513 md
.methodish_function_decl_header env
.context errors in
1515 produce_error errors
1516 methodish_multiple_reactivity_annotations node
1517 SyntaxError.multiple_reactivity_annotations
method_attrs in
1519 check_nonrx_annotation node
errors in
1521 produce_error errors
1522 methodish_missing_reactivity_for_condition node
1523 SyntaxError.missing_reactivity_for_condition
method_attrs in
1525 produce_error errors
1526 methodish_contains_owned_mutable_attribute node
1527 SyntaxError.misplaced_owned_mutable
method_attrs in
1531 let is_hashbang text =
1532 match Syntax.extract_text
text with
1535 let r = Str.regexp
"^#!.*\n" in
1536 let count = List.length
@@ String_utils.split_on_newlines
text in
1537 count = 1 && Str.string_match
r text 0 && Str.matched_string
text = text
1539 let class_has_a_construct_method context =
1540 match first_parent_classish_node TokenKind.Class
context with
1541 | Some
({ syntax
= ClassishDeclaration
1543 { syntax
= ClassishBody
1544 { classish_body_elements
= methods
; _}; _}; _}; _}) ->
1545 let methods = syntax_to_list_no_separators methods in
1546 List.exists
methods ~f
:(function
1547 { syntax
= MethodishDeclaration
1548 { methodish_function_decl_header
=
1549 { syntax
= FunctionDeclarationHeader
1550 { function_name
; _}; _}; _}; _} ->
1551 String.lowercase
@@ text function_name
= SN.Members.__construct
1555 let is_in_construct_method context = if is_immediately_in_lambda context then false else
1556 match first_parent_function_name context, first_parent_class_name context with
1558 (* Function name is __construct *)
1559 | Some
s, _ when String.lowercase
s = SN.Members.__construct
-> true
1560 (* Function name is same as class name *)
1561 | Some s1
, Some s2
->
1562 context.nested_namespaces
= [] &&
1563 not
@@ class_has_a_construct_method context &&
1564 String.lowercase s1
= String.lowercase s2
1568 (* If a variadic parameter has a default value, return it *)
1569 let variadic_param_with_default_value params =
1570 Option.filter
(variadic_param params) ~f
:is_parameter_with_default_value
1572 (* If a variadic parameter is marked inout, return it *)
1573 let variadic_param_with_callconv params =
1574 Option.filter
(variadic_param params) ~f
:is_parameter_with_callconv
1576 (* If an inout parameter has a default, return the default *)
1577 let param_with_callconv_has_default node
=
1578 match syntax node
with
1579 | ParameterDeclaration
{ parameter_default_value
; _ } when
1580 is_parameter_with_callconv node
&&
1581 is_parameter_with_default_value node
-> Some parameter_default_value
1584 (* If an inout parameter is passed by reference, return it *)
1585 let param_with_callconv_is_byref node
=
1586 match syntax node
with
1587 | ParameterDeclaration
{ parameter_name
; _ } when
1588 is_parameter_with_callconv node
&&
1589 is_byref_parameter_variable parameter_name
-> Some node
1592 let params_errors _env
params _namespace_name
names errors =
1594 produce_error_from_check errors ends_with_variadic_comma
1595 params SyntaxError.error2022
in
1597 produce_error_from_check errors misplaced_variadic_param
1598 params SyntaxError.error2021
in
1600 produce_error_from_check errors variadic_param_with_default_value
1601 params SyntaxError.error2065
in
1603 produce_error_from_check errors variadic_param_with_callconv
1604 params SyntaxError.error2073
in
1605 let param_list = syntax_to_list_no_separators params in
1606 let has_inout_param, has_reference_param
, has_inout_and_ref_param
=
1607 List.fold_right
param_list ~init
:(false, false, false)
1608 ~f
:begin fun p
(b1
, b2
, b3
) ->
1609 let is_inout = is_parameter_with_callconv p
in
1610 let is_ref = is_param_by_ref p
in
1611 b1
|| is_inout, b2
|| is_ref, b3
|| (is_inout && is_ref)
1614 let errors = if has_inout_param && has_reference_param
then
1615 let error_type = if has_inout_and_ref_param
then
1616 SyntaxError.ParseError
else SyntaxError.RuntimeError
in
1617 make_error_from_node ~
error_type
1618 params SyntaxError.fn_with_inout_and_ref_params
:: errors
1623 let decoration_errors node
errors =
1624 let errors = produce_error errors is_double_variadic node
SyntaxError.double_variadic node
in
1625 let errors = produce_error errors is_double_reference node
SyntaxError.double_reference node
in
1628 let parameter_rx_errors context errors node
=
1629 match syntax node
with
1630 | ParameterDeclaration
{ parameter_attribute
= spec
; parameter_name
= name; _ } ->
1631 let has_owned_mutable =
1632 attribute_specification_contains spec
SN.UserAttributes.uaOwnedMutable
in
1635 attribute_specification_contains spec
SN.UserAttributes.uaMutable
in
1636 let has_maybemutable =
1637 attribute_specification_contains spec
SN.UserAttributes.uaMaybeMutable
in
1639 match has_mutable, has_owned_mutable, has_maybemutable with
1641 make_error_from_node node
1642 SyntaxError.conflicting_mutable_and_owned_mutable_attributes
:: errors
1644 make_error_from_node node
1645 SyntaxError.conflicting_mutable_and_maybe_mutable_attributes
:: errors
1647 make_error_from_node node
1648 SyntaxError.conflicting_owned_mutable_and_maybe_mutable_attributes
:: errors
1651 if (has_mutable || has_owned_mutable || has_maybemutable) &&
1652 is_variadic_expression name
1653 then make_error_from_node name SyntaxError.vararg_and_mutable
:: errors
1655 let is_inout = is_parameter_with_callconv node
in
1657 if is_inout && (has_mutable || has_maybemutable || has_owned_mutable)
1658 then make_error_from_node
1659 node
SyntaxError.mutability_annotation_on_inout_parameter
:: errors
1663 if has_owned_mutable || has_mutable
1665 let attrs = context.active_callable_attr_spec
in
1666 let active_is_rx = context.active_is_rx_or_enclosing_for_lambdas
in
1667 let parent_func_is_memoize =
1668 Option.value_map
attrs ~default
:false ~f
:(fun spec
->
1669 attribute_specification_contains spec
SN.UserAttributes.uaMemoize
||
1670 attribute_specification_contains spec
SN.UserAttributes.uaMemoize
1673 if has_owned_mutable && not
active_is_rx
1674 then make_error_from_node node
1675 SyntaxError.mutably_owned_attribute_on_non_rx_function
:: errors
1679 if has_mutable && parent_func_is_memoize
1680 then make_error_from_node node
1681 (SyntaxError.mutable_parameter_in_memoize_function ~is_this
:false) :: errors
1692 let does_binop_create_write_on_left = function
1693 | Some
(TokenKind.Equal
1694 | TokenKind.BarEqual
1695 | TokenKind.PlusEqual
1696 | TokenKind.StarEqual
1697 | TokenKind.StarStarEqual
1698 | TokenKind.SlashEqual
1699 | TokenKind.DotEqual
1700 | TokenKind.MinusEqual
1701 | TokenKind.PercentEqual
1702 | TokenKind.CaratEqual
1703 | TokenKind.AmpersandEqual
1704 | TokenKind.LessThanLessThanEqual
1705 | TokenKind.GreaterThanGreaterThanEqual
1706 | TokenKind.QuestionQuestionEqual
) -> true
1709 let does_unop_create_write = function
1710 | Some
(TokenKind.PlusPlus
| TokenKind.MinusMinus
| TokenKind.Ampersand
) -> true
1713 let does_decorator_create_write = function
1714 | Some
(TokenKind.Inout
) -> true
1717 type lval_type
= LvalTypeNone
| LvalTypeNonFinal
| LvalTypeFinal
| LvalTypeNonFinalInout
1719 let node_lval_type node parents
=
1720 let rec is_in_final_lval_position node parents
=
1722 | ExpressionStatement
_ :: _ -> true
1724 for_initializer
= { syntax
= for_initializer
; _ };
1725 for_end_of_loop
= { syntax
= for_end_of_loop
; _ }; _
1727 when phys_equal for_initializer node
|| phys_equal for_end_of_loop node
->
1729 | (UsingStatementFunctionScoped
{ using_function_expression
= { syntax
= e; _ }; _ }
1730 | UsingStatementBlockScoped
{ using_block_expressions
= { syntax
= e; _ }; _ }) :: _
1731 when phys_equal
e node
-> true
1732 | (SyntaxList
_ | ListItem
_) as node
:: parents
->
1733 is_in_final_lval_position node parents
1736 let rec get_arg_call_node_with_parents node parents
=
1738 | (SyntaxList
_ | ListItem
_) as next_node
:: next_parents
->
1739 get_arg_call_node_with_parents next_node next_parents
1740 | (FunctionCallExpression
{
1741 function_call_argument_list
= { syntax
= arg_list
; _ }; _ }
1742 ) as call_expression
:: parents
when phys_equal arg_list node
->
1744 | PrefixUnaryExpression
{
1745 prefix_unary_operator
= token
; _
1746 } as next_node
:: next_parents
1747 when Some
TokenKind.At
= token_kind token
->
1748 Some
(next_node
, next_parents
)
1750 Some
(call_expression
, parents
))
1753 let lval_ness_of_function_arg_for_inout next_node next_parents
=
1754 (match get_arg_call_node_with_parents next_node next_parents
with
1755 | None
-> LvalTypeNone
1756 | Some
(call_node
, call_parents
) ->
1757 if is_in_final_lval_position call_node call_parents
1759 else (match call_parents
with
1760 | BinaryExpression
{
1761 binary_operator
= token
;
1762 binary_right_operand
= { syntax
= rval
; _ };
1763 _ } as next_node
:: next_parents
1764 when phys_equal rval call_node
&&
1765 does_binop_create_write_on_left (token_kind token
) ->
1766 if is_in_final_lval_position next_node next_parents
1768 else LvalTypeNonFinalInout
1769 | _ -> LvalTypeNonFinalInout
)
1772 | DecoratedExpression
{
1773 decorated_expression_decorator
= token
;
1774 decorated_expression_expression
= { syntax
= lval
; _ }
1775 } as next_node
:: next_parents
1776 when phys_equal lval node
&&
1777 does_decorator_create_write (token_kind token
) ->
1778 lval_ness_of_function_arg_for_inout next_node next_parents
1780 | PrefixUnaryExpression
{
1781 prefix_unary_operator
= token
;
1782 prefix_unary_operand
= { syntax
= lval
; _ }
1784 when phys_equal lval node
&&
1785 Some
TokenKind.Ampersand
= token_kind token
->
1788 | (PrefixUnaryExpression
{
1789 prefix_unary_operator
= token
;
1790 prefix_unary_operand
= { syntax
= lval
; _ }
1792 | PostfixUnaryExpression
{
1793 postfix_unary_operator
= token
;
1794 postfix_unary_operand
= { syntax
= lval
; _ }
1795 }) as next_node
:: next_parents
1796 when phys_equal lval node
&&
1797 does_unop_create_write (token_kind token
) ->
1798 if is_in_final_lval_position next_node next_parents
1800 else LvalTypeNonFinal
1802 | BinaryExpression
{
1803 binary_operator
= token
;
1804 binary_left_operand
= { syntax
= lval
; _ };
1805 _ } as next_node
:: next_parents
1806 when phys_equal lval node
&&
1807 does_binop_create_write_on_left (token_kind token
) ->
1808 if is_in_final_lval_position next_node next_parents
1810 else LvalTypeNonFinal
1812 | ForeachStatement
{
1813 foreach_key
= { syntax
= key
; _ };
1814 foreach_value
= { syntax
= value; _ };
1816 when phys_equal key node
|| phys_equal
value node
->
1821 let lval_errors env syntax_node parents
errors =
1822 if not
(ParserOptions.disable_lval_as_an_expression env
.parser_options
) then errors else
1823 let node = syntax syntax_node
in
1824 let parents = List.map ~f
:syntax
parents in
1825 match node_lval_type node parents with
1827 | LvalTypeNonFinalInout
1828 | LvalTypeNone
-> errors
1829 | LvalTypeNonFinal
->
1830 make_error_from_node syntax_node
SyntaxError.lval_as_expression
:: errors
1833 let parameter_errors env
node namespace_name
names errors =
1834 match syntax
node with
1835 | ParameterDeclaration p
->
1837 let callconv_text = Option.value (extract_callconv_node node) ~default
:node
1840 produce_error_from_check errors param_with_callconv_has_default
1841 node (SyntaxError.error2074
callconv_text) in
1842 let errors = parameter_rx_errors env
.context errors node in
1844 produce_error_from_check errors param_with_callconv_is_byref
1845 node (SyntaxError.error2075
callconv_text) in
1847 check_type_hint env p
.parameter_type
names errors in
1848 let errors = if is_parameter_with_callconv node then
1851 if is_inside_async_method env
.context then
1852 make_error_from_node ~
error_type:SyntaxError.RuntimeError
1853 node SyntaxError.inout_param_in_async
:: errors
1856 if is_in_construct_method env
.context then
1857 make_error_from_node ~
error_type:SyntaxError.RuntimeError
1858 node SyntaxError.inout_param_in_construct
:: errors
1860 let inMemoize = first_parent_function_attributes_contains
1861 env
.context SN.UserAttributes.uaMemoize
in
1862 let inMemoizeLSB = first_parent_function_attributes_contains
1863 env
.context SN.UserAttributes.uaMemoizeLSB
in
1864 let errors = if (inMemoize || inMemoizeLSB) &&
1865 not
@@ is_immediately_in_lambda env
.context then
1866 make_error_from_node ~
error_type:SyntaxError.RuntimeError
1867 node SyntaxError.memoize_with_inout
:: errors
1873 if is_reference_variadic p
.parameter_name
then
1874 make_error_from_node node SyntaxError.variadic_reference
:: errors
1875 else if is_variadic_reference p
.parameter_name
then
1876 make_error_from_node node SyntaxError.reference_variadic
:: errors
1879 | FunctionDeclarationHeader
{ function_parameter_list
= params; _ }
1880 | AnonymousFunction
{ anonymous_parameters
= params; _ }
1881 | ClosureTypeSpecifier
{ closure_parameter_list
= params; _ }
1883 { lambda_signature
= {syntax
= LambdaSignature
{ lambda_parameters
= params; _ }; _}
1887 syntax_to_list_no_separators params
1888 |> List.fold_left ~init
:errors ~f
:(parameter_rx_errors env
.context) in
1889 params_errors env
params namespace_name
names errors
1890 | DecoratedExpression
_ -> names, decoration_errors node errors
1891 | _ -> names, errors
1894 let redeclaration_errors env
node parents namespace_name
names errors =
1895 match syntax
node with
1896 | FunctionDeclarationHeader f
when not
(is_missing f
.function_name
)->
1897 begin match parents with
1898 | { syntax
= FunctionDeclaration
_; _}
1899 :: _ :: {syntax
= NamespaceBody
_; _} :: _
1900 | [{ syntax
= FunctionDeclaration
_; _ }; _; _]
1901 | { syntax
= MethodishDeclaration
_; _ } :: _
1902 | { syntax
= MethodishTraitResolution
_; _ } :: _ ->
1903 let function_name = text f
.function_name in
1904 let location = make_location_of_node f
.function_name in
1905 let is_method = match parents with
1906 | { syntax
= MethodishDeclaration
_; _ } :: _ -> true
1909 let def = make_first_use_or_def ~
is_method
1910 ~
kind:Name_def
location namespace_name
function_name in
1912 match strmap_get function_name names.t_functions
with
1913 | Some
{ f_location
= { start_offset; _}; f_kind
= Name_def
; f_global
; _ }
1914 when f_global
= def.f_global
->
1915 let text = SyntaxTree.text env
.syntax_tree
in
1917 Full_fidelity_source_text.offset_to_position
text start_offset in
1919 Relative_path.to_absolute
@@
1920 Full_fidelity_source_text.file_path
text in
1921 let loc = path ^
":" ^ string_of_int
line in
1922 let err, error_type =
1923 match first_parent_class_name env
.context with
1925 SyntaxError.redeclaration_of_function ~
name:function_name ~
loc,
1926 SyntaxError.RuntimeError
1927 | Some
class_name ->
1928 let full_name = class_name ^
"::" ^
function_name in
1929 SyntaxError.redeclaration_of_method ~
name:full_name,
1930 SyntaxError.ParseError
1932 make_error_from_node ~
error_type node err :: errors
1936 t_functions
= strmap_add function_name def names.t_functions
}, errors
1938 if not
(is_typechecker env
) then names, errors else
1939 let error = make_error_from_node
1940 ~
error_type:SyntaxError.ParseError
1942 SyntaxError.decl_outside_global_scope
1944 names, error :: errors
1946 | _ -> names, errors
1948 let is_foreach_in_for for_initializer
=
1949 match syntax_node_to_list for_initializer
with
1950 | ( { syntax
= ListItem
{ list_item
= item
; _ }; _ } :: _) ->
1951 is_as_expression item
1954 let statement_errors env
node parents errors =
1955 let result = match syntax
node with
1956 | TryStatement
{ try_catch_clauses
; try_finally_clause
; _ }
1957 when (is_missing try_catch_clauses
) && (is_missing try_finally_clause
) ->
1958 Some
(node, SyntaxError.error2007
)
1959 | UsingStatementFunctionScoped
_
1960 when not
(using_statement_function_scoped_is_legal parents) ->
1961 Some
(node, SyntaxError.using_st_function_scoped_top_level
)
1962 | ForStatement
{ for_initializer
; _ }
1963 when is_foreach_in_for for_initializer
->
1964 Some
(node, SyntaxError.for_with_as_expression
)
1978 } when is_typechecker env
&& Token.kind m
<> TokenKind.Colon
->
1979 Some
(colon
, SyntaxError.error1020
)
1983 | Some
(error_node
, error_message
) ->
1984 make_error_from_node error_node error_message
:: errors
1986 let check_collection_element m error_text
errors =
1988 | PrefixUnaryExpression
1989 { prefix_unary_operator
= { syntax
= Token token
; _ }; _ }
1990 when Token.kind token
= TokenKind.Ampersand
->
1991 make_error_from_node m error_text
:: errors
1994 let check_collection_member errors m
=
1996 | ElementInitializer
{ element_key
; element_value
; _ } ->
1998 check_collection_element element_key
1999 SyntaxError.reference_not_allowed_on_key
errors in
2001 check_collection_element element_value
2002 SyntaxError.reference_not_allowed_on_value
errors in
2005 check_collection_element m
2006 SyntaxError.reference_not_allowed_on_element
errors
2008 let check_collection_members members
errors =
2009 syntax_to_list_no_separators members
2010 |> List.fold_left ~init
:errors ~f
:check_collection_member
2012 let invalid_shape_initializer_name env
node errors =
2013 match syntax
node with
2014 | LiteralExpression
{ literal_expression
= expr
} ->
2016 begin match token_kind expr
with
2017 | Some
TokenKind.SingleQuotedStringLiteral
-> true
2018 (* TODO: Double quoted string are only legal
2019 * if they contain no encapsulated expressions. *)
2020 | Some
TokenKind.DoubleQuotedStringLiteral
-> true
2025 then make_error_from_node node SyntaxError.invalid_shape_field_name
:: errors
2027 | ScopeResolutionExpression
_ -> errors
2028 | QualifiedName
_ ->
2029 if is_typechecker env
then
2030 make_error_from_node node SyntaxError.invalid_shape_field_name
:: errors
2032 | Token
_ when is_name
node ->
2033 if is_typechecker env
then
2034 make_error_from_node node SyntaxError.invalid_shape_field_name
:: errors
2037 | _ -> make_error_from_node node SyntaxError.invalid_shape_field_name
:: errors
2039 let invalid_shape_field_check env
node errors =
2040 match syntax
node with
2041 | FieldInitializer
{ field_initializer_name
; _} ->
2042 invalid_shape_initializer_name env field_initializer_name
errors
2043 | _ -> make_error_from_node node SyntaxError.invalid_shape_field_name
:: errors
2045 let is_in_unyieldable_magic_method context =
2046 match first_parent_function_name context with
2049 let s = String.lowercase
s in
2051 | _ when s = SN.Members.__call
-> false
2052 | _ when s = SN.Members.__invoke
-> false
2053 | _ -> SSet.mem
s SN.Members.as_lowercase_set
2056 let function_call_argument_errors ~in_constructor_call
node errors =
2057 match syntax
node with
2058 | PrefixUnaryExpression
2059 { prefix_unary_operator
= { syntax
= Token token
; _ }
2060 ; prefix_unary_operand
2061 } when Token.kind token
= TokenKind.Ampersand
&&
2062 SN.Superglobals.is_superglobal
@@ text prefix_unary_operand
->
2063 make_error_from_node node SyntaxError.error2078
:: errors
2064 | DecoratedExpression
2065 { decorated_expression_decorator
= { syntax
= Token token
; _ }
2066 ; decorated_expression_expression
= expression
2067 } when Token.kind token
= TokenKind.Inout
->
2069 if in_constructor_call
then Some
SyntaxError.inout_param_in_construct
else
2070 match syntax expression
with
2071 | BinaryExpression
_ ->
2072 Some
SyntaxError.fun_arg_inout_set
2073 | QualifiedName
_ ->
2074 Some
SyntaxError.fun_arg_inout_const
2075 | Token
_ when is_name expression
->
2076 Some
SyntaxError.fun_arg_inout_const
2077 (* TODO: Maybe be more descriptive in error messages *)
2078 | ScopeResolutionExpression
_
2079 | FunctionCallExpression
_
2080 | MemberSelectionExpression
_
2081 | SafeMemberSelectionExpression
_
2082 | SubscriptExpression
2083 { subscript_receiver
= {
2085 (MemberSelectionExpression
_ | ScopeResolutionExpression
_)
2087 }; _ } -> Some
SyntaxError.fun_arg_invalid_arg
2088 | SubscriptExpression
{ subscript_receiver
; _ }
2089 when SN.Superglobals.is_superglobal
@@ text subscript_receiver
->
2090 Some
SyntaxError.fun_arg_inout_containers
2093 begin match result with
2095 | Some
e -> make_error_from_node node e :: errors
2099 let function_call_on_xhp_name_errors env
node errors =
2100 match syntax
node with
2101 | MemberSelectionExpression
{ member_object
; member_name
= name; _ }
2102 | SafeMemberSelectionExpression
{
2103 safe_member_object
=member_object
;
2104 safe_member_name
= name; _ } ->
2106 begin match syntax member_object
with
2107 | XHPExpression
_ when is_typechecker env
->
2109 make_error_from_node node SyntaxError.method_calls_on_xhp_expression
in
2113 begin match syntax
name with
2114 | Token token
when Token.kind token
= TokenKind.XHPClassName
->
2116 make_error_from_node node SyntaxError.method_calls_on_xhp_attributes
in
2122 let no_async_before_lambda_body env body_node
errors =
2123 match syntax body_node
with
2124 | AwaitableCreationExpression
_ when is_typechecker env
->
2125 (make_error_from_node body_node
SyntaxError.no_async_before_lambda_body)
2129 let no_memoize_attribute_on_lambda node errors =
2130 match syntax
node with
2131 | AttributeSpecification
{ attribute_specification_attributes
= attrs; _ } ->
2132 List.fold
(syntax_node_to_list
attrs) ~init
:errors ~f
:begin fun errors n
->
2135 list_item
= ({ syntax
= ConstructorCall
{ constructor_call_type
; _ }; _ } as attr
);_
2137 begin match Syntax.extract_text constructor_call_type
with
2138 | Some n
when n
= SN.UserAttributes.uaMemoize
->
2140 make_error_from_node attr
SyntaxError.memoize_on_lambda
in
2142 | Some n
when n
= SN.UserAttributes.uaMemoizeLSB
->
2144 make_error_from_node attr
SyntaxError.memoize_on_lambda
in
2152 let is_good_scope_resolution_qualifier node =
2153 match syntax
node with
2154 | QualifiedName
_ -> true
2156 let open TokenKind
in
2157 (match Token.kind token
with
2158 | XHPClassName
| Name
| Self
| Parent
| Static
-> true
2163 let new_variable_errors node =
2164 let rec helper node ~inside_scope_resolution
=
2165 match syntax
node with
2166 | SimpleTypeSpecifier
_ -> []
2167 | VariableExpression
_ -> []
2168 | GenericTypeSpecifier
_ -> []
2169 | PipeVariableExpression
_ -> []
2170 | SubscriptExpression
{ subscript_index
= { syntax
= Missing
; _ }; _ } ->
2171 [ make_error_from_node node SyntaxError.instanceof_missing_subscript_index
]
2172 | SubscriptExpression
{ subscript_receiver
; _ } ->
2173 helper subscript_receiver ~inside_scope_resolution
2174 | MemberSelectionExpression
{ member_object
; _ } ->
2175 if inside_scope_resolution
2177 make_error_from_node node SyntaxError.instanceof_memberselection_inside_scoperesolution
2179 else helper member_object ~inside_scope_resolution
2180 | ScopeResolutionExpression
2182 scope_resolution_qualifier
;
2183 scope_resolution_name
= { syntax
= Token
name; _ };
2185 } when is_good_scope_resolution_qualifier scope_resolution_qualifier
2186 && Token.kind name = TokenKind.Variable
-> []
2187 | ScopeResolutionExpression
2189 scope_resolution_qualifier
;
2190 scope_resolution_name
= { syntax
= Token
name; _ };
2192 } when Token.kind name = TokenKind.Variable
->
2193 helper scope_resolution_qualifier ~inside_scope_resolution
:true
2194 | ScopeResolutionExpression
_ ->
2195 [ make_error_from_node node SyntaxError.instanceof_invalid_scope_resolution
]
2198 let error_msg = SyntaxError.instanceof_new_unknown_node
2199 (SyntaxKind.to_string
@@ kind node) in
2200 [ make_error_from_node node error_msg ]
2202 helper node ~inside_scope_resolution
:false
2204 let class_type_designator_errors node =
2205 if is_good_scope_resolution_qualifier node then [] else
2206 match syntax
node with
2207 | ParenthesizedExpression
2209 parenthesized_expression_expression
= {
2210 syntax
= PrefixUnaryExpression
{ prefix_unary_operator
= { syntax
= Token token
; _ }; _ };
2215 when Token.kind token
= TokenKind.Ampersand
->
2216 [make_error_from_node node SyntaxError.instanceof_reference
]
2217 | ParenthesizedExpression
_ ->
2218 (* A parenthesized expression that evaluates to a string or object is a
2219 valid RHS for instanceof and new. *)
2221 | _ -> new_variable_errors node
2223 let rec check_reference node errors =
2224 match syntax
node with
2225 | PrefixUnaryExpression
{ prefix_unary_operator
; _ }
2226 when token_kind prefix_unary_operator
<> Some
TokenKind.Dollar
->
2227 make_error_from_node node SyntaxError.nested_unary_reference
:: errors
2228 | FunctionCallExpression
_
2229 | VariableExpression
_ -> errors
2230 | Token token
when Token.kind token
= TokenKind.Variable
-> errors
2231 | PrefixUnaryExpression
{
2232 prefix_unary_operator
= { syntax
= Token token
; _ };
2233 prefix_unary_operand
= {
2234 syntax
= PrefixUnaryExpression
{ prefix_unary_operator
= op
; _ };
2237 } when Token.kind token
= TokenKind.Dollar
&& token_kind op
= Some
TokenKind.Dollar
->
2239 | PrefixUnaryExpression
{
2240 prefix_unary_operator
= { syntax
= Token token
; _ };
2241 prefix_unary_operand
= { syntax
= BracedExpression
_ | VariableExpression
_; _ }
2242 } when Token.kind token
= TokenKind.Dollar
-> errors
2243 | ParenthesizedExpression
{ parenthesized_expression_expression
; _ } ->
2244 check_reference parenthesized_expression_expression
errors
2245 | _ -> make_error_from_node node SyntaxError.invalid_reference
:: errors
2247 let rec_walk ~init ~f
node =
2248 let rec rec_walk_impl parents init
node =
2249 let new_init, continue_walk
= f init
node parents in
2250 if continue_walk
then
2253 ~f
:(rec_walk_impl ((syntax
node) :: parents))
2254 (Syntax.children
node)
2256 rec_walk_impl [] init
node
2258 let does_binop_create_write_on_left = function
2259 | Some
(TokenKind.Equal
2260 | TokenKind.BarEqual
2261 | TokenKind.PlusEqual
2262 | TokenKind.StarEqual
2263 | TokenKind.StarStarEqual
2264 | TokenKind.SlashEqual
2265 | TokenKind.DotEqual
2266 | TokenKind.MinusEqual
2267 | TokenKind.PercentEqual
2268 | TokenKind.CaratEqual
2269 | TokenKind.AmpersandEqual
2270 | TokenKind.LessThanLessThanEqual
2271 | TokenKind.GreaterThanGreaterThanEqual
2272 | TokenKind.QuestionQuestionEqual
) -> true
2275 let find_invalid_lval_usage nodes
=
2276 let get_errors = rec_walk ~f
:(fun errors syntax_node
parents ->
2277 let node = syntax syntax_node
in
2279 | AnonymousFunction
_
2280 | LambdaExpression
_
2281 | AwaitableCreationExpression
_ ->
2284 let errors = match node_lval_type node parents with
2286 | LvalTypeNone
-> errors
2287 | LvalTypeNonFinalInout
2288 | LvalTypeNonFinal
->
2289 make_error_from_node syntax_node
SyntaxError.lval_as_expression
:: errors in
2295 ~f
:(fun acc node -> get_errors ~init
:acc node)
2298 type binop_allows_await_in_positions
=
2299 | BinopAllowAwaitBoth
2300 | BinopAllowAwaitLeft
2301 | BinopAllowAwaitRight
2302 | BinopAllowAwaitNone
2304 let get_positions_binop_allows_await t
=
2305 (match token_kind t
with
2306 | None
-> BinopAllowAwaitNone
2307 | Some t
-> (match t
with
2309 | TokenKind.AmpersandAmpersand
2310 | TokenKind.QuestionColon
2311 | TokenKind.QuestionQuestion
2312 | TokenKind.BarGreaterThan
-> BinopAllowAwaitLeft
2314 | TokenKind.BarEqual
2315 | TokenKind.PlusEqual
2316 | TokenKind.StarEqual
2317 | TokenKind.StarStarEqual
2318 | TokenKind.SlashEqual
2319 | TokenKind.DotEqual
2320 | TokenKind.MinusEqual
2321 | TokenKind.PercentEqual
2322 | TokenKind.CaratEqual
2323 | TokenKind.AmpersandEqual
2324 | TokenKind.LessThanLessThanEqual
2325 | TokenKind.GreaterThanGreaterThanEqual
-> BinopAllowAwaitRight
2330 | TokenKind.StarStar
2331 | TokenKind.EqualEqualEqual
2332 | TokenKind.LessThan
2333 | TokenKind.GreaterThan
2336 | TokenKind.EqualEqual
2337 | TokenKind.ExclamationEqual
2338 | TokenKind.ExclamationEqualEqual
2339 | TokenKind.LessThanEqual
2340 | TokenKind.LessThanEqualGreaterThan
2341 | TokenKind.GreaterThanEqual
2342 | TokenKind.Ampersand
2344 | TokenKind.LessThanLessThan
2345 | TokenKind.GreaterThanGreaterThan
2346 | TokenKind.Carat
-> BinopAllowAwaitBoth
2347 | TokenKind.QuestionQuestionEqual
2348 | _ -> BinopAllowAwaitNone
2351 let unop_allows_await t
=
2352 (match token_kind t
with
2354 | Some t
-> (match t
with
2355 | TokenKind.Exclamation
2361 | TokenKind.Print
-> true
2365 let await_as_an_expression_errors await_node
parents =
2366 let rec go parents node =
2369 | head
:: tail
-> head
, tail
2370 | _ -> failwith
"Unexpect missing parent"
2373 (* statements that root for the concurrently executed await expressions *)
2374 | ExpressionStatement
_
2379 | LetStatement
_ -> []
2380 | IfStatement
{ if_condition
; _ }
2381 when phys_equal
node if_condition
-> []
2382 | ForStatement
{ for_initializer
; _ }
2383 when phys_equal
node for_initializer
-> []
2384 | SwitchStatement
{ switch_expression
; _ }
2385 when phys_equal
node switch_expression
-> []
2386 | ForeachStatement
{ foreach_collection
; _ }
2387 when phys_equal
node foreach_collection
-> []
2388 | UsingStatementBlockScoped
{ using_block_expressions
; _ }
2389 when phys_equal
node using_block_expressions
-> []
2390 | UsingStatementFunctionScoped
{ using_function_expression
; _ }
2391 when phys_equal
node using_function_expression
-> []
2392 | LambdaExpression
{ lambda_body
; _ }
2393 when phys_equal
node lambda_body
-> []
2395 (* Dependent awaits are not allowed currently *)
2396 | PrefixUnaryExpression
{ prefix_unary_operator
= op
; _ }
2397 when token_kind op
= Some
TokenKind.Await
->
2398 [make_error_from_node
2399 await_node
SyntaxError.invalid_await_position_dependent
]
2401 (* Unary based expressions have their own custom fanout *)
2402 | PrefixUnaryExpression
{ prefix_unary_operator
= operator
; _ }
2403 | PostfixUnaryExpression
{ postfix_unary_operator
= operator
; _ }
2404 | DecoratedExpression
{ decorated_expression_decorator
= operator
; _ }
2405 when unop_allows_await operator
-> go tail
n
2407 left or right operand of binary expressions are considered legal locations
2408 if operator is not short-circuiting and containing expression
2409 is in legal location *)
2410 | BinaryExpression
{
2411 binary_left_operand
= l
;
2412 binary_right_operand
= r;
2413 binary_operator
= op
;
2416 (match get_positions_binop_allows_await op
with
2417 | BinopAllowAwaitBoth
-> true
2418 | BinopAllowAwaitLeft
-> phys_equal
node l
2419 | BinopAllowAwaitRight
-> phys_equal
node r
2420 | BinopAllowAwaitNone
-> false) ->
2422 (* test part of conditional expression is considered legal location if
2423 conditional expression itself is in legal location *)
2424 | ConditionalExpression
{
2425 conditional_test
= test
; _
2426 } when phys_equal
node test
-> go tail
n
2427 | FunctionCallExpression
{
2428 function_call_receiver
= r;
2429 function_call_argument_list
= args; _
2431 when phys_equal
node r ||
2432 (phys_equal
node args && not
(is_safe_member_selection_expression
r))
2434 (* object of member selection expression or safe member selection expression
2435 is in legal position if member selection expression itself is in legal position *)
2436 | SafeMemberSelectionExpression
{
2437 safe_member_object
= o
; _
2438 } when phys_equal
node o
-> go tail
n
2439 (* These are nodes where any position is valid *)
2441 | MemberSelectionExpression
_
2442 | ScopeResolutionExpression
_
2443 | InstanceofExpression
_
2446 | NullableAsExpression
_
2448 | ParenthesizedExpression
_
2449 | BracedExpression
_
2450 | EmbeddedBracedExpression
_
2451 | CollectionLiteralExpression
_
2452 | ObjectCreationExpression
_
2456 | ArrayCreationExpression
_
2457 | ArrayIntrinsicExpression
_
2458 | DarrayIntrinsicExpression
_
2459 | DictionaryIntrinsicExpression
_
2460 | KeysetIntrinsicExpression
_
2461 | VarrayIntrinsicExpression
_
2462 | VectorIntrinsicExpression
_
2463 | ElementInitializer
_
2464 | FieldInitializer
_
2465 | SimpleInitializer
_
2466 | SubscriptExpression
_
2467 | EmbeddedSubscriptExpression
_
2471 | XHPSimpleAttribute
_
2472 | XHPSpreadAttribute
_
2474 | ListItem
_ -> go tail
n
2475 (* otherwise report error and bail out *)
2477 [make_error_from_node
2478 await_node
SyntaxError.invalid_await_position
]
2481 let conditional_errors = go parents await_node
in
2482 let is_in_concurrent = List.exists
2483 ~f
:(fun parent
-> match syntax parent
with
2484 | ConcurrentStatement
_ -> true
2487 let lval_errors = if is_in_concurrent then [] else
2488 let await_node_statement_parent = List.find
2489 ~f
:(fun parent
-> match syntax parent
with
2490 | ExpressionStatement
_
2498 | ForeachStatement
_ -> true
2501 match await_node_statement_parent with
2502 | Some x
-> find_invalid_lval_usage [x
]
2503 (* We must have already errored in "go" *)
2506 List.append
lval_errors conditional_errors
2508 let node_has_await_child = rec_walk ~init
:false ~f
:(fun acc node _ ->
2509 let is_new_scope = match syntax
node with
2510 | AnonymousFunction
_
2511 | LambdaExpression
_
2512 | AwaitableCreationExpression
_ ->
2515 if is_new_scope then false, false else
2516 let is_await n = match syntax
n with
2517 | PrefixUnaryExpression
{ prefix_unary_operator
= op
; _ }
2518 when token_kind op
= Some
TokenKind.Await
-> true
2520 let found_await = acc || is_await node in
2521 found_await, not
found_await
2524 let expression_errors env _is_in_concurrent_block namespace_name
node parents errors =
2525 let is_decimal_or_hexadecimal_literal token
=
2526 match Token.kind token
with
2527 | TokenKind.DecimalLiteral
| TokenKind.HexadecimalLiteral
-> true
2530 match syntax
node with
2531 (* It is ambiguous what `instanceof (A)` means: either instanceof a type A
2532 * or instanceof a type whose name is what the constant A evaluates to.
2533 * We therefore simply disallow this. *)
2534 | InstanceofExpression
2535 { instanceof_right_operand
=
2536 { syntax
= ParenthesizedExpression
2537 { parenthesized_expression_expression
=
2538 { syntax
= Token
_; _ } as in_paren
2541 ; _ } when is_typechecker env
->
2542 let in_paren = text in_paren in
2543 make_error_from_node node (SyntaxError.instanceof_paren
in_paren) :: errors
2544 (* We parse the right hand side of `new` and `instanceof` as a generic
2545 expression, but PHP (and therefore Hack) only allow a certain subset of
2546 expressions, so we should verify here that the expression we parsed is in
2548 Refer: https://github.com/php/php-langspec/blob/master/spec/10-expressions.md#instanceof-operator*)
2549 | ConstructorCall ctr_call
->
2550 let typechecker_errors =
2551 if is_typechecker env
then
2553 (* list item -> syntax list -> attribute *)
2554 | _ :: _ :: a
:: _ when
2555 is_attribute_specification a
|| is_file_attribute_specification a
->
2558 if (is_missing ctr_call
.constructor_call_left_paren
||
2559 is_missing ctr_call
.constructor_call_right_paren
)
2561 let node = ctr_call
.constructor_call_type
in
2562 let constructor_name = text ctr_call
.constructor_call_type
in
2563 [make_error_from_node node (SyntaxError.error2038
constructor_name)]
2567 let designator_errors = class_type_designator_errors ctr_call
.constructor_call_type
in
2569 let arg_list = syntax_to_list_no_separators ctr_call
.constructor_call_argument_list
in
2570 List.fold_right
arg_list ~init
:[]
2571 ~f
:(fun p
acc -> function_call_argument_errors ~in_constructor_call
:true p
acc)
2573 typechecker_errors @ designator_errors @ func_errors @ errors
2574 | InstanceofExpression
{ instanceof_right_operand
= operand
; _ } ->
2575 (class_type_designator_errors operand
) @ errors
2576 | LiteralExpression
{ literal_expression
= {syntax
= Token token
; _} as e ; _}
2577 when is_decimal_or_hexadecimal_literal token
->
2578 let text = text e in
2579 begin try ignore
(Int64.of_string
text); errors
2582 if Token.kind token
= TokenKind.DecimalLiteral
2583 then SyntaxError.error2071
text
2584 else SyntaxError.error2072
text in
2585 make_error_from_node node error_text :: errors
2587 | SubscriptExpression
{ subscript_left_bracket
; _}
2588 when (is_typechecker env
)
2589 && is_left_brace subscript_left_bracket
->
2590 make_error_from_node node SyntaxError.error2020
:: errors
2591 | HaltCompilerExpression
{ halt_compiler_argument_list
= args; _ } ->
2593 if List.is_empty
(syntax_to_list_no_separators args) then errors
2594 else make_error_from_node node SyntaxError.no_args_in_halt_compiler
:: errors in
2597 (* expression statement -> syntax list -> script *)
2598 | [_; _; _] -> errors
2599 | _ -> make_error_from_node node SyntaxError.halt_compiler_top_level_only
:: errors in
2601 | FunctionCallExpression
{
2602 function_call_argument_list
= arg_list;
2603 function_call_receiver
; _
2606 match misplaced_variadic_arg arg_list with
2608 make_error_from_node h
SyntaxError.error2033
:: errors
2611 let arg_list = syntax_to_list_no_separators arg_list in
2612 let errors = List.fold_right
arg_list ~init
:errors
2613 ~f
:(fun p
acc -> function_call_argument_errors ~in_constructor_call
:false p
acc)
2616 function_call_on_xhp_name_errors env function_call_receiver
errors in
2618 | ListExpression
{ list_members
; _ }
2619 when is_missing list_members
&& is_hhvm_compat env
->
2620 begin match parents with
2621 | { syntax
= ForeachStatement
{ foreach_value
; _ }; _ } :: _
2622 when phys_equal
node foreach_value
->
2623 make_error_from_node ~
error_type:SyntaxError.RuntimeError
node
2624 SyntaxError.error2077
:: errors
2627 | ListExpression
_ ->
2628 begin match parents with
2629 | e :: _ when is_return_statement
e ->
2630 make_error_from_node node SyntaxError.list_must_be_lvar
:: errors
2633 | ShapeExpression
{ shape_expression_fields
; _} ->
2634 List.fold_right ~f
:(invalid_shape_field_check env
)
2635 (syntax_to_list_no_separators shape_expression_fields
) ~init
:errors
2636 | DecoratedExpression
2637 { decorated_expression_decorator
= decorator
2638 ; decorated_expression_expression
=
2639 { syntax
= PrefixUnaryExpression
{ prefix_unary_operator
= operator
; _ }
2642 when is_inout decorator
&& is_ampersand operator
->
2643 make_error_from_node node SyntaxError.error2076
:: errors
2644 | VectorIntrinsicExpression
{ vector_intrinsic_members
= m
; _ }
2645 | DictionaryIntrinsicExpression
{ dictionary_intrinsic_members
= m
; _ }
2646 | KeysetIntrinsicExpression
{ keyset_intrinsic_members
= m
; _ }
2647 | ArrayCreationExpression
{ array_creation_members
= m
; _ }
2648 | ArrayIntrinsicExpression
{ array_intrinsic_members
= m
; _ }
2649 | VarrayIntrinsicExpression
{ varray_intrinsic_members
= m
; _ }
2650 | DarrayIntrinsicExpression
{ darray_intrinsic_members
= m
; _ } ->
2651 check_collection_members m
errors
2652 | YieldFromExpression
_
2653 | YieldExpression
_ ->
2655 if is_in_unyieldable_magic_method env
.context then
2656 make_error_from_node node SyntaxError.yield_in_magic_methods
:: errors
2658 let errors = match env
.context.active_callable
with
2660 | None
-> make_error_from_node node SyntaxError.yield_outside_function
:: errors
2663 if has_inout_params env
.context then
2665 if is_inside_async_method env
.context
2666 then SyntaxError.inout_param_in_async_generator
2667 else SyntaxError.inout_param_in_generator
in
2668 make_error_from_node ~
error_type:SyntaxError.RuntimeError
node e :: errors
2671 | ScopeResolutionExpression
2672 { scope_resolution_qualifier
= qualifier
2673 ; scope_resolution_name
= name
2675 let is_dynamic_name, is_self_or_parent
, is_valid
=
2676 (* PHP langspec allows string literals, variables
2677 qualified names, static, self and parent as valid qualifiers *)
2678 (* We do not allow string literals in hack *)
2679 match syntax qualifier
, token_kind qualifier
with
2680 | LiteralExpression
_, _ ->
2681 false, false, not
(is_typechecker env
)
2682 | QualifiedName
_, _ -> false, false, true
2683 | _, Some
TokenKind.Name
2684 | _, Some
TokenKind.XHPClassName
2685 | _, Some
TokenKind.Static
-> false, false, true
2686 | _, Some
TokenKind.Self
2687 | _, Some
TokenKind.Parent
-> false, true, true
2689 | PrefixUnaryExpression
{
2690 prefix_unary_operator
= op
; _
2691 }, _ when token_kind op
= Some
TokenKind.Dollar
->
2693 | PipeVariableExpression
_, _
2694 | VariableExpression
_, _
2695 | SimpleTypeSpecifier
_, _
2696 | GenericTypeSpecifier
_, _ -> true, false, true
2697 | _ -> true, false, not
(is_typechecker env
)
2699 let errors = if not is_valid
then
2700 make_error_from_node
2701 node SyntaxError.invalid_scope_resolution_qualifier
:: errors
2703 let is_name_class = String.lowercase
@@ text name = "class" in
2704 let errors = if is_dynamic_name && is_name_class then
2705 make_error_from_node
2706 node SyntaxError.coloncolonclass_on_dynamic
:: errors
2708 let text_name = text qualifier
in
2709 let is_name_namespace = String.lowercase
@@ text_name = "namespace" in
2710 let errors = if is_name_namespace
2711 then make_error_from_node ~
error_type:SyntaxError.ParseError
2712 node (SyntaxError.namespace_not_a_classname
)::errors
2714 let errors = if is_self_or_parent
&& is_name_class &&
2715 not
@@ is_in_active_class_scope env
.context
2716 then make_error_from_node ~
error_type:SyntaxError.RuntimeError
2717 node (SyntaxError.self_or_parent_colon_colon_class_outside_of_class
2718 @@ text qualifier
) :: errors
2721 | PrefixUnaryExpression
{ prefix_unary_operator
; prefix_unary_operand
}
2722 when token_kind prefix_unary_operator
= Some
TokenKind.Ampersand
->
2723 check_reference prefix_unary_operand
errors
2724 | PrefixUnaryExpression
{ prefix_unary_operator
; prefix_unary_operand
}
2725 when token_kind prefix_unary_operator
= Some
TokenKind.Dollar
->
2726 let original_node = node in
2727 let rec check_prefix_unary_dollar node =
2728 match syntax
node with
2729 | PrefixUnaryExpression
{ prefix_unary_operator
; prefix_unary_operand
}
2730 when token_kind prefix_unary_operator
= Some
TokenKind.Dollar
->
2731 check_prefix_unary_dollar prefix_unary_operand
2732 | BracedExpression
_
2733 | SubscriptExpression
_
2734 | VariableExpression
_ -> errors (* these ones are valid *)
2735 | LiteralExpression
_
2736 | PipeVariableExpression
_ -> errors (* these ones get caught later *)
2737 | _ -> make_error_from_node original_node SyntaxError.dollar_unary
:: errors
2739 check_prefix_unary_dollar prefix_unary_operand
2740 (* TODO(T21285960): Remove this bug-port, stemming from T22184312 *)
2741 | LambdaExpression
{ lambda_async
; lambda_coroutine
; lambda_signature
; _ }
2742 when is_hhvm_compat env
2743 && not
(is_missing lambda_async
)
2744 && trailing_width lambda_async
= 0
2745 && full_width lambda_coroutine
= 0
2746 && leading_width lambda_signature
= 0
2748 make_error_from_node node
2749 (SyntaxError.error1057
"==>") :: errors
2750 (* End of bug-port *)
2752 { is_right_operand
= hint
2756 { as_right_operand
= hint
2759 let n = match syntax
node with IsExpression
_ -> "is" | _ -> "as" in
2760 begin match syntax hint
with
2761 | ClosureTypeSpecifier
_ when env
.hhvm_compat_mode
<> NoCompat
->
2762 make_error_from_node hint
2763 (SyntaxError.invalid_is_as_expression_hint
n "Callable") :: errors
2764 | SoftTypeSpecifier
_ ->
2765 make_error_from_node hint
2766 (SyntaxError.invalid_is_as_expression_hint
n "Soft") :: errors
2769 | ConditionalExpression
2771 ; conditional_consequence
= cons
2772 ; conditional_alternative
2775 if is_missing cons
&& is_typechecker env
2776 then make_error_from_node node SyntaxError.elvis_operator_space
:: errors
2779 if is_conditional_expression conditional_test
&& is_typechecker env
2780 then make_error_from_node node SyntaxError.nested_ternary
:: errors
2782 begin match conditional_alternative
with
2783 | { syntax
= LambdaExpression
{ lambda_body
; _ }; _ }
2784 when is_conditional_expression lambda_body
&& is_typechecker env
->
2785 make_error_from_node node SyntaxError.nested_ternary
:: errors
2788 { lambda_attribute_spec
= s
2789 ; lambda_body
= body
2791 let errors = no_memoize_attribute_on_lambda s errors in
2792 no_async_before_lambda_body env
body errors
2793 | AnonymousFunction
{ anonymous_attribute_spec
= s; _ }
2794 | AwaitableCreationExpression
{ awaitable_attribute_spec
= s; _ }
2795 -> no_memoize_attribute_on_lambda s errors
2796 | CollectionLiteralExpression
2797 { collection_literal_name
= n
2798 ; collection_literal_initializers
= initializers
2800 let is_standard_collection lc_name
=
2801 lc_name
= "pair" || lc_name
= "vector" || lc_name
= "map" ||
2802 lc_name
= "set" || lc_name
= "immvector" || lc_name
= "immmap" ||
2803 lc_name
= "immset" in
2804 let is_qualified_std_collection l
r =
2805 token_kind l
= Some
TokenKind.Name
&&
2806 token_kind r = Some
TokenKind.Name
&&
2807 String.lowercase
(text l
) = "hh" &&
2808 is_standard_collection (String.lowercase
(text r)) in
2811 (* non-qualified name *)
2812 | SimpleTypeSpecifier
{ simple_type_specifier
= ({
2815 | GenericTypeSpecifier
{ generic_class_type
= ({
2818 when Token.kind t
= TokenKind.Name
->
2819 begin match String.lowercase
(text n) with
2820 | "dict" | "vec" | "keyset" -> `InvalidBraceKind
2821 | n -> if is_standard_collection n then `ValidClass
n else `InvalidClass
2823 (* qualified name *)
2824 | SimpleTypeSpecifier
{ simple_type_specifier
= {
2825 syntax
= QualifiedName
{ qualified_name_parts
= parts
; _ }; _
2827 | GenericTypeSpecifier
{ generic_class_type
= {
2828 syntax
= QualifiedName
{ qualified_name_parts
= parts
; _ }; _
2830 begin match syntax_to_list false parts
with
2831 (* HH\Vector in global namespace *)
2833 when namespace_name
= global_namespace_name &&
2834 is_qualified_std_collection l
r ->
2835 `ValidClass
(String.lowercase
(text r))
2837 | [{ syntax
= Missing
; _}; l
; r]
2838 when is_qualified_std_collection l
r ->
2839 `ValidClass
(String.lowercase
(text r))
2840 | _ -> `InvalidClass
2842 | _ -> `InvalidClass
in
2843 let num_initializers =
2844 List.length
(syntax_to_list_no_separators initializers
) in
2845 let errors = begin match status with
2846 | `ValidClass
"pair" when num_initializers <> 2 ->
2848 if num_initializers = 0
2849 then SyntaxError.pair_initializer_needed
2850 else SyntaxError.pair_initializer_arity
2853 make_error_from_node node msg ~
error_type:SyntaxError.RuntimeError
in
2855 | `ValidClass
_ -> errors
2856 | `InvalidBraceKind
->
2858 make_error_from_node node SyntaxError.invalid_brace_kind_in_collection_initializer
in
2862 make_error_from_node node SyntaxError.invalid_class_in_collection_initializer
in
2865 check_collection_members initializers
errors
2866 | DecoratedExpression
{ decorated_expression_decorator
= op
; _ }
2867 | PrefixUnaryExpression
{ prefix_unary_operator
= op
; _ }
2868 when token_kind op
= Some
TokenKind.Await
->
2869 let aaae_errors = await_as_an_expression_errors node parents in
2870 List.append
aaae_errors errors
2871 | _ -> errors (* Other kinds of expressions currently produce no expr errors. *)
2873 let check_repeated_properties_tconst_const full_name (errors, p_names
, c_names
) prop
=
2874 let check errors sname
names =
2875 let name = text sname
in
2876 (* If the name is empty, then there was an earlier
2877 parsing error that should supercede this one. *)
2881 if SSet.mem
name names
2882 then make_error_from_node prop
2883 (SyntaxError.redeclaration_error
2884 ((Utils.strip_ns
full_name) ^
"::" ^
name)) :: errors, names
2885 else errors, SSet.add
name names
2887 match syntax prop
with
2888 | PropertyDeclaration
{ property_declarators
; _} ->
2889 let declarators = syntax_to_list_no_separators property_declarators
in
2890 List.fold
declarators ~init
:(errors, p_names
, c_names
)
2891 ~f
:begin fun (errors, p_names
, c_names
) prop
->
2892 match syntax prop
with
2893 | PropertyDeclarator
{property_name
= name; _} ->
2894 let errors, p_names
= check errors name p_names
in
2895 errors, p_names
, c_names
2896 | _ -> errors, p_names
, c_names
2898 | ConstDeclaration
{ const_declarators
; _ } ->
2899 let declarators = syntax_to_list_no_separators const_declarators
in
2900 List.fold
declarators ~init
:(errors, p_names
, c_names
)
2901 ~f
:begin fun (errors, p_names
, c_names
) prop
->
2902 match syntax prop
with
2903 | ConstantDeclarator
{constant_declarator_name
= name; _} ->
2904 let errors, c_names
= check errors name c_names
in
2905 errors, p_names
, c_names
2906 | _ -> errors, p_names
, c_names
2908 | TypeConstDeclaration
{ type_const_name
; _ } ->
2909 let errors, c_names
= check errors type_const_name c_names
in
2910 errors, p_names
, c_names
2911 | _ -> errors, p_names
, c_names
2913 let require_errors _env
node trait_use_clauses
errors =
2914 match syntax
node with
2915 | RequireClause p
->
2916 let name = text p
.require_name
in
2917 let req_kind = token_kind p
.require_kind
in
2918 let trait_use_clauses, errors =
2919 match strmap_get name trait_use_clauses, req_kind with
2920 | None
, Some tk
-> strmap_add name tk
trait_use_clauses, errors
2921 | Some tk1
, Some tk2
when tk1
= tk2
-> (* duplicate, it is okay *)
2922 trait_use_clauses, errors
2923 | _ -> (* Conflicting entry *)
2925 make_error_from_node node
2926 (SyntaxError.conflicting_trait_require_clauses ~
name) :: errors
2929 match (active_classish_kind _env
.context, req_kind) with
2930 | (Some
TokenKind.Interface
, Some
TokenKind.Implements
)
2931 | (Some
TokenKind.Class
, Some
TokenKind.Implements
) ->
2932 make_error_from_node node SyntaxError.error2030
:: errors
2935 trait_use_clauses, errors
2936 | _ -> trait_use_clauses, errors
2938 let check_type_name syntax_tree
name namespace_name name_text
location names errors =
2939 begin match strmap_get name_text
names.t_classes
with
2940 | Some
{ f_location
= location; f_kind
; f_name
; _ }
2941 when combine_names namespace_name name_text
<> f_name
&& f_kind
<> Name_def
->
2942 let text = SyntaxTree.text syntax_tree
in
2944 Full_fidelity_source_text.offset_to_position
2945 text location.start_offset in
2946 let long_name_text = combine_names namespace_name name_text
in
2948 make_name_already_used_error name long_name_text name_text
location
2950 | Name_implicit_use
-> SyntaxError.declared_name_is_already_in_use_implicit_hh ~
line_num
2951 | Name_use
-> SyntaxError.declared_name_is_already_in_use ~
line_num
2952 | Name_def
-> SyntaxError.type_name_is_already_in_use
) in
2953 names, error :: errors
2956 make_first_use_or_def ~
kind:Name_def
location namespace_name name_text
in
2959 t_classes
= strmap_add name_text
def names.t_classes
} in
2963 let get_type_params_and_emit_shadowing_errors l
errors =
2964 syntax_to_list_no_separators l
2965 |> List.fold_right ~init
:(SSet.empty
, errors)
2966 ~f
:(fun p
(s, e) -> match syntax p
with
2967 | TypeParameter
{ type_reified
; type_name
; _}
2968 when not
@@ is_missing type_reified
->
2969 let name = text type_name
in
2970 if SSet.mem
name s then
2971 (s, make_error_from_node p
SyntaxError.shadowing_reified
:: e)
2972 else (SSet.add
name s, e)
2975 let reified_parameter_errors node errors =
2976 match syntax
node with
2977 | FunctionDeclarationHeader
{
2978 function_type_parameter_list
= {
2979 syntax
= TypeParameters
{
2980 type_parameters_parameters
; _}; _}; _} ->
2981 snd
@@ get_type_params_and_emit_shadowing_errors
2982 type_parameters_parameters
errors
2985 let class_reified_param_errors env
node errors =
2986 match syntax
node with
2987 | ClassishDeclaration cd
->
2988 let reified_params, errors = match syntax cd
.classish_type_parameters
with
2989 | TypeParameters
{ type_parameters_parameters
; _ } ->
2990 get_type_params_and_emit_shadowing_errors
2991 type_parameters_parameters
errors
2992 | _ -> SSet.empty
, errors in
2993 let add_error e acc = match syntax
e with
2994 | TypeParameter
{ type_reified
; type_name
; _}
2995 when not
@@ is_missing type_reified
&&
2996 SSet.mem
(text type_name
) reified_params ->
2997 make_error_from_node e SyntaxError.shadowing_reified
:: acc
2999 let check_method e acc = match syntax
e with
3000 | MethodishDeclaration
{
3001 methodish_function_decl_header
= {
3002 syntax
= FunctionDeclarationHeader
{
3003 function_type_parameter_list
= {
3004 syntax
= TypeParameters
{
3005 type_parameters_parameters
; _}; _}; _}; _}; _} ->
3006 syntax_to_list_no_separators type_parameters_parameters
3007 |> List.fold_right ~init
:acc ~f
:add_error
3009 let errors = match syntax cd
.classish_body
with
3010 | ClassishBody
{ classish_body_elements
; _} ->
3011 syntax_to_list_no_separators classish_body_elements
3012 |> List.fold_right ~init
:errors ~f
:check_method
3014 let errors = if not
@@ SSet.is_empty
reified_params then begin
3015 if is_token_kind cd
.classish_keyword
TokenKind.Interface
then
3016 make_error_from_node node
3017 (SyntaxError.reified_in_invalid_classish
"an interface") :: errors
3018 else if is_token_kind cd
.classish_keyword
TokenKind.Trait
then
3019 make_error_from_node node
3020 (SyntaxError.reified_in_invalid_classish
"a trait") :: errors
3024 | PropertyDeclaration
_ ->
3025 if methodish_contains_static node && is_in_reified_class env
.context then
3026 make_error_from_node node SyntaxError.static_property_in_reified_class
3027 :: errors else errors
3030 let attr_spec_contains_sealed node =
3031 attribute_specification_contains node SN.UserAttributes.uaSealed
3033 (* If there's more than one XHP category, report an error on the last one. *)
3034 let duplicate_xhp_category_errors (elts
: Syntax.t list
) errors =
3035 let category_nodes = List.filter elts ~f
:(fun elt
->
3036 match syntax elt
with
3037 | XHPCategoryDeclaration
_ -> true
3040 if List.length
category_nodes > 1 then
3041 let node = List.last_exn
category_nodes in
3042 let err = make_error_from_node node SyntaxError.xhp_class_multiple_category_decls
in
3047 (* If there's more than one XHP children declaration, report an error
3049 let duplicate_xhp_children_errors (elts
: Syntax.t list
) errors =
3050 let child_nodes = List.filter elts ~f
:(fun elt
->
3051 match syntax elt
with
3052 | XHPChildrenDeclaration
_ -> true
3055 if List.length
child_nodes > 1 then
3056 let node = List.last_exn
child_nodes in
3057 let err = make_error_from_node node SyntaxError.xhp_class_multiple_children_decls
in
3062 let classish_errors env
node namespace_name
names errors =
3063 match syntax
node with
3064 | ClassishDeclaration cd
->
3065 (* Given a ClassishDeclaration node, test whether or not it's a trait
3066 * invoking the 'extends' keyword. *)
3067 let classish_invalid_extends_keyword _ =
3068 (* Invalid if uses 'extends' and is a trait. *)
3069 token_kind cd
.classish_extends_keyword
= Some
TokenKind.Extends
&&
3070 token_kind cd
.classish_keyword
= Some
TokenKind.Trait
in
3072 (* Given a sealed ClassishDeclaration node, test whether all the params
3073 * are classnames. *)
3074 let classish_sealed_arg_not_classname _env
_ =
3075 match cd
.classish_attribute
.syntax
with
3076 | AttributeSpecification
{ attribute_specification_attributes
= attrs; _ } ->
3077 let attrs = syntax_to_list_no_separators attrs in
3078 List.exists
attrs (fun e ->
3080 | ConstructorCall
{constructor_call_argument_list
; constructor_call_type
; _ } ->
3081 text constructor_call_type
= SN.UserAttributes.uaSealed
&&
3082 List.exists
(syntax_to_list_no_separators constructor_call_argument_list
) (fun e ->
3084 | ScopeResolutionExpression
{scope_resolution_name
; _ } ->
3085 text scope_resolution_name
<> "class"
3090 let classish_is_sealed =
3091 attr_spec_contains_sealed cd
.classish_attribute
in
3093 (* Given a ClassishDeclaration node, test whether or not length of
3094 * extends_list is appropriate for the classish_keyword. *)
3095 let classish_invalid_extends_list env
_ =
3096 (* Invalid if is a class and has list of length greater than one. *)
3097 (is_typechecker env
) &&
3098 token_kind cd
.classish_keyword
= Some
TokenKind.Class
&&
3099 token_kind cd
.classish_extends_keyword
= Some
TokenKind.Extends
&&
3100 match syntax_to_list_no_separators cd
.classish_extends_list
with
3102 | _ -> true (* General bc empty list case is already caught by error1007 *) in
3103 let abstract_keyword =
3104 Option.value (extract_keyword is_abstract node) ~default
:node in
3105 let errors = produce_error errors
3106 (is_classish_kind_declared_abstract env
)
3107 node SyntaxError.error2042
abstract_keyword in
3108 (* Given a ClassishDeclaration node, test whether it is sealed and final. *)
3109 let classish_sealed_final _env
_ =
3110 list_contains_predicate is_final cd
.classish_modifiers
&&
3111 classish_is_sealed in
3112 let errors = produce_error errors (classish_invalid_extends_list env
) ()
3113 SyntaxError.error2037 cd
.classish_extends_list
in
3116 match attribute_first_reactivity_annotation cd
.classish_attribute
with
3118 make_error_from_node n SyntaxError.misplaced_reactivity_annotation
:: errors
3122 multiple_modifiers_errors cd
.classish_modifiers
3123 SyntaxError.error2031
errors in
3125 produce_error errors
3126 (classish_sealed_arg_not_classname env
) ()
3127 SyntaxError.sealed_val_not_classname cd
.classish_attribute
in
3129 produce_error errors
3130 classish_invalid_extends_keyword ()
3131 SyntaxError.error2036 cd
.classish_extends_keyword
in
3133 produce_error errors
3134 (classish_sealed_final env
) ()
3135 SyntaxError.sealed_final cd
.classish_attribute
in
3137 let classish_name = text cd
.classish_name in
3138 produce_error errors
3139 cant_be_classish_name classish_name
3140 (SyntaxError.reserved_keyword_as_class_name
classish_name)
3143 if is_token_kind cd
.classish_keyword
TokenKind.Interface
&&
3144 not
(is_missing cd
.classish_implements_keyword
)
3145 then make_error_from_node node
3146 SyntaxError.interface_implements
:: errors
3148 let name = text cd
.classish_name in
3150 match syntax cd
.classish_body
with
3151 | ClassishBody
{classish_body_elements
= methods; _} ->
3152 let methods = syntax_to_list_no_separators methods in
3153 let declared_name_str =
3154 Option.value ~default
:"" (Syntax.extract_text cd
.classish_name) in
3155 let full_name = combine_names namespace_name
declared_name_str in
3158 ~f
:(check_repeated_properties_tconst_const full_name)
3159 ~init
:(errors, SSet.empty
, SSet.empty
) in
3160 let has_abstract_fn =
3161 List.exists
methods ~f
:methodish_contains_abstract in
3162 let has_private_method =
3164 ~f
:(methodish_modifier_contains_helper is_private
) in
3166 if has_abstract_fn &&
3167 is_token_kind cd
.classish_keyword
TokenKind.Class
&&
3168 not
(list_contains_predicate is_abstract cd
.classish_modifiers
)
3169 then make_error_from_node node
3170 (SyntaxError.class_with_abstract_method
name) :: errors
3173 if has_private_method &&
3174 is_token_kind cd
.classish_keyword
TokenKind.Interface
3175 then make_error_from_node node
3176 SyntaxError.interface_has_private_method
:: errors
3178 let errors = duplicate_xhp_category_errors methods errors in
3179 let errors = duplicate_xhp_children_errors methods errors in
3183 match token_kind cd
.classish_keyword
with
3184 | Some
TokenKind.Class
| Some
TokenKind.Trait
3185 when not
(is_missing cd
.classish_name)->
3186 let location = make_location_of_node cd
.classish_name in
3187 check_type_name env
.syntax_tree cd
.classish_name namespace_name
name location names errors
3191 | _ -> names, errors
3193 let class_element_errors env
node errors =
3194 match syntax
node with
3195 | ConstDeclaration
_ when is_inside_trait env
.context ->
3196 make_error_from_node node SyntaxError.const_in_trait
:: errors
3197 | ConstDeclaration
{ const_visibility
; _ }
3198 when not
(is_missing const_visibility
) && is_typechecker env
->
3199 make_error_from_node node SyntaxError.const_visibility
:: errors
3203 let alias_errors env
node namespace_name
names errors =
3204 match syntax
node with
3205 | AliasDeclaration ad
->
3207 if token_kind ad
.alias_keyword
= Some
TokenKind.Type
&&
3208 not
(is_missing ad
.alias_constraint
)
3209 then make_error_from_node ad
.alias_keyword
SyntaxError.error2034
:: errors
3211 if is_missing ad
.alias_name
then names,errors
3213 let name = text ad
.alias_name
in
3214 let location = make_location_of_node ad
.alias_name
in
3215 let errors = match ad
.alias_type
with
3217 syntax
= TypeConstant
_;
3219 } when is_typechecker env
->
3220 make_error_from_node ad
.alias_type
3221 SyntaxError.type_alias_to_type_constant
:: errors
3223 check_type_name env
.syntax_tree ad
.alias_name namespace_name
name location names errors
3224 | _ -> names, errors
3226 let is_invalid_group_use_clause kind clause
=
3227 match syntax clause
with
3228 | NamespaceUseClause
{ namespace_use_clause_kind
= clause_kind
; _ } ->
3231 begin match syntax clause_kind
with
3233 | Token token
when let k = Token.kind token
in
3234 TokenKind.(k = Function
|| k = Const
) -> false
3237 else not
(is_missing clause_kind
)
3240 let is_invalid_group_use_prefix prefix
=
3241 not
(is_namespace_prefix prefix
)
3243 let group_use_errors _env
node errors =
3244 match syntax
node with
3245 | NamespaceGroupUseDeclaration
3246 { namespace_group_use_prefix
= prefix
3247 ; namespace_group_use_clauses
= clauses
3248 ; namespace_group_use_kind
= kind
3251 let invalid_clauses = List.filter ~f
:(is_invalid_group_use_clause kind)
3252 (syntax_to_list_no_separators clauses
) in
3253 let mapper errors clause
=
3254 make_error_from_node clause
SyntaxError.error2049
:: errors in
3255 List.fold_left ~f
:mapper ~init
:errors invalid_clauses in
3256 produce_error errors is_invalid_group_use_prefix prefix
3257 SyntaxError.error2048 prefix
3260 let use_class_or_namespace_clause_errors
3261 env is_global_namespace namespace_prefix
3262 kind (names, errors) cl
=
3264 match syntax cl
with
3265 | NamespaceUseClause
{
3266 namespace_use_name
= name;
3267 namespace_use_alias
= alias
;
3268 namespace_use_clause_kind
; _
3269 } when not
(is_missing name) ->
3270 let kind = if is_missing kind then namespace_use_clause_kind
else kind in
3271 let name_text = text name in
3272 let qualified_name =
3273 match namespace_prefix
with
3274 | None
-> combine_names global_namespace_name name_text
3275 | Some p
-> combine_names p
name_text in
3276 let short_name = get_short_name_from_qualified_name name_text (text alias
) in
3278 let do_check ?
(case_sensitive
= false) ~error_on_global_redefinition
names errors
3279 get_map update_map report_error
=
3280 (* We store the original names in the SMap of names for error messaging purposes
3281 but we check for case sensitivity specifically. *)
3282 let find_name name =
3284 then short_name = name
3285 else (String.lowercase
short_name) = String.lowercase
name in
3286 let map = get_map
names in
3287 match strmap_find_first_opt find_name map with
3288 | Some
(_, { f_location
= location; f_kind
; f_global
; _ }) ->
3289 if (f_kind
<> Name_def
3290 || (error_on_global_redefinition
&& (is_global_namespace
|| f_global
)))
3293 make_name_already_used_error name name_text
3294 short_name location report_error
in
3295 names, error :: errors
3300 make_first_use_or_def
3302 (make_location_of_node name)
3303 global_namespace_name qualified_name in
3304 update_map
names (strmap_add short_name new_use map), errors
3307 begin match syntax
kind with
3309 let open TokenKind
in
3310 (match Token.kind token
with
3312 do_check ~error_on_global_redefinition
:false names errors
3313 (fun n -> n.t_namespaces
)
3314 (fun n v
-> { n with t_namespaces
= v
})
3315 SyntaxError.namespace_name_is_already_in_use
3318 do_check ~error_on_global_redefinition
:false names errors
3319 (fun n -> n.t_classes
)
3320 (fun n v
-> { n with t_classes
= v
})
3321 SyntaxError.type_name_is_already_in_use
3324 do_check ~error_on_global_redefinition
:true names errors
3325 (fun n -> n.t_functions
)
3326 (fun n v
-> { n with t_functions
= v
})
3327 SyntaxError.function_name_is_already_in_use
3330 do_check ~case_sensitive
:true ~error_on_global_redefinition
:true names errors
3331 (fun n -> n.t_constants
)
3332 (fun n v
-> { n with t_constants
= v
})
3333 SyntaxError.const_name_is_already_in_use
3339 if name_text = "strict"
3340 then make_error_from_node name SyntaxError.strict_namespace_hh
:: errors
3343 let location = make_location_of_node name in
3344 match strmap_get short_name names.t_classes
with
3345 | Some
{ f_location
= loc; f_name
; f_kind
; _ } ->
3346 if qualified_name = f_name
&& f_kind
= Name_def
then names, errors
3349 if f_kind
<> Name_def
then
3350 let text = SyntaxTree.text env
.syntax_tree
in
3352 Full_fidelity_source_text.offset_to_position
3353 text loc.start_offset in
3354 if f_kind
= Name_implicit_use
3355 then SyntaxError.name_is_already_in_use_implicit_hh ~
line_num
3356 else SyntaxError.name_is_already_in_use_hh ~
line_num
3357 else SyntaxError.name_is_already_in_use_php
3359 let error = make_name_already_used_error
3360 name name_text short_name loc err_msg in
3361 names, error :: errors
3364 make_first_use_or_def ~
kind:Name_use
location global_namespace_name qualified_name in
3365 let t_classes = strmap_add short_name new_use names.t_classes in
3367 if strmap_mem short_name names.t_namespaces
3368 then names.t_namespaces
3369 else strmap_add short_name new_use names.t_namespaces in
3370 { names with t_classes; t_namespaces }, errors in
3379 let is_global_in_const_decl init
=
3380 match syntax init
with
3381 | SimpleInitializer
{ simple_initializer_value
; _ } ->
3382 begin match syntax simple_initializer_value
with
3383 | VariableExpression
{ variable_expression
} ->
3384 SN.Superglobals.is_superglobal
@@ text variable_expression
3389 let namespace_use_declaration_errors
3390 env
node is_global_namespace
names errors =
3391 match syntax
node with
3392 | NamespaceUseDeclaration
{
3393 namespace_use_kind
= kind;
3394 namespace_use_clauses
= clauses
; _ } ->
3396 use_class_or_namespace_clause_errors
3397 env is_global_namespace None
kind in
3398 List.fold_left ~
f ~init
:(names, errors) (syntax_to_list_no_separators clauses
)
3399 | NamespaceGroupUseDeclaration
{
3400 namespace_group_use_kind
= kind;
3401 namespace_group_use_clauses
= clauses
;
3402 namespace_group_use_prefix
= prefix
; _ } ->
3404 use_class_or_namespace_clause_errors
3405 env is_global_namespace
(Some
(text prefix
)) kind in
3406 List.fold_left ~
f ~init
:(names, errors) (syntax_to_list_no_separators clauses
)
3407 | _ -> names, errors
3410 let rec check_constant_expression errors node =
3411 let is_namey token
=
3412 match Token.kind token
with
3413 TokenKind.Name
-> true
3416 let is_good_scope_resolution_name node =
3417 match syntax
node with
3418 | QualifiedName
_ -> true
3420 let open TokenKind
in
3421 (match Token.kind token
with
3422 | Name
| Trait
| Extends
| Implements
| Static
3423 | Abstract
| Final
| Private
| Protected
| Public
| Global
3424 | Goto
| Instanceof
| Insteadof
| Interface
| Namespace
| New
| Try
| Use
3425 | Var
| List
| Clone
| Include
| Include_once
| Throw
| Array
| Tuple
3426 | Print
| Echo
| Require
| Require_once
| Return
| Else
| Elseif
| Default
3427 | Break
| Continue
| Switch
| Yield
| Function
| If
| Finally
| For
3428 | Foreach
| Case
| Do
| While
| As
| Catch
| Empty
| Using
| Class
3429 | NullLiteral
| Super
| Where
3435 match syntax
node with
3438 | LiteralExpression
_
3440 | Token token
when is_namey token
-> errors
3441 | PrefixUnaryExpression
3442 { prefix_unary_operand
3443 ; prefix_unary_operator
= { syntax
= Token token
; _ }
3444 } when ( let open TokenKind
in
3445 match Token.kind token
with
3446 | Exclamation
| Plus
| Minus
| Tilde
-> true
3449 check_constant_expression errors prefix_unary_operand
3451 { binary_left_operand
3452 ; binary_right_operand
3453 ; binary_operator
= { syntax
= Token token
; _ }
3454 ; _ } when ( let open TokenKind
in
3455 match Token.kind token
with
3456 | BarBar
| AmpersandAmpersand
| Carat
3457 | Bar
| Ampersand
| Dot
| Plus
| Minus
| Star
| Slash
| Percent
3458 | LessThanLessThan
| GreaterThanGreaterThan
| StarStar
3459 | EqualEqual
| EqualEqualEqual
| ExclamationEqual
3460 | ExclamationEqualEqual
| GreaterThan
| GreaterThanEqual
3461 | LessThan
| LessThanEqual
| LessThanEqualGreaterThan
3466 let errors = check_constant_expression errors binary_left_operand
in
3467 let errors = check_constant_expression errors binary_right_operand
in
3469 | ConditionalExpression
{
3471 conditional_consequence
;
3472 conditional_alternative
; _
3474 let errors = check_constant_expression errors conditional_test
in
3475 let errors = check_constant_expression errors conditional_consequence
in
3476 let errors = check_constant_expression errors conditional_alternative
in
3478 | SimpleInitializer
{ simple_initializer_value
= e; _ }
3479 | ParenthesizedExpression
{ parenthesized_expression_expression
= e; _} ->
3480 check_constant_expression errors e
3481 | CollectionLiteralExpression
3482 { collection_literal_name
=
3484 ( SimpleTypeSpecifier
3485 { simple_type_specifier
= { syntax
= Token token
; _ } }
3486 | GenericTypeSpecifier
3487 { generic_class_type
= { syntax
= Token token
; _ }; _ }
3491 ; collection_literal_initializers
= lst
3493 } when is_namey token
->
3494 syntax_to_list_no_separators lst
3495 |> List.fold_left ~init
:errors ~
f:check_constant_expression
3496 | TupleExpression
{ tuple_expression_items
= lst
; _ }
3497 | KeysetIntrinsicExpression
{ keyset_intrinsic_members
= lst
; _}
3498 | VarrayIntrinsicExpression
{ varray_intrinsic_members
= lst
; _ }
3499 | DarrayIntrinsicExpression
{ darray_intrinsic_members
= lst
; _ }
3500 | VectorIntrinsicExpression
{ vector_intrinsic_members
= lst
; _ }
3501 | DictionaryIntrinsicExpression
{ dictionary_intrinsic_members
= lst
; _}
3502 | ArrayIntrinsicExpression
{ array_intrinsic_members
= lst
; _}
3503 | ArrayCreationExpression
{ array_creation_members
= lst
; _ }
3504 | ShapeExpression
{ shape_expression_fields
= lst
; _ } ->
3505 syntax_to_list_no_separators lst
3506 |> List.fold_left ~init
:errors ~
f:check_constant_expression
3507 | ElementInitializer
{ element_key
= n; element_value
= v
; _ }
3508 | FieldInitializer
{ field_initializer_name
= n; field_initializer_value
= v
; _ } ->
3509 let errors = check_constant_expression errors n in
3510 let errors = check_constant_expression errors v
in
3512 | ScopeResolutionExpression
3513 { scope_resolution_qualifier
3514 ; scope_resolution_name
3516 ; _ } when is_good_scope_resolution_qualifier scope_resolution_qualifier
&&
3517 is_good_scope_resolution_name scope_resolution_name
3520 (make_error_from_node node SyntaxError.invalid_constant_initializer
) :: errors
3522 let check_static_in_initializer initializer_
=
3523 match syntax initializer_
with
3524 | SimpleInitializer
{
3525 simple_initializer_value
= {
3526 syntax
= ScopeResolutionExpression
{
3527 scope_resolution_qualifier
= { syntax
= Token t
; _ };
3528 scope_resolution_name
= name;
3531 begin match Token.kind t
with
3532 | TokenKind.Static
-> true
3533 | TokenKind.Parent
when (String.lowercase
@@ text name = "class") -> true
3538 let const_decl_errors env
node namespace_name
names errors =
3539 match syntax
node with
3540 | ConstantDeclarator cd
->
3542 produce_error_context errors constant_abstract_with_initializer
3543 cd
.constant_declarator_initializer env
.context
3544 SyntaxError.error2051 cd
.constant_declarator_initializer
in
3546 produce_error_context errors constant_concrete_without_initializer
3547 cd
.constant_declarator_initializer env
.context SyntaxError.error2050
3548 cd
.constant_declarator_initializer
in
3550 produce_error errors is_global_in_const_decl cd
.constant_declarator_initializer
3551 SyntaxError.global_in_const_decl cd
.constant_declarator_initializer
in
3553 check_constant_expression errors cd
.constant_declarator_initializer
in
3555 produce_error errors check_static_in_initializer cd
.constant_declarator_initializer
3556 SyntaxError.parent_static_const_decl cd
.constant_declarator_initializer
in
3558 match syntax cd
.constant_declarator_initializer
with
3559 | SimpleInitializer
{ simple_initializer_value
= { syntax
=
3560 LiteralExpression
{ literal_expression
= { syntax
=
3561 SyntaxList
_; _}}; _}; _} ->
3562 make_error_from_node
3563 node SyntaxError.invalid_constant_initializer
:: errors
3565 if is_missing cd
.constant_declarator_name
3568 let constant_name = text cd
.constant_declarator_name
in
3569 let location = make_location_of_node cd
.constant_declarator_name
in
3571 make_first_use_or_def ~
kind:Name_def
location namespace_name
constant_name in
3573 match strmap_get constant_name names.t_constants
with
3576 (* Only error if this is inside a class *)
3577 begin match first_parent_class_name env
.context with
3579 | Some
class_name ->
3580 let full_name = class_name ^
"::" ^
constant_name in
3581 make_error_from_node
3582 node (SyntaxError.redeclaration_error
full_name) :: errors
3586 names with t_constants
=
3587 strmap_add constant_name def names.t_constants
} in
3589 | _ -> names, errors
3592 let class_property_visibility_errors env
node errors =
3593 match syntax
node with
3594 | PropertyDeclaration
{ property_modifiers
; _ } ->
3595 let first_parent_name = Option.value (first_parent_class_name env
.context)
3598 multiple_modifiers_errors
3600 (SyntaxError.property_has_multiple_modifiers
first_parent_name) errors
3603 multiple_visibility_errors
3605 (SyntaxError.property_has_multiple_visibilities
first_parent_name) errors
3608 produce_error errors
3609 is_empty_list_or_missing property_modifiers
3610 SyntaxError.property_requires_visibility
node
3616 let mixed_namespace_errors _env
node parents namespace_type
errors =
3617 match syntax
node with
3618 | NamespaceBody
{ namespace_left_brace
; namespace_right_brace
; _ } ->
3619 let s = start_offset namespace_left_brace
in
3620 let e = end_offset namespace_right_brace
in
3621 begin match namespace_type
with
3622 | Unbracketed
{ start_offset; end_offset } ->
3624 (SyntaxError.make
start_offset end_offset SyntaxError.error2057
)
3626 SyntaxError.make ~
child s e SyntaxError.error2052
:: errors
3629 | NamespaceEmptyBody
{ namespace_semicolon
; _ } ->
3630 let s = start_offset namespace_semicolon
in
3631 let e = end_offset namespace_semicolon
in
3632 begin match namespace_type
with
3633 | Bracketed
{ start_offset; end_offset } ->
3635 (SyntaxError.make
start_offset end_offset SyntaxError.error2056
)
3637 SyntaxError.make ~
child s e SyntaxError.error2052
:: errors
3640 | NamespaceDeclaration
{ namespace_body
; _ } ->
3641 let is_first_decl, has_code_outside_namespace
=
3643 | [{ syntax
= SyntaxList
_; _} as decls
; { syntax
= Script
_; _}] ->
3644 let decls = syntax_to_list_no_separators decls in
3645 let rec is_first l
=
3647 | { syntax
= MarkupSection
{markup_text
; _}; _} :: rest
3648 when width markup_text
= 0 || is_hashbang markup_text
->
3650 | { syntax
= ( NamespaceUseDeclaration
_
3651 | FileAttributeSpecification
_
3654 | { syntax
= NamespaceDeclaration
_; _} :: _ -> true
3657 let has_code_outside_namespace =
3658 not
(is_namespace_empty_body namespace_body
) &&
3660 ~
f:(function | { syntax
= MarkupSection
{ markup_text
; _}; _}
3661 when width markup_text
= 0
3662 || is_hashbang markup_text
-> false
3663 | { syntax
= NamespaceDeclaration
_; _}
3664 | { syntax
= ExpressionStatement
{
3665 expression_statement_expression
=
3666 { syntax
= HaltCompilerExpression
_; _}; _}; _}
3667 | { syntax
= FileAttributeSpecification
_; _}
3668 | { syntax
= EndOfFile
_; _}
3669 | { syntax
= NamespaceUseDeclaration
_; _} -> false
3672 is_first decls, has_code_outside_namespace
3675 let errors = if not
is_first_decl then
3676 make_error_from_node node
3677 SyntaxError.namespace_decl_first_statement
:: errors else errors
3679 let errors = if has_code_outside_namespace then
3680 make_error_from_node node
3681 SyntaxError.code_outside_namespace
:: errors else errors
3686 let enumerator_errors node errors =
3687 match syntax
node with
3688 | Enumerator
{ enumerator_name
= name; enumerator_value
= value; _} ->
3689 let errors = if String.lowercase
@@ text name = "class" then
3690 make_error_from_node node SyntaxError.enum_elem_name_is_class
:: errors
3692 let errors = check_constant_expression errors value in
3696 let enum_decl_errors node errors =
3697 match syntax
node with
3699 { enum_attribute_spec
= attrs
3703 ; enum_type = constr
3704 ; enum_enumerators = enums
3707 if attr_spec_contains_sealed attrs then
3708 make_error_from_node node SyntaxError.sealed_enum
:: errors
3712 let assignment_errors _env
node errors =
3713 let append_errors node errors error =
3714 make_error_from_node node error :: errors
3716 let rec check_lvalue ?
(allow_reassign_this
=false) loperand
errors : SyntaxError.t list
=
3717 let err = append_errors loperand
errors in
3718 match syntax loperand
with
3719 | ListExpression
{ list_members
= members
; _ } ->
3720 let members = syntax_to_list_no_separators members in
3721 List.fold_left ~
f:(fun e n -> check_lvalue n e) ~init
:errors members
3722 | SafeMemberSelectionExpression
_ ->
3723 err (SyntaxError.not_allowed_in_write
"?-> operator")
3724 | MemberSelectionExpression
{ member_name
; _ }
3725 when token_kind member_name
= Some
TokenKind.XHPClassName
->
3726 err (SyntaxError.not_allowed_in_write
"->: operator")
3727 | VariableExpression
{ variable_expression
}
3728 when not allow_reassign_this
3729 && String.lowercase
(text variable_expression
) = SN.SpecialIdents.this
->
3730 err SyntaxError.reassign_this
3731 | DecoratedExpression
{ decorated_expression_decorator
= op
; _ }
3732 when token_kind op
= Some
TokenKind.Clone
->
3733 err (SyntaxError.not_allowed_in_write
"Clone")
3734 | DecoratedExpression
{ decorated_expression_decorator
= op
; _ }
3735 when token_kind op
= Some
TokenKind.Await
->
3736 err (SyntaxError.not_allowed_in_write
"Await")
3737 | DecoratedExpression
{ decorated_expression_decorator
= op
; _ }
3738 when token_kind op
= Some
TokenKind.Suspend
->
3739 err (SyntaxError.not_allowed_in_write
"Suspend")
3740 | DecoratedExpression
{ decorated_expression_decorator
= op
; _ }
3741 when token_kind op
= Some
TokenKind.QuestionQuestion
->
3742 err (SyntaxError.not_allowed_in_write
"?? operator")
3743 | DecoratedExpression
{ decorated_expression_decorator
= op
; _ }
3744 when token_kind op
= Some
TokenKind.BarGreaterThan
->
3745 err (SyntaxError.not_allowed_in_write
"|> operator")
3746 | DecoratedExpression
{ decorated_expression_decorator
= op
; _ }
3747 when token_kind op
= Some
TokenKind.Inout
->
3748 err (SyntaxError.not_allowed_in_write
"Inout")
3749 | ParenthesizedExpression
{ parenthesized_expression_expression
= e; _} ->
3750 check_lvalue ~allow_reassign_this
e errors
3751 | SubscriptExpression
{ subscript_receiver
= e; _ } ->
3752 check_lvalue ~allow_reassign_this
:true e errors
3753 | LambdaExpression
_ | AnonymousFunction
_
3754 | AwaitableCreationExpression
_
3755 | ArrayIntrinsicExpression
_ | ArrayCreationExpression
_
3756 | DarrayIntrinsicExpression
_
3757 | VarrayIntrinsicExpression
_
3759 | CollectionLiteralExpression
_
3760 | GenericTypeSpecifier
_
3761 | YieldExpression
_ | YieldFromExpression
_
3763 | BinaryExpression
_
3764 | ConditionalExpression
_
3765 | InstanceofExpression
_
3767 | AsExpression
_ | NullableAsExpression
_
3768 | ConstructorCall
_ | AnonymousClass
_
3770 | InclusionExpression
_
3772 | LiteralExpression
_ ->
3773 let kind = kind loperand
in
3774 let kind_str = Full_fidelity_syntax_kind.to_string
kind in
3775 err (SyntaxError.not_allowed_in_write
kind_str)
3776 | PrefixUnaryExpression
{ prefix_unary_operator
= op
; _ }
3777 | PostfixUnaryExpression
{ postfix_unary_operator
= op
; _ } ->
3778 begin match token_kind op
with
3779 | Some
TokenKind.At
| Some
TokenKind.Dollar
-> errors
3780 | Some
TokenKind.Ampersand
->
3781 err (SyntaxError.not_allowed_in_write
"&")
3782 | _ -> err (SyntaxError.not_allowed_in_write
"Unary expression")
3784 (* FIXME: Array_get ((_, Class_const _), _) is not a valid lvalue. *)
3786 (* Ideally we should put all the rest of the syntax here so everytime
3787 * a new syntax is added people need to consider whether the syntax
3788 * can be a valid lvalue or not. However, there are too many of them. *)
3790 let check_rvalue roperand
errors : SyntaxError.t list
=
3791 match syntax roperand
with
3792 | PrefixUnaryExpression
{ prefix_unary_operator
= op
; _ }
3793 when token_kind op
= Some
TokenKind.Ampersand
->
3794 append_errors roperand
errors (SyntaxError.references_not_allowed
)
3797 match syntax
node with
3798 | (PrefixUnaryExpression
3799 { prefix_unary_operator
= op
3800 ; prefix_unary_operand
= loperand
3802 | PostfixUnaryExpression
3803 { postfix_unary_operator
= op
3804 ; postfix_unary_operand
= loperand
3806 ) when does_unop_create_write (token_kind op
) ->
3807 check_lvalue ~allow_reassign_this
:true loperand
errors
3808 | DecoratedExpression
3809 { decorated_expression_decorator
= op
3810 ; decorated_expression_expression
= loperand
3811 } when does_decorator_create_write (token_kind op
) ->
3812 check_lvalue ~allow_reassign_this
:true loperand
errors
3814 { binary_left_operand
= loperand
3815 ; binary_operator
= op
3816 ; binary_right_operand
= roperand
3817 } when does_binop_create_write_on_left (token_kind op
) ->
3818 let errors = check_lvalue loperand
errors in
3819 check_rvalue roperand
errors
3825 check_lvalue k @@ check_lvalue v
errors
3829 let dynamic_method_call_errors node errors =
3830 match syntax
node with
3831 | FunctionCallExpression
3833 function_call_type_args
= type_args
;
3834 function_call_receiver
= receiver
; _ } when not
(is_missing type_args
) ->
3835 let is_dynamic = match syntax receiver
with
3836 | ScopeResolutionExpression
{ scope_resolution_name
= name; _ }
3837 | MemberSelectionExpression
{ member_name
= name; _ }
3838 | SafeMemberSelectionExpression
{ safe_member_name
= name; _ } ->
3839 is_token_kind name TokenKind.Variable
3842 if not
is_dynamic then errors else
3843 (make_error_from_node node SyntaxError.no_type_parameters_on_dynamic_method_calls
) :: errors
3846 let get_namespace_name context current_namespace_name
=
3847 match context.nested_namespaces
with
3848 | { syntax
= NamespaceDeclaration
{ namespace_name
= ns
; _ }; _ } :: _ ->
3849 if is_missing ns
then current_namespace_name
3850 else combine_names current_namespace_name
(text ns
)
3851 | _ -> current_namespace_name
3853 let is_invalid_hack_mode env
errors =
3854 if SyntaxTree.mode env
.syntax_tree
= None
then
3855 let root = SyntaxTree.root env
.syntax_tree
in
3856 let e = make_error_from_node root SyntaxError.invalid_hack_mode
in
3861 let find_syntax_errors env
=
3862 let has_rx_attr_mutable_hack attrs =
3863 attribute_first_reactivity_annotation attrs
3864 |> Option.value_map ~default
:false ~
f:(fun a
->
3865 match attribute_matches_criteria ((<>) SN.UserAttributes.uaNonRx
) a
with
3869 let rec folder env
acc node parents =
3874 ; trait_require_clauses
3875 ; is_in_concurrent_block
3878 { env with context =
3879 let node_syntax = syntax
node in
3880 match node_syntax with
3881 | ClassishDeclaration
_ ->
3882 { env.context with active_classish
= Some
node }
3883 | FunctionDeclaration
{ function_attribute_spec
= s; _ }
3884 | MethodishDeclaration
{ methodish_attribute
= s; _ } ->
3885 (* named functions *)
3887 (* a _single_ variable suffices as they cannot be nested *)
3888 active_methodish
= Some
node;
3889 (* inspect the rx attribute directly. *)
3890 active_is_rx_or_enclosing_for_lambdas
= has_rx_attr_mutable_hack s;
3891 active_callable
= Some
node;
3892 active_callable_attr_spec
= Some
s;
3894 | AnonymousFunction
{ anonymous_attribute_spec
= s; _ }
3895 | LambdaExpression
{ lambda_attribute_spec
= s; _ }
3896 | AwaitableCreationExpression
{ awaitable_attribute_spec
= s; _ } ->
3897 (* preserve context when entering lambdas (and anonymous functions) *)
3899 active_callable
= Some
node;
3900 active_callable_attr_spec
= Some
s;
3902 | ConstDeclaration
_ ->
3903 { env.context with active_const
= Some
node }
3904 | NamespaceDeclaration
{ namespace_name
; _ }
3905 when not
@@ is_missing namespace_name
&& text namespace_name
<> "" ->
3907 nested_namespaces
= node :: env.context.nested_namespaces
;
3912 parameter_errors env node namespace_name
names errors in
3913 let trait_require_clauses, names, errors =
3914 match syntax
node with
3916 | UsingStatementFunctionScoped
_
3920 let errors = statement_errors env node parents errors in
3921 trait_require_clauses, names, errors
3922 | MethodishDeclaration
_
3923 | FunctionDeclaration
_
3924 | FunctionDeclarationHeader
_ ->
3925 let errors = reified_parameter_errors node errors in
3927 redeclaration_errors env node parents namespace_name
names errors in
3929 methodish_errors env node errors in
3930 trait_require_clauses, names, errors
3931 | ArrayCreationExpression
_
3932 | ArrayIntrinsicExpression
_ ->
3934 expression_errors env is_in_concurrent_block namespace_name
node parents errors in
3935 trait_require_clauses, names, errors
3936 | InstanceofExpression
_
3937 | LiteralExpression
_
3938 | SafeMemberSelectionExpression
_
3939 | HaltCompilerExpression
_
3940 | FunctionCallExpression
_
3943 | DecoratedExpression
_
3944 | VectorIntrinsicExpression
_
3945 | DictionaryIntrinsicExpression
_
3946 | KeysetIntrinsicExpression
_
3947 | VarrayIntrinsicExpression
_
3948 | DarrayIntrinsicExpression
_
3949 | YieldFromExpression
_
3951 | ScopeResolutionExpression
_
3952 | PrefixUnaryExpression
_
3953 | LambdaExpression
_
3956 | AnonymousFunction
_
3957 | SubscriptExpression
_
3959 | AwaitableCreationExpression
_
3960 | PipeVariableExpression
_
3961 | ConditionalExpression
_
3962 | CollectionLiteralExpression
_
3963 | VariableExpression
_ ->
3964 let errors = dynamic_method_call_errors node errors in
3966 expression_errors env is_in_concurrent_block namespace_name
node parents errors in
3967 let errors = check_nonrx_annotation node errors in
3968 let errors = assignment_errors env node errors in
3969 trait_require_clauses, names, errors
3970 | RequireClause
_ ->
3971 let trait_require_clauses, errors =
3972 require_errors env node trait_require_clauses errors in
3973 trait_require_clauses, names, errors
3974 | ClassishDeclaration
_ ->
3976 classish_errors env node namespace_name
names errors in
3977 let errors = class_reified_param_errors env node errors in
3978 trait_require_clauses, names, errors
3979 | ConstDeclaration
_ ->
3981 class_element_errors env node errors in
3982 trait_require_clauses, names, errors
3983 | AliasDeclaration
_ ->
3984 let names, errors = alias_errors env node namespace_name
names errors in
3985 trait_require_clauses, names, errors
3986 | ConstantDeclarator
_ ->
3988 const_decl_errors env node namespace_name
names errors in
3989 trait_require_clauses, names, errors
3991 | NamespaceEmptyBody
_
3992 | NamespaceDeclaration
_ ->
3994 mixed_namespace_errors env node parents namespace_type
errors in
3995 trait_require_clauses, names, errors
3996 | NamespaceUseDeclaration
_
3997 | NamespaceGroupUseDeclaration
_ ->
3998 let errors = group_use_errors env node errors in
4000 namespace_use_declaration_errors env node
4001 (namespace_name
= global_namespace_name) names errors in
4002 trait_require_clauses, names, errors
4003 | PropertyDeclaration
_ ->
4004 let errors = class_property_visibility_errors env node errors in
4005 let errors = class_reified_param_errors env node errors in
4006 trait_require_clauses, names, errors
4007 | EnumDeclaration
_ ->
4008 let errors = enum_decl_errors node errors in
4009 trait_require_clauses, names, errors
4011 let errors = enumerator_errors node errors in
4012 trait_require_clauses, names, errors
4013 | PostfixUnaryExpression
_
4014 | BinaryExpression
_
4015 | ForeachStatement
_ ->
4016 let errors = assignment_errors env node errors in
4017 trait_require_clauses, names, errors
4019 | XHPExpression
_ ->
4020 let errors = xhp_errors env node errors in
4021 trait_require_clauses, names, errors
4022 | PropertyDeclarator
{ property_initializer
= init
; _ } ->
4024 produce_error errors check_static_in_initializer init
4025 SyntaxError.parent_static_prop_decl init
in
4026 let errors = check_constant_expression errors init
in
4027 trait_require_clauses, names, errors
4029 | XHPClassAttribute
{ xhp_attribute_decl_initializer
= init
; _ } ->
4030 let errors = check_constant_expression errors init
in
4031 trait_require_clauses, names, errors
4032 | _ -> trait_require_clauses, names, errors in
4034 let errors = lval_errors env node parents errors in
4036 match syntax
node with
4037 | LambdaExpression
_
4038 | AwaitableCreationExpression
_
4039 | AnonymousFunction
_ ->
4040 (* reset is_in_concurrent_block for functions *)
4043 acc errors namespace_type
names
4044 namespace_name
trait_require_clauses
4046 (* analyze the body of lambda block *)
4047 let acc1 = fold_child_nodes env folder node parents acc1 in
4048 (* adjust is_in_concurrent_block in final result *)
4050 acc acc1.errors acc1.namespace_type
acc1.names
4051 acc1.namespace_name
acc1.trait_require_clauses
4052 is_in_concurrent_block
4054 | ConcurrentStatement
{ concurrent_statement
= { syntax
= statement
; _ }; _ } ->
4055 (* issue error if concurrent blocks are nested *)
4057 if is_in_concurrent_block
4058 then make_error_from_node
4059 node SyntaxError.nested_concurrent_blocks
:: errors
4062 (* issue error if concurrent block isn't well formed
4063 - must have at least two statements
4064 - must be a compound statement
4065 - must only contain expression statements
4066 - statement without await
4068 let errors = (match statement
with
4069 | CompoundStatement
{ compound_statements
= statements
; _ } ->
4070 let statement_list = syntax_to_list_no_separators statements
in
4071 let errors = (match statement_list with
4072 | _ :: _ :: _ -> errors
4073 | _ -> make_error_from_node node
4074 SyntaxError.fewer_than_two_statements_in_concurrent_block
:: errors
4077 let errors = List.fold_left ~init
:errors ~
f:(fun errors n ->
4079 | ExpressionStatement
{ expression_statement_expression
= se
; _ } ->
4080 if node_has_await_child se
then errors else
4081 make_error_from_node n
4082 SyntaxError.statement_without_await_in_concurrent_block
:: errors
4083 | _ -> make_error_from_node n SyntaxError.invalid_syntax_concurrent_block
:: errors
4086 List.append
(find_invalid_lval_usage statement_list) errors
4087 | _ -> make_error_from_node node SyntaxError.invalid_syntax_concurrent_block
:: errors) in
4089 (* adjust is_in_concurrent_block in accumulator to dive into the
4093 acc errors namespace_type
names
4094 namespace_name
trait_require_clauses
4096 (* analyze the body of concurrent block *)
4097 let acc1 = fold_child_nodes env folder node parents acc1 in
4098 (* adjust is_in_concurrent_block in final result *)
4100 acc acc1.errors acc1.namespace_type
acc1.names
4101 acc1.namespace_name
acc1.trait_require_clauses
4102 is_in_concurrent_block
4104 | NamespaceBody
{ namespace_left_brace
; namespace_right_brace
; _ } ->
4105 let namespace_type =
4106 if namespace_type = Unspecified
4107 then Bracketed
(make_location namespace_left_brace namespace_right_brace
)
4108 else namespace_type in
4109 (* reset names/namespace_type before diving into namespace body,
4110 keeping global function names *)
4111 let namespace_name = get_namespace_name env.context namespace_name in
4112 let is_global _ f = f.f_global
in
4113 let global_funs names = strmap_filter is_global names.t_functions
in
4114 let new_names = {empty_names with t_functions
= global_funs names} in
4117 acc errors namespace_type new_names
4118 namespace_name empty_trait_require_clauses
4119 is_in_concurrent_block
4121 let acc1 = fold_child_nodes env folder node parents acc1 in
4122 (* add newly declared global functions to the old set of names *)
4124 {acc.names with t_functions
=
4125 strmap_union (global_funs acc1.names) acc.names.t_functions
}
4127 (* resume with old set of names and pull back
4128 accumulated errors/last seen namespace type *)
4130 acc acc1.errors namespace_type old_names
4131 acc.namespace_name acc.trait_require_clauses
4132 acc.is_in_concurrent_block
4133 | NamespaceEmptyBody
{ namespace_semicolon
; _ } ->
4134 let namespace_type =
4135 if namespace_type = Unspecified
4136 then Unbracketed
(make_location_of_node namespace_semicolon
)
4139 let namespace_name = get_namespace_name env.context namespace_name in
4140 (* consider the rest of file to be the part of the namespace:
4141 reset names and namespace type, keep errors *)
4144 acc errors namespace_type empty_names
4145 namespace_name empty_trait_require_clauses
4146 is_in_concurrent_block
4148 fold_child_nodes env folder node parents acc
4149 | ClassishDeclaration
_
4150 | AnonymousClass
_ ->
4151 (* Reset the trait require clauses *)
4152 (* Reset the const declarations *)
4153 (* Reset the function declarations *)
4156 { new_acc
with names =
4157 { new_acc
.names with t_constants
= acc.names.t_constants
;
4158 t_functions
= acc.names.t_functions
}} in
4159 let names = { names with t_constants
= YesCase
SMap.empty
;
4160 t_functions
= NoCase
LSMap.empty
} in
4163 acc errors namespace_type names
4164 namespace_name empty_trait_require_clauses
4165 is_in_concurrent_block
4167 fold_child_nodes ~
cleanup env folder node parents acc
4171 acc errors namespace_type names
4172 namespace_name trait_require_clauses
4173 is_in_concurrent_block
4175 fold_child_nodes env folder node parents acc in
4177 if is_typechecker env then is_invalid_hack_mode env []
4180 let acc = fold_child_nodes env folder (SyntaxTree.root env.syntax_tree
) []
4182 ; namespace_type = Unspecified
4183 ; names = empty_names
4184 ; namespace_name = global_namespace_name
4185 ; trait_require_clauses = empty_trait_require_clauses
4186 ; is_in_concurrent_block
= false
4190 let parse_errors_impl env =
4192 Minimum: suppress cascading errors; no second-pass errors if there are
4193 any first-pass errors.
4194 Typical: suppress cascading errors; give second pass errors always.
4198 let errors1 = match env.level
with
4199 | Maximum
-> SyntaxTree.all_errors
env.syntax_tree
4200 | _ -> SyntaxTree.errors env.syntax_tree
in
4202 if env.level
= Minimum
&& errors1 <> [] then []
4203 else find_syntax_errors env in
4204 List.sort
SyntaxError.compare (List.append
errors1 errors2)
4206 let error_msg = "UNEXPECTED_ERROR: " ^
(Exn.to_string
e) in
4207 [make_error_from_node (SyntaxTree.root env.syntax_tree
) error_msg]
4209 let parse_errors env =
4210 Stats_container.wrap_nullary_fn_timing
4211 ?stats
:(Stats_container.get_instance
())
4212 ~key
:"full_fidelity_parse_errors:parse_errors"
4213 ~
f:(fun () -> parse_errors_impl env)
4215 end (* WithSmartConstructors *)
4217 include WithSmartConstructors
(SyntaxSmartConstructors.WithSyntax
(Syntax
))
4219 end (* WithSyntax *)