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.
11 module WithSyntax
(Syntax
: Syntax_sig.Syntax_S
) = struct
12 module WithSmartConstructors
(SCI
: SmartConstructors.SmartConstructors_S
13 with type r
= Syntax.t
14 with module Token
= Syntax.Token
19 module SyntaxTree_
= Full_fidelity_syntax_tree
21 module SyntaxTree
= SyntaxTree_.WithSmartConstructors
(SCI
)
23 module Token
= Syntax.Token
24 module SyntaxError
= Full_fidelity_syntax_error
25 module SyntaxKind
= Full_fidelity_syntax_kind
26 module TokenKind
= Full_fidelity_token_kind
28 module SN
= Naming_special_names
36 Option.value ~default
:"<text_extraction_failure>" (Syntax.extract_text node
)
38 let make_location s e
=
39 match position
Relative_path.default s
, position
Relative_path.default e
with
41 let start_offset, _
= Pos.info_raw s
in
42 let _, end_offset
= Pos.info_raw e
in
43 { start_offset ; end_offset
}
45 failwith
"Could not determine positions of parse tree nodes."
47 let make_location_of_node n
=
51 let s = Syntax.position
Relative_path.default n
in
52 let s, _ = Pos.info_raw
(Option.value ~default
:Pos.none
s) in
56 let e = Syntax.position
Relative_path.default n
in
57 let _, e = Pos.info_raw
(Option.value ~default
:Pos.none
e) in
62 | Bracketed
of location
63 | Unbracketed
of location
66 | Name_use
(* `use` construct *)
67 | Name_def
(* definition e.g. `class` or `trait` *)
68 | Name_implicit_use
(* implicit `use` e.g. HH type in type hint *)
70 type first_use_or_def
= {
77 type error_level
= Minimum
| Typical
| Maximum
79 type hhvm_compat_mode
= NoCompat
| HHVMCompat
| SystemLibCompat
82 { syntax_tree
: SyntaxTree.t
84 ; hhvm_compat_mode
: hhvm_compat_mode
85 ; enable_hh_syntax
: bool
93 ?
(hhvm_compat_mode
= NoCompat
)
94 ?
(enable_hh_syntax
= false )
95 (syntax_tree
: SyntaxTree.t
)
102 ; is_hh_file
= SyntaxTree.is_hack syntax_tree
103 ; is_strict
= SyntaxTree.is_strict syntax_tree
107 and is_hhvm_compat env
= env
.hhvm_compat_mode
<> NoCompat
109 and is_systemlib_compat env
= env
.hhvm_compat_mode
= SystemLibCompat
111 and is_hack env
= env
.is_hh_file
|| env
.enable_hh_syntax
113 let is_typechecker env
=
114 is_hack env
&& (not env
.codegen
)
115 let global_namespace_name = "\\"
117 let combine_names n1 n2
=
118 let has_leading_slash = String.length n2
> 0 && String.get n2
0 = '
\\'
in
119 let len = String.length n1
in
120 let has_trailing_slash = String.get n1
(len - 1) = '
\\'
in
121 match has_leading_slash, has_trailing_slash with
122 | true, true -> n1 ^
(String.sub n2
1 (String.length n2
- 1))
123 | false, false -> n1 ^
"\\" ^ n2
126 let make_first_use_or_def ~kind ?
(is_method
=false) location namespace_name name
=
128 f_location
= location
;
130 f_name
= combine_names namespace_name name
;
131 f_global
= not is_method
&& namespace_name
= global_namespace_name;
135 | YesCase
of 'a
SMap.t
136 | NoCase
of 'a
LSMap.t
140 t_classes
: first_use_or_def strmap
; (* NoCase *)
141 t_namespaces
: first_use_or_def strmap
; (* NoCase *)
142 t_functions
: first_use_or_def strmap
; (* NoCase *)
143 t_constants
: first_use_or_def strmap
; (* YesCase *)
147 t_classes
= NoCase
LSMap.empty
;
148 t_namespaces
= NoCase
LSMap.empty
;
149 t_functions
= NoCase
LSMap.empty
;
150 t_constants
= YesCase
SMap.empty
;
153 let strmap_mem : string -> 'a strmap
-> bool =
156 | NoCase m
-> LSMap.mem k m
157 | YesCase m
-> SMap.mem k m
160 let strmap_add : string -> 'a
-> 'a strmap
-> 'a strmap
=
163 | NoCase m'
-> NoCase
(LSMap.add k v m'
)
164 | YesCase m'
-> YesCase
(SMap.add k v m'
)
167 let strmap_get : string -> 'a strmap
-> 'a
option =
170 | NoCase m'
-> LSMap.get k m'
171 | YesCase m'
-> SMap.get k m'
174 let strmap_find_first_opt : (string -> bool) -> 'a strmap
-> (string * 'a
) option =
177 | NoCase m'
-> LSMap.find_first_opt k m'
178 | YesCase m'
-> SMap.find_first_opt k m'
181 let strmap_filter : (string -> 'a
-> bool) -> 'a strmap
-> 'a strmap
=
184 | NoCase m'
-> NoCase
(LSMap.filter f m'
)
185 | YesCase m'
-> YesCase
(SMap.filter f m'
)
188 let strmap_union : 'a strmap
-> 'a strmap
-> 'a strmap
=
190 begin match x
, y
with
191 | NoCase x'
, NoCase y'
-> NoCase
(LSMap.union x' y'
)
192 | YesCase x'
, YesCase y'
-> YesCase
(SMap.union x' y'
)
193 | NoCase
_, YesCase
_ -> failwith
"cannot union NoCase and YesCase."
194 | YesCase
_, NoCase
_ -> failwith
"cannot union YesCase and NoCase."
197 let empty_trait_require_clauses = NoCase
LSMap.empty
199 let get_short_name_from_qualified_name name alias
=
200 if String.length alias
<> 0 then alias
203 let i = String.rindex name '
\\'
in
204 String.sub name
(i + 1) (String.length name
- i - 1)
205 with Not_found
-> name
208 errors
: SyntaxError.t list
;
209 namespace_type
: namespace_type
;
210 namespace_name
: string;
212 trait_require_clauses
: TokenKind.t strmap
;
216 acc errors namespace_type names namespace_name trait_require_clauses
=
217 if acc
.errors
== errors
&&
218 acc
.namespace_type
== namespace_type
&&
219 acc
.names
== names
&&
220 acc
.namespace_name
== namespace_name
&&
221 acc
.trait_require_clauses
== trait_require_clauses
227 ; trait_require_clauses
230 let fold_child_nodes ?
(cleanup
= (fun x
-> x
)) f node parents acc
=
232 |> Core_list.fold_left ~init
:acc ~f
:(fun acc c
-> f acc c
(node
:: parents
))
235 (* Turns a syntax node into a list of nodes; if it is a separated syntax
236 list then the separators are filtered from the resulting list. *)
237 let syntax_to_list include_separators node
=
238 let rec aux acc syntax_list
=
239 match syntax_list
with
244 | ListItem
{ list_item
; list_separator
} ->
245 let acc = list_item
:: acc in
247 if include_separators
then (list_separator
:: acc ) else acc in
249 | _ -> aux (h
:: acc) t
251 match syntax node
with
253 | SyntaxList
s -> List.rev
(aux [] s)
254 | ListItem
{ list_item
; list_separator
} ->
255 if include_separators
then [ list_item
; list_separator
] else [ list_item
]
258 let syntax_to_list_no_separators = syntax_to_list false
259 let syntax_to_list_with_separators = syntax_to_list true
261 let assert_last_in_list assert_fun node
=
266 | h
:: _ when assert_fun h
-> Some h
268 aux (syntax_to_list_no_separators node
)
270 let is_decorated_expression ~f node
=
271 begin match syntax node
with
272 | DecoratedExpression
{ decorated_expression_decorator
; _ } ->
273 f decorated_expression_decorator
277 let test_decorated_expression_child ~f node
=
278 begin match syntax node
with
279 | DecoratedExpression
{ decorated_expression_expression
; _ } ->
280 f decorated_expression_expression
284 (* Test two levels in case ...& or &... hiding under *)
285 let rec is_reference_expression node
=
286 is_decorated_expression ~f
:is_ampersand node
||
287 test_decorated_expression_child node ~f
:is_reference_expression
289 let rec is_variadic_expression node
=
290 is_decorated_expression ~f
:is_ellipsis node
||
291 test_decorated_expression_child node ~f
:is_variadic_expression
293 let is_reference_variadic node
=
294 is_decorated_expression ~f
:is_ellipsis node
&&
295 test_decorated_expression_child node ~f
:is_reference_expression
297 let is_double_variadic node
=
298 is_decorated_expression ~f
:is_ellipsis node
&&
299 test_decorated_expression_child node ~f
:is_variadic_expression
301 let is_double_reference node
=
302 is_decorated_expression ~f
:is_ampersand node
&&
303 test_decorated_expression_child node ~f
:is_reference_expression
305 let is_variadic_parameter_variable node
=
306 (* TODO: This shouldn't be a decorated *expression* because we are not
307 expecting an expression at all. We're expecting a declaration. *)
308 is_variadic_expression node
310 let is_variadic_parameter_declaration node
=
311 begin match syntax node
with
312 | VariadicParameter
_ -> true
313 | ParameterDeclaration
{ parameter_name
; _ } ->
314 is_variadic_parameter_variable parameter_name
318 let misplaced_variadic_param params
=
319 assert_last_in_list is_variadic_parameter_declaration params
321 let misplaced_variadic_arg args
=
322 assert_last_in_list is_variadic_expression args
324 (* If a list ends with a variadic parameter followed by a comma, return it *)
325 let ends_with_variadic_comma params
=
329 | x
:: y
:: [] when is_variadic_parameter_declaration x
&& is_comma y
->
332 aux (syntax_to_list_with_separators params
)
334 (* Extract variadic parameter from a parameter list *)
335 let variadic_param params
=
339 | x
:: _ when is_variadic_parameter_declaration x
-> Some x
341 aux (syntax_to_list_with_separators params
)
343 let is_parameter_with_default_value param
=
344 match syntax param
with
345 | ParameterDeclaration
{ parameter_default_value
; _ } ->
346 not
(is_missing parameter_default_value
)
349 (* True or false: the first item in this list matches the predicate? *)
350 let matches_first f items
=
352 | h
:: _ when f h
-> true
355 (* test a node is a syntaxlist and that the list contains an element
356 * satisfying a given predicate *)
357 let list_contains_predicate p node
=
358 match syntax node
with
363 (* test a node is a syntaxlist and that the list contains multiple elements
364 * satisfying a given predicate *)
365 let list_contains_multiple_predicate p node
=
366 match syntax node
with
368 let count_fun acc el
= if p el
then acc + 1 else acc in
369 (List.fold_left
count_fun 0 lst
) > 1
372 let list_contains_duplicate node
=
373 let module SyntaxMap
= Map.Make
(
376 let compare a b
= match syntax a
, syntax b
with
377 | Token x
, Token y
->
378 Token.(compare (kind x
) (kind y
))
379 | _, _ -> Pervasives.compare a b
382 match syntax node
with
384 let check_fun (tbl
, acc) el
=
385 if SyntaxMap.mem el tbl
then (tbl
, true)
386 else (SyntaxMap.add el
() tbl
, acc)
388 let (_, result
) = List.fold_left
check_fun (SyntaxMap.empty
, false) lst
in
392 let token_kind node
=
393 match syntax node
with
394 | Token t
-> Some
(Token.kind t
)
397 (* Helper function for common code pattern *)
398 let is_token_kind node kind
=
399 (token_kind node
) = Some kind
401 let rec containing_classish_kind parents
=
407 | ClassishDeclaration c
-> token_kind c
.classish_keyword
408 | _ -> containing_classish_kind t
411 let modifiers_of_function_decl_header_exn node
=
412 match syntax node
with
413 | FunctionDeclarationHeader
{ function_modifiers
= m
; _ } -> m
414 | _ -> failwith
"expected to get FunctionDeclarationHeader"
416 let get_modifiers_of_declaration node
=
417 match syntax node
with
418 | MethodishDeclaration
{ methodish_function_decl_header
= header
; _ } ->
419 Some
(modifiers_of_function_decl_header_exn header
)
420 | PropertyDeclaration
{ property_modifiers
; _} ->
421 Some
(property_modifiers
)
424 (* tests whether the methodish contains a modifier that satisfies [p] *)
425 let methodish_modifier_contains_helper p node
=
426 get_modifiers_of_declaration node
427 |> Option.exists ~f
:(list_contains_predicate p
)
429 (* tests whether the methodish contains > 1 modifier that satisfies [p] *)
430 let methodish_modifier_multiple_helper p node
=
431 get_modifiers_of_declaration node
432 |> Option.value_map ~default
:false ~f
:(list_contains_multiple_predicate p
)
434 (* test the methodish node contains the Final keyword *)
435 let methodish_contains_final node
=
436 methodish_modifier_contains_helper is_final node
438 (* test the methodish node contains the Abstract keyword *)
439 let methodish_contains_abstract node
=
440 methodish_modifier_contains_helper is_abstract node
442 (* test the methodish node contains the Static keyword *)
443 let methodish_contains_static node
=
444 methodish_modifier_contains_helper is_static node
446 (* test the methodish node contains the Private keyword *)
447 let methodish_contains_private node
=
448 methodish_modifier_contains_helper is_private node
450 let is_visibility x
=
451 is_public x
|| is_private x
|| is_protected x
453 let contains_async_not_last mods
=
454 let mod_list = syntax_to_list_no_separators mods
in
455 List.exists is_async
mod_list
456 && not
@@ is_async
@@ List.nth
mod_list (List.length
mod_list - 1)
458 let has_static node parents f
=
460 | FunctionDeclarationHeader node
->
461 let label = node
.function_name
in
463 (matches_first (methodish_contains_static) parents
)
466 (* checks if a methodish decl or property has multiple visibility modifiers *)
467 let declaration_multiple_visibility node
=
468 methodish_modifier_multiple_helper is_visibility node
470 (* Given a function declaration header, confirm that it is a constructor
471 * and that the methodish containing it has a static keyword *)
474 String.lowercase_ascii
(text label) = SN.SpecialFunctions.clone
476 let class_constructor_has_static node parents
=
477 has_static node parents is_construct
479 let class_destructor_cannot_be_static node parents
=
480 has_static node parents
(is_destruct
)
482 let clone_cannot_be_static node parents
=
483 has_static node parents
is_clone
485 (* Given a function declaration header, confirm that it is NOT a constructor
486 * and that the header containing it has visibility modifiers in parameters
488 let class_non_constructor_has_visibility_param node _parents
=
490 | FunctionDeclarationHeader node
->
491 let has_visibility node
=
492 match syntax node
with
493 | ParameterDeclaration
{ parameter_visibility
; _ } ->
494 parameter_visibility
|> is_missing
|> not
497 let label = node
.function_name
in
498 let params = syntax_to_list_no_separators node
.function_parameter_list
in
499 (not
(is_construct
label)) && (List.exists
has_visibility params)
502 (* check that a constructor or a destructor is type annotated *)
503 let class_constructor_destructor_has_non_void_type env node _parents
=
504 if not
(is_typechecker env
) then false
507 | FunctionDeclarationHeader node
->
508 let label = node
.function_name
in
509 let type_ano = node
.function_type
in
510 let function_colon = node
.function_colon in
511 let is_missing = is_missing type_ano && is_missing function_colon in
512 let is_void = match syntax
type_ano with
513 | SimpleTypeSpecifier spec
->
514 is_void spec
.simple_type_specifier
517 (is_construct
label || is_destruct
label) &&
518 not
(is_missing || is_void)
520 let async_magic_method node _parents
=
522 | FunctionDeclarationHeader node
->
523 let name = String.lowercase_ascii
@@ text node
.function_name
in
524 begin match name with
525 | _ when name = String.lowercase_ascii
SN.Members.__disposeAsync
-> false
526 | _ when SSet.mem
name SN.Members.as_lowercase_set
->
527 list_contains_predicate is_async node
.function_modifiers
533 let clone_destruct_takes_no_arguments _method_name node _parents
=
535 | FunctionDeclarationHeader
{ function_parameter_list
= l
; function_name
= name; _} ->
536 let num_params = List.length
(syntax_to_list_no_separators l
) in
537 ((is_clone name) || (is_destruct
name)) && num_params <> 0
540 (* whether a methodish has duplicate modifiers *)
541 let methodish_duplicate_modifier node
=
542 get_modifiers_of_declaration node
543 |> Option.value_map ~default
:false ~f
:list_contains_duplicate
545 (* whether a methodish decl has body *)
546 let methodish_has_body node
=
547 match syntax node
with
548 | MethodishDeclaration syntax
->
549 let body = syntax
.methodish_function_body
in
550 not
(is_missing body)
553 (* whether a methodish decl is native *)
554 let methodish_is_native node
=
555 match syntax node
with
556 | MethodishDeclaration
{ methodish_attribute
= {
557 syntax
= AttributeSpecification
{
558 attribute_specification_attributes
= attrs
; _}; _}; _} ->
559 let attrs = syntax_to_list_no_separators attrs in
560 Hh_core.List.exists
attrs
561 ~f
:(function { syntax
= Attribute
{attribute_name
; _}; _} ->
562 String.lowercase_ascii
@@ text attribute_name
= "__native"
566 (* By checking the third parent of a methodish node, tests whether the methodish
567 * node is inside an interface. *)
568 let methodish_inside_interface parents
=
570 | _ :: _ :: p3
:: _ ->
571 begin match syntax p3
with
572 | ClassishDeclaration
{ classish_keyword
; _ } ->
573 is_token_kind classish_keyword
TokenKind.Interface
578 (* Test whether node is a non-abstract method without a body and not native.
579 * Here node is the methodish node
580 * And methods inside interfaces are inherently considered abstract *)
581 let methodish_non_abstract_without_body_not_native node parents
=
582 let non_abstract = not
(methodish_contains_abstract node
583 || methodish_inside_interface parents
) in
584 let not_has_body = not
(methodish_has_body node
) in
585 let not_native = not
(methodish_is_native node
) in
586 non_abstract && not_has_body && not_native
588 (* Test whether node is a method that is both abstract and private
590 let methodish_abstract_conflict_with_private node
=
591 let is_abstract = methodish_contains_abstract node
in
592 let has_private = methodish_contains_private node
in
593 is_abstract && has_private
595 (* Test whether node is a method that is both abstract and final
597 let methodish_abstract_conflict_with_final node
=
598 let is_abstract = methodish_contains_abstract node
in
599 let has_final = methodish_contains_final node
in
600 is_abstract && has_final
602 let using_statement_function_scoped_is_legal parents
=
604 (* using is allowed in the toplevel, and also in toplevel async blocks *)
606 { syntax
= CompoundStatement
_; _ } ::
608 FunctionDeclaration
_ |
609 MethodishDeclaration
_ |
610 AnonymousFunction
_ |
612 AwaitableCreationExpression
_); _ } :: _ -> true
615 let make_error_from_nodes
616 ?
(error_type
=SyntaxError.ParseError
) start_node end_node error
=
617 let s = start_offset start_node
in
618 let e = end_offset end_node
in
619 SyntaxError.make ~error_type
s e error
621 let make_error_from_node ?
(error_type
=SyntaxError.ParseError
) node error
=
622 make_error_from_nodes ~error_type node node error
624 let is_invalid_xhp_attr_enum_item_literal literal_expression
=
625 match syntax literal_expression
with
627 Full_fidelity_token_kind.(match Token.kind t
with
628 | DecimalLiteral
| SingleQuotedStringLiteral
629 | DoubleQuotedStringLiteral
-> false
634 let is_invalid_xhp_attr_enum_item node
=
635 match syntax node
with
636 | LiteralExpression
{literal_expression
} ->
637 is_invalid_xhp_attr_enum_item_literal literal_expression
640 let xhp_errors env node errors
=
641 match syntax node
with
642 | XHPEnumType enumType
when
643 (is_typechecker env
) &&
644 (is_missing enumType
.xhp_enum_values
) ->
645 make_error_from_node enumType
.xhp_enum_values
SyntaxError.error2055
:: errors
646 | XHPEnumType enumType
when
647 (is_typechecker env
) ->
648 let invalid_enum_items = List.filter
is_invalid_xhp_attr_enum_item
649 (syntax_to_list_no_separators enumType
.xhp_enum_values
) in
650 let mapper errors item
=
651 make_error_from_node item
SyntaxError.error2063
:: errors
in
652 List.fold_left
mapper errors
invalid_enum_items
655 { syntax
= XHPOpen
{ xhp_open_name
; _ }; _ }
657 { syntax
= XHPClose
{ xhp_close_name
; _ }; _ }
658 ; _ } when text xhp_open_name
<> text xhp_close_name
->
659 make_error_from_node node
(SyntaxError.error2070
660 ~open_tag
:(text xhp_open_name
)
661 ~close_tag
:(text xhp_close_name
)) :: errors
666 let classish_duplicate_modifiers node
=
667 list_contains_duplicate node
670 (* helper since there are so many kinds of errors *)
671 let produce_error acc check node error error_node
=
673 (make_error_from_node error_node error
) :: acc
676 let produce_error_from_check acc check node error
=
677 match check node
with
679 (make_error_from_node error_node error
) :: acc
682 let produce_error_parents acc check node parents error error_node
=
683 if check node parents
then
684 (make_error_from_node error_node error
) :: acc
687 (* use [check] to check properties of function *)
688 let function_header_check_helper check node parents
=
689 check
(syntax node
) parents
691 let produce_error_for_header acc check node error error_node
=
692 produce_error_parents acc (function_header_check_helper check
) node
696 let is_reserved_keyword env classish_name
=
697 let name = text classish_name
in
698 (* TODO: What else goes here? *)
699 match String.lowercase_ascii
name with
700 | "eval" | "isset" | "unset" | "empty" | "const" | "new"
701 | "and" | "or" | "xor" | "as" | "print" | "throw"
702 | "array" | "instanceof" | "trait" | "class" | "interface"
704 | "using" | "inout" when is_hack env
-> true
707 (* Given a function_declaration_header node, returns its function_name
708 * as a string opt. *)
709 let extract_function_name header_node
=
710 (* The '_' arm of this match will never be reached, but the type checker
711 * doesn't allow a direct extraction of function_name from
712 * function_declaration_header. *)
713 match syntax header_node
with
714 | FunctionDeclarationHeader fdh
->
715 Syntax.extract_text fdh
.function_name
718 (* Return, as a string opt, the name of the function with the earliest
719 * declaration node in the list of parents. *)
720 let first_parent_function_name parents
=
721 Hh_core.List.find_map parents ~f
:begin fun node
->
722 match syntax node
with
723 | FunctionDeclaration
{function_declaration_header
= header
; _ }
724 | MethodishDeclaration
{methodish_function_decl_header
= header
; _ } ->
725 extract_function_name header
730 (* Given a particular TokenKind.(Trait/Interface), tests if a given
731 * classish_declaration node is both of that kind and declared abstract. *)
732 let is_classish_kind_declared_abstract env cd_node
=
733 if not
(is_hack env
) then false
735 match syntax cd_node
with
736 | ClassishDeclaration
{ classish_keyword
; classish_modifiers
; _ }
737 when is_token_kind classish_keyword
TokenKind.Trait
738 || is_token_kind classish_keyword
TokenKind.Interface
->
739 list_contains_predicate is_abstract classish_modifiers
742 let rec is_immediately_in_lambda = function
743 | { syntax
= LambdaExpression
_; _} :: _ -> true
744 | [] | { syntax
= (FunctionDeclaration
_ | MethodishDeclaration
_); _} :: _
746 | _ :: xs
-> is_immediately_in_lambda xs
748 (* Returns the whether the current context is in an active class scope *)
749 let is_in_active_class_scope parents
=
750 Hh_core.List.exists parents ~f
:begin fun node
->
751 match syntax node
with
752 | ClassishDeclaration
_ -> true
756 (* Returns the first ClassishDeclaration node in the list of parents,
757 * or None if there isn't one. *)
758 let first_parent_classish_node classish_kind parents
=
759 Hh_core.List.find_map parents ~f
:begin fun node
->
760 match syntax node
with
761 | ClassishDeclaration cd
762 when is_token_kind cd
.classish_keyword classish_kind
-> Some node
766 (* Return, as a string opt, the name of the earliest Class in the list of
768 let first_parent_class_name parents
=
769 let parent_class_decl = first_parent_classish_node TokenKind.Class parents
in
770 Option.value_map
parent_class_decl ~default
:None ~f
:begin fun node
->
771 match syntax node
with
772 | ClassishDeclaration cd
-> Syntax.extract_text cd
.classish_name
773 | _ -> None
(* This arm is never reached *)
776 (* Return, as a string opt, the name of the closest enclosing classish entity in
777 the list of parents(not just Classes ) *)
778 let enclosing_classish_name parents
=
779 Hh_core.List.find_map parents ~f
:begin fun node
->
780 match syntax node
with
781 | ClassishDeclaration cd
-> Syntax.extract_text cd
.classish_name
786 (* Given a classish_ or methodish_ declaration node, returns the modifier node
787 from its list of modifiers, or None if there isn't one. *)
788 let extract_keyword modifier declaration_node
=
789 let aux modifiers_list
=
790 Hh_core.List.find ~f
:modifier
(syntax_to_list_no_separators modifiers_list
)
793 match syntax declaration_node
with
794 | ClassishDeclaration
{ classish_modifiers
= modifiers_list
; _ } ->
797 Option.bind
(get_modifiers_of_declaration declaration_node
) aux
799 (* Wrapper function that uses above extract_keyword function to test if node
800 contains is_abstract keyword *)
801 let is_abstract_declaration declaration_node
=
802 not
(Option.is_none
(extract_keyword is_abstract declaration_node
))
804 (* Given a list of parents, tests if the immediate classish parent is an
806 let is_inside_interface parents
=
807 Option.is_some
(first_parent_classish_node TokenKind.Interface parents
)
809 (* Given a list of parents, tests if the immediate classish parent is a
811 let is_inside_trait parents
=
812 Option.is_some
(first_parent_classish_node TokenKind.Trait parents
)
814 (* Tests if md_node is either explicitly declared abstract or is
815 * defined inside an interface *)
816 let is_generalized_abstract_method md_node parents
=
817 is_abstract_declaration md_node
|| is_inside_interface parents
819 (* Returns the 'async'-annotation syntax node from the methodish_declaration
820 * node. The returned node may have syntax kind 'Missing', but it will only be
821 * None if something other than a methodish_declaration node was provided as
823 let extract_async_node md_node
=
824 get_modifiers_of_declaration md_node
825 |> Option.value_map ~default
:[] ~f
:syntax_to_list_no_separators
826 |> Hh_core.List.find ~f
:is_async
828 let get_params_and_is_async_for_first_parent_function_or_lambda parents
=
829 Hh_core.List.find_map parents ~f
:begin fun node
->
830 match syntax node
with
831 | FunctionDeclaration
{ function_declaration_header
= header
; _ }
832 | MethodishDeclaration
{ methodish_function_decl_header
= header
; _ } ->
833 begin match syntax header
with
834 | FunctionDeclarationHeader fdh
->
835 let is_async = Hh_core.List.exists ~f
:is_async @@
836 syntax_to_list_no_separators fdh
.function_modifiers
in
837 Some
(fdh
.function_parameter_list
, is_async)
840 | LambdaExpression
{ lambda_signature
; lambda_async
; _} ->
841 begin match syntax lambda_signature
with
842 | LambdaSignature
{ lambda_parameters
; _ } ->
843 Some
(lambda_parameters
, not
@@ is_missing lambda_async
)
849 let first_parent_function_attributes_contains parents
name =
850 Hh_core.List.exists parents ~f
:begin fun node
->
851 match syntax node
with
852 | FunctionDeclaration
{ function_attribute_spec
= {
853 syntax
= AttributeSpecification
{
854 attribute_specification_attributes
; _ }; _ }; _ }
855 | MethodishDeclaration
{ methodish_attribute
= {
856 syntax
= AttributeSpecification
{
857 attribute_specification_attributes
; _ }; _ }; _ } ->
859 syntax_to_list_no_separators attribute_specification_attributes
in
860 Hh_core.List.exists
attrs
861 ~f
:(function { syntax
= Attribute
{ attribute_name
; _}; _} ->
862 text attribute_name
= name | _ -> false)
866 let is_parameter_with_callconv param
=
867 match syntax param
with
868 | ParameterDeclaration
{ parameter_call_convention
; _ } ->
869 not
@@ is_missing parameter_call_convention
870 | ClosureParameterTypeSpecifier
{ closure_parameter_call_convention
; _ } ->
871 not
@@ is_missing closure_parameter_call_convention
872 | VariadicParameter
{ variadic_parameter_call_convention
; _ } ->
873 not
@@ is_missing variadic_parameter_call_convention
876 let has_inout_params parents
=
877 match get_params_and_is_async_for_first_parent_function_or_lambda parents
with
878 | Some
(function_parameter_list
, _) ->
879 let params = syntax_to_list_no_separators function_parameter_list
in
880 Hh_core.List.exists
params ~f
:is_parameter_with_callconv
883 let is_inside_async_method parents
=
884 match get_params_and_is_async_for_first_parent_function_or_lambda parents
with
885 | Some
(_, is_async) -> is_async
888 let make_name_already_used_error node
name short_name original_location
890 let name = Utils.strip_ns
name in
891 let original_location_error =
893 original_location
.start_offset
894 original_location
.end_offset
895 SyntaxError.original_definition
in
896 let s = start_offset node
in
897 let e = end_offset node
in
899 ~child
:(Some
original_location_error) s e (report_error ~
name ~short_name
)
901 let check_type_name_reference env name_text location names errors
=
902 if not
(is_hack env
&& Hh_autoimport.is_hh_autoimport name_text
)
903 || strmap_mem name_text names
.t_classes
906 let def = make_first_use_or_def ~kind
:Name_implicit_use location
"HH" name_text
in
907 let names = { names with t_classes
= strmap_add name_text
def names.t_classes
} in
910 let check_type_hint env node
names errors
=
911 let rec check (names, errors
) node
=
913 Core_list.fold_left
(Syntax.children node
) ~f
:check ~init
:(names, errors
) in
914 match syntax node
with
915 | SimpleTypeSpecifier
{ simple_type_specifier
= s; _ }
916 | GenericTypeSpecifier
{ generic_class_type
= s; _ } ->
917 check_type_name_reference env
(text s) (make_location_of_node node
) names errors
921 check (names, errors
) node
923 (* Given a node and its parents, tests if the node declares a method that is
924 * both abstract and async. *)
925 let is_abstract_and_async_method md_node parents
=
926 let async_node = extract_async_node md_node
in
927 match async_node with
930 is_generalized_abstract_method md_node parents
931 && not
(is_missing async_node)
933 let extract_callconv_node node
=
934 match syntax node
with
935 | ParameterDeclaration
{ parameter_call_convention
; _ } ->
936 Some parameter_call_convention
937 | ClosureParameterTypeSpecifier
{ closure_parameter_call_convention
; _ } ->
938 Some closure_parameter_call_convention
939 | VariadicParameter
{ variadic_parameter_call_convention
; _ } ->
940 Some variadic_parameter_call_convention
943 (* Test if a list_expression is the value clause of a foreach_statement *)
944 let is_value_of_foreach le_node p1
=
946 | ForeachStatement
{ foreach_value
; _ } -> le_node
== foreach_value
949 (* Given a node, checks if it is a abstract ConstDeclaration *)
950 let is_abstract_const declaration
=
951 match syntax declaration
with
952 | ConstDeclaration x
-> not
(is_missing x
.const_abstract
)
955 (* Given a ConstDeclarator node, test whether it is abstract, but has an
957 let constant_abstract_with_initializer init parents
=
960 | _p_list_item
:: _p_syntax_list
:: p_const_declaration
:: _
961 when is_abstract_const p_const_declaration
-> true
964 let has_initializer =
965 not
(is_missing init
) in
966 is_abstract && has_initializer
968 (* Given a node, checks if it is a concrete ConstDeclaration *)
969 let is_concrete_const declaration
=
970 match syntax declaration
with
971 | ConstDeclaration x
-> is_missing x
.const_abstract
974 (* Given a ConstDeclarator node, test whether it is concrete, but has no
976 let constant_concrete_without_initializer init parents
=
977 let is_concrete = match parents
with
978 | _p_list_item
:: _p_syntax_list
:: p_const_declaration
:: _ ->
979 is_concrete_const p_const_declaration
981 is_concrete && is_missing init
983 (* Given a PropertyDeclaration node, tests whether parent class is abstract
984 final but child variable is non-static *)
986 let is_byref_expression node
=
987 is_decorated_expression ~f
:is_ampersand node
989 let is_byref_parameter_variable node
=
990 (* TODO: This shouldn't be a decorated *expression* because we are not
991 expecting an expression at all. We're expecting a declaration. *)
992 is_byref_expression node
994 let is_param_by_ref node
=
995 match syntax node
with
996 | ParameterDeclaration
{ parameter_name
; _ } ->
997 is_byref_parameter_variable parameter_name
1000 let special_method_param_errors node parents errors
=
1001 match syntax node
with
1002 | FunctionDeclarationHeader
{function_name
; function_parameter_list
; _}
1003 when SSet.mem
(String.lowercase_ascii
@@ text function_name
)
1004 SN.Members.as_lowercase_set
->
1005 let params = syntax_to_list_no_separators function_parameter_list
in
1006 let len = Hh_core.List.length
params in
1007 let name = text function_name
in
1008 let full_name = match first_parent_class_name parents
with
1010 | Some c_name
-> c_name ^
"::" ^
name ^
"()"
1012 let s = String.lowercase_ascii
name in
1015 | _ when s = SN.Members.__call
&& len <> 2 -> Some
2
1016 | _ when s = String.lowercase_ascii
SN.Members.__callStatic
&& len <> 2 -> Some
2
1017 | _ when s = SN.Members.__get
&& len <> 1 -> Some
1
1018 | _ when s = SN.Members.__set
&& len <> 2 -> Some
2
1019 | _ when s = SN.Members.__isset
&& len <> 1 -> Some
1
1020 | _ when s = SN.Members.__unset
&& len <> 1 -> Some
1
1023 let errors = match num_args_opt with
1026 make_error_from_node
1027 node
(SyntaxError.invalid_number_of_args
full_name n
) :: errors
1029 let errors = if (s = SN.Members.__call
1030 || s = String.lowercase_ascii
SN.Members.__callStatic
1031 || s = SN.Members.__get
1032 || s = SN.Members.__set
1033 || s = SN.Members.__isset
1034 || s = SN.Members.__unset
)
1035 && Hh_core.List.exists ~f
:is_param_by_ref params then
1036 make_error_from_node
1037 node
(SyntaxError.invalid_args_by_ref
full_name) :: errors
1043 let methodish_errors env node parents
errors =
1044 match syntax node
with
1045 (* TODO how to narrow the range of error *)
1046 | FunctionDeclarationHeader
{ function_parameter_list
; function_type
; _} ->
1048 produce_error_for_header errors
1049 (class_constructor_destructor_has_non_void_type env
)
1050 node parents
SyntaxError.error2018 function_type
in
1052 produce_error_for_header errors class_non_constructor_has_visibility_param
1053 node parents
SyntaxError.error2010 function_parameter_list
in
1055 | MethodishDeclaration md
->
1056 let header_node = md
.methodish_function_decl_header
in
1057 let modifiers = modifiers_of_function_decl_header_exn header_node in
1058 let class_name = Option.value (enclosing_classish_name parents
)
1060 let method_name = Option.value (extract_function_name
1061 md
.methodish_function_decl_header
) ~default
:"" in
1063 produce_error_for_header errors
1064 (class_constructor_has_static) header_node
1065 [node
] (SyntaxError.error2009
class_name method_name) modifiers in
1067 produce_error_for_header errors
1068 (class_destructor_cannot_be_static)
1070 (SyntaxError.class_destructor_cannot_be_static class_name method_name) modifiers in
1072 produce_error_for_header errors async_magic_method header_node [node
]
1073 (SyntaxError.async_magic_method ~
name:method_name) modifiers in
1075 produce_error_for_header errors
1076 (clone_destruct_takes_no_arguments method_name) header_node [node
]
1077 (SyntaxError.clone_destruct_takes_no_arguments class_name method_name) modifiers in
1079 produce_error_for_header errors (clone_cannot_be_static) header_node [node
]
1080 (SyntaxError.clone_cannot_be_static class_name method_name) modifiers in
1082 produce_error errors declaration_multiple_visibility node
1083 SyntaxError.error2017
modifiers in
1085 produce_error errors methodish_duplicate_modifier node
1086 SyntaxError.error2013
modifiers in
1087 let fun_semicolon = md
.methodish_semicolon
in
1089 produce_error errors
1090 (methodish_non_abstract_without_body_not_native node
) parents
1091 (SyntaxError.error2015
class_name method_name) fun_semicolon in
1093 produce_error errors
1094 methodish_abstract_conflict_with_private
1095 node
(SyntaxError.error2016
class_name method_name) modifiers in
1097 produce_error errors
1098 methodish_abstract_conflict_with_final
1099 node
(SyntaxError.error2019
class_name method_name) modifiers in
1101 let async_annotation = Option.value (extract_async_node node
)
1103 produce_error errors
1104 (is_abstract_and_async_method node
) parents
1105 SyntaxError.error2046
async_annotation in
1107 if is_typechecker env
1108 then produce_error errors
1109 contains_async_not_last
1110 modifiers SyntaxError.async_not_last
modifiers
1113 special_method_param_errors
1114 md
.methodish_function_decl_header parents
errors in
1118 let is_hashbang text =
1119 match Syntax.extract_text
text with
1122 let r = Str.regexp
"^#!.*\n" in
1123 let count = List.length
@@ String_utils.split_on_newlines
text in
1124 count = 1 && Str.string_match
r text 0 && Str.matched_string
text = text
1127 let is_in_namespace parents
=
1128 Hh_core.List.exists parents ~f
:(fun node
->
1129 match syntax node
with
1130 | NamespaceDeclaration
{namespace_name
; _}
1131 when not
@@ is_missing namespace_name
&& text namespace_name
<> "" -> true
1134 let class_has_a_construct_method parents
=
1135 match first_parent_classish_node TokenKind.Class parents
with
1136 | Some
({ syntax
= ClassishDeclaration
1138 { syntax
= ClassishBody
1139 { classish_body_elements
= methods
; _}; _}; _}; _}) ->
1140 let methods = syntax_to_list_no_separators methods in
1141 Hh_core.List.exists
methods ~f
:(function
1142 { syntax
= MethodishDeclaration
1143 { methodish_function_decl_header
=
1144 { syntax
= FunctionDeclarationHeader
1145 { function_name
; _}; _}; _}; _} ->
1146 String.lowercase_ascii
@@ text function_name
= SN.Members.__construct
1150 let is_in_construct_method parents
=
1151 match first_parent_function_name parents
, first_parent_class_name parents
with
1152 | _ when is_immediately_in_lambda parents
-> false
1154 (* Function name is __construct *)
1155 | Some
s, _ when String.lowercase_ascii
s = SN.Members.__construct
-> true
1156 (* Function name is same as class name *)
1157 | Some s1
, Some s2
->
1158 not
@@ is_in_namespace parents
&&
1159 not
@@ class_has_a_construct_method parents
&&
1160 String.lowercase_ascii s1
= String.lowercase_ascii s2
1164 (* If a variadic parameter has a default value, return it *)
1165 let variadic_param_with_default_value params =
1166 Option.filter
(variadic_param params) ~f
:is_parameter_with_default_value
1168 (* If a variadic parameter is marked inout, return it *)
1169 let variadic_param_with_callconv params =
1170 Option.filter
(variadic_param params) ~f
:is_parameter_with_callconv
1172 (* If an inout parameter has a default, return the default *)
1173 let param_with_callconv_has_default node
=
1174 match syntax node
with
1175 | ParameterDeclaration
{ parameter_default_value
; _ } when
1176 is_parameter_with_callconv node
&&
1177 is_parameter_with_default_value node
-> Some parameter_default_value
1180 (* If an inout parameter is passed by reference, return it *)
1181 let param_with_callconv_is_byref node
=
1182 match syntax node
with
1183 | ParameterDeclaration
{ parameter_name
; _ } when
1184 is_parameter_with_callconv node
&&
1185 is_byref_parameter_variable parameter_name
-> Some node
1188 let params_errors _env
params _namespace_name
names errors =
1190 produce_error_from_check errors ends_with_variadic_comma
1191 params SyntaxError.error2022
in
1193 produce_error_from_check errors misplaced_variadic_param
1194 params SyntaxError.error2021
in
1196 produce_error_from_check errors variadic_param_with_default_value
1197 params SyntaxError.error2065
in
1199 produce_error_from_check errors variadic_param_with_callconv
1200 params SyntaxError.error2073
in
1201 let param_list = syntax_to_list_no_separators params in
1202 let has_inout_param, has_reference_param
, has_inout_and_ref_param
=
1203 Hh_core.List.fold_right
param_list ~init
:(false, false, false)
1204 ~f
:begin fun p
(b1
, b2
, b3
) ->
1205 let is_inout = is_parameter_with_callconv p
in
1206 let is_ref = is_param_by_ref p
in
1207 b1
|| is_inout, b2
|| is_ref, b3
|| (is_inout && is_ref)
1210 let errors = if has_inout_param && has_reference_param
then
1211 let error_type = if has_inout_and_ref_param
then
1212 SyntaxError.ParseError
else SyntaxError.RuntimeError
in
1213 make_error_from_node ~
error_type
1214 params SyntaxError.fn_with_inout_and_ref_params
:: errors
1219 let decoration_errors node
errors =
1220 let errors = produce_error errors is_double_variadic node
SyntaxError.double_variadic node
in
1221 let errors = produce_error errors is_double_reference node
SyntaxError.double_reference node
in
1224 let parameter_errors env node parents namespace_name
names errors =
1225 match syntax node
with
1226 | ParameterDeclaration p
->
1228 let callconv_text = Option.value (extract_callconv_node node
) ~default
:node
1231 produce_error_from_check errors param_with_callconv_has_default
1232 node
(SyntaxError.error2074
callconv_text) in
1234 produce_error_from_check errors param_with_callconv_is_byref
1235 node
(SyntaxError.error2075
callconv_text) in
1237 check_type_hint env p
.parameter_type
names errors in
1238 let errors = if is_parameter_with_callconv node
then
1240 let errors = if is_inside_async_method parents
then
1241 make_error_from_node ~
error_type:SyntaxError.RuntimeError
1242 node
SyntaxError.inout_param_in_async
:: errors
1245 if is_in_construct_method parents
then
1246 make_error_from_node ~
error_type:SyntaxError.RuntimeError
1247 node
SyntaxError.inout_param_in_construct
:: errors
1249 let errors = if first_parent_function_attributes_contains
1250 parents
SN.UserAttributes.uaMemoize
&&
1251 not
@@ is_immediately_in_lambda parents
then
1252 make_error_from_node ~
error_type:SyntaxError.RuntimeError
1253 node
SyntaxError.memoize_with_inout
:: errors
1259 if not
(is_hack env
) &&
1260 is_variadic_expression p
.parameter_name
&&
1261 not
(is_missing p
.parameter_type
) then
1262 (* Strip & and ..., reference will always come before variadic *)
1263 let name = String_utils.lstrip
(text p
.parameter_name
) "&" in
1264 let name = String_utils.lstrip
name "..." in
1265 let type_ = text p
.parameter_type
in
1266 make_error_from_node node
1267 (SyntaxError.variadic_param_with_type_in_php
name type_) :: errors
1270 if is_reference_variadic p
.parameter_name
then
1271 make_error_from_node node
SyntaxError.variadic_reference
:: errors
1274 | FunctionDeclarationHeader
{ function_parameter_list
= params; _ }
1275 | AnonymousFunction
{ anonymous_parameters
= params; _ }
1276 | ClosureTypeSpecifier
{ closure_parameter_list
= params; _ } ->
1277 params_errors env
params namespace_name
names errors
1279 { lambda_signature
= {syntax
= LambdaSignature
{ lambda_parameters
; _ }; _}
1281 } -> params_errors env lambda_parameters namespace_name
names errors
1282 | DecoratedExpression
_ -> names, decoration_errors node
errors
1283 | _ -> names, errors
1286 let redeclaration_errors env node parents namespace_name
names errors =
1287 match syntax node
with
1288 | FunctionDeclarationHeader f
when not
(is_missing f
.function_name
)->
1289 begin match parents
with
1290 | { syntax
= FunctionDeclaration
_; _}
1291 :: _ :: {syntax
= NamespaceBody
_; _} :: _
1292 | [{ syntax
= FunctionDeclaration
_; _ }; _; _]
1293 | { syntax
= MethodishDeclaration
_; _ } :: _ ->
1294 let function_name = text f
.function_name in
1295 let location = make_location_of_node f
.function_name in
1296 let is_method = match parents
with
1297 | { syntax
= MethodishDeclaration
_; _ } :: _ -> true
1300 let def = make_first_use_or_def ~
is_method
1301 ~kind
:Name_def
location namespace_name
function_name in
1303 match strmap_get function_name names.t_functions
with
1304 | Some
{ f_location
= { start_offset; _}; f_kind
= Name_def
; f_global
; _ }
1305 when f_global
= def.f_global
->
1306 let text = SyntaxTree.text env
.syntax_tree
in
1308 Full_fidelity_source_text.offset_to_position
text start_offset in
1310 Relative_path.to_absolute
@@
1311 Full_fidelity_source_text.file_path
text in
1312 let loc = path ^
":" ^ string_of_int
line in
1313 let err, error_type =
1314 match first_parent_class_name parents
with
1316 SyntaxError.redeclaration_of_function ~
name:function_name ~
loc,
1317 SyntaxError.RuntimeError
1318 | Some
class_name ->
1319 let full_name = class_name ^
"::" ^
function_name in
1320 SyntaxError.redeclaration_of_method ~
name:full_name,
1321 SyntaxError.ParseError
1323 make_error_from_node ~
error_type node
err :: errors
1327 t_functions
= strmap_add function_name def names.t_functions
}, errors
1328 | _ -> names, errors
1330 | _ -> names, errors
1332 let is_foreach_in_for for_initializer
=
1333 match syntax_node_to_list for_initializer
with
1334 | ( { syntax
= ListItem
{ list_item
= item
; _ }; _ } :: _) ->
1335 is_as_expression item
1338 let statement_errors _env node parents
errors =
1339 let result = match syntax node
with
1340 | TryStatement
{ try_catch_clauses
; try_finally_clause
; _ }
1341 when (is_missing try_catch_clauses
) && (is_missing try_finally_clause
) ->
1342 Some
(node
, SyntaxError.error2007
)
1343 | UsingStatementFunctionScoped
_
1344 when not
(using_statement_function_scoped_is_legal parents
) ->
1345 Some
(node
, SyntaxError.using_st_function_scoped_top_level
)
1346 | ForStatement
{ for_initializer
; _ }
1347 when is_foreach_in_for for_initializer
->
1348 Some
(node
, SyntaxError.for_with_as_expression
)
1352 | Some
(error_node
, error_message
) ->
1353 make_error_from_node error_node error_message
:: errors
1355 let string_starts_with_int s =
1356 if String.length
s = 0 then false else
1357 try let _ = int_of_string
(String.make
1 s.[0]) in true with _ -> false
1359 let check_collection_element m error_text
errors =
1361 | PrefixUnaryExpression
1362 { prefix_unary_operator
= { syntax
= Token token
; _ }; _ }
1363 when Token.kind token
= TokenKind.Ampersand
->
1364 make_error_from_node m error_text
:: errors
1367 let check_collection_member errors m
=
1369 | ElementInitializer
{ element_key
; element_value
; _ } ->
1371 check_collection_element element_key
1372 SyntaxError.reference_not_allowed_on_key
errors in
1374 check_collection_element element_value
1375 SyntaxError.reference_not_allowed_on_value
errors in
1378 check_collection_element m
1379 SyntaxError.reference_not_allowed_on_element
errors
1381 let check_collection_members members
errors =
1382 syntax_to_list_no_separators members
1383 |> Core_list.fold_left ~init
:errors ~f
:check_collection_member
1385 let invalid_shape_initializer_name env node
errors =
1386 match syntax node
with
1387 | LiteralExpression
{ literal_expression
= expr
} ->
1389 begin match token_kind expr
with
1390 | Some
TokenKind.SingleQuotedStringLiteral
-> true
1391 (* TODO: Double quoted string are only legal
1392 * if they contain no encapsulated expressions. *)
1393 | Some
TokenKind.DoubleQuotedStringLiteral
-> true
1398 then make_error_from_node node
SyntaxError.invalid_shape_field_name
:: errors else begin
1399 let str = text expr
in
1400 if string_starts_with_int str
1401 then make_error_from_node node
SyntaxError.error2060
:: errors
1404 | ScopeResolutionExpression
_ -> errors
1405 | QualifiedName
_ ->
1406 if is_typechecker env
then
1407 make_error_from_node node
SyntaxError.invalid_shape_field_name
:: errors
1409 | Token
_ when is_name node
->
1410 if is_typechecker env
then
1411 make_error_from_node node
SyntaxError.invalid_shape_field_name
:: errors
1414 | _ -> make_error_from_node node
SyntaxError.invalid_shape_field_name
:: errors
1416 let invalid_shape_field_check env node
errors =
1417 match syntax node
with
1418 | FieldInitializer
{ field_initializer_name
; _} ->
1419 invalid_shape_initializer_name env field_initializer_name
errors
1420 | _ -> make_error_from_node node
SyntaxError.invalid_shape_field_name
:: errors
1422 let is_in_unyieldable_magic_method parents
=
1423 match first_parent_function_name parents
with
1426 let s = String.lowercase_ascii
s in
1428 | _ when s = SN.Members.__call
-> false
1429 | _ when s = SN.Members.__invoke
-> false
1430 | _ when s = String.lowercase_ascii
SN.Members.__callStatic
-> false
1431 | _ -> SSet.mem
s SN.Members.as_lowercase_set
1434 let is_in_function parents
=
1435 Hh_core.List.exists parents ~f
:begin fun node
->
1436 match syntax node
with
1437 | FunctionDeclaration
_
1438 | MethodishDeclaration
_
1439 | AnonymousFunction
_ -> true
1443 let function_call_argument_errors node
errors =
1444 match syntax node
with
1445 | DecoratedExpression
1446 { decorated_expression_decorator
= { syntax
= Token token
; _ }
1447 ; decorated_expression_expression
= expression
1448 } when Token.kind token
= TokenKind.Inout
->
1450 match syntax expression
with
1451 | BinaryExpression
_ ->
1452 Some
(true, SyntaxError.fun_arg_inout_set
)
1453 | QualifiedName
_ ->
1454 Some
(true, SyntaxError.fun_arg_inout_const
)
1455 | Token
_ when is_name expression
->
1456 Some
(true, SyntaxError.fun_arg_inout_const
)
1457 (* TODO: Maybe be more descriptive in error messages *)
1458 | ScopeResolutionExpression
_
1459 | FunctionCallExpression
_
1460 | MemberSelectionExpression
_
1461 | SafeMemberSelectionExpression
_
1462 | SubscriptExpression
1463 { subscript_receiver
= {
1465 (MemberSelectionExpression
_ | ScopeResolutionExpression
_)
1467 }; _ } -> Some
(true, SyntaxError.fun_arg_invalid_arg
)
1468 | SubscriptExpression
{ subscript_receiver
; _ }
1469 when SN.Superglobals.is_superglobal
@@ text subscript_receiver
->
1470 Some
(false, SyntaxError.fun_arg_inout_containers
)
1473 begin match result with
1475 | Some
(is_parse_error
, e) ->
1476 let error_type = if is_parse_error
then
1477 SyntaxError.ParseError
else SyntaxError.RuntimeError
in
1478 make_error_from_node ~
error_type node
e :: errors
1482 let function_call_on_xhp_name_errors node
errors =
1483 match syntax node
with
1484 | MemberSelectionExpression
{ member_name
= name; _ }
1485 | SafeMemberSelectionExpression
{ safe_member_name
= name; _ } ->
1486 begin match syntax
name with
1487 | Token token
when Token.kind token
= TokenKind.XHPClassName
->
1489 make_error_from_node node
SyntaxError.method_calls_on_xhp_attributes
in
1495 let no_async_before_lambda_body env body_node
errors =
1496 match syntax body_node
with
1497 | AwaitableCreationExpression
_ when not env
.codegen
->
1498 (make_error_from_node body_node
SyntaxError.no_async_before_lambda_body)
1502 let no_memoize_attribute_on_lambda node
errors =
1503 match syntax node
with
1504 | AttributeSpecification
{ attribute_specification_attributes
= attrs; _ } ->
1505 Core_list.fold
(syntax_node_to_list
attrs) ~init
:errors ~f
:begin fun errors n
->
1508 list_item
= ({ syntax
= Attribute
{ attribute_name
; _ }; _ } as attr
);_
1510 begin match Syntax.extract_text attribute_name
with
1511 | Some n
when n
= SN.UserAttributes.uaMemoize
->
1513 make_error_from_node attr
SyntaxError.memoize_on_lambda
in
1521 let is_assignment node
=
1522 match syntax node
with
1523 | BinaryExpression
{ binary_operator
= { syntax
= Token token
; _ }; _ } ->
1524 Token.kind token
= TokenKind.Equal
1527 let is_good_scope_resolution_qualifier node
=
1528 match syntax node
with
1529 | QualifiedName
_ -> true
1531 let open TokenKind
in
1532 (match Token.kind token
with
1533 | XHPClassName
| Name
| Self
| Parent
| Static
-> true
1538 let new_variable_errors node
=
1539 let rec helper node ~inside_scope_resolution
=
1540 match syntax node
with
1541 | SimpleTypeSpecifier
_ -> []
1542 | VariableExpression
_ -> []
1543 | GenericTypeSpecifier
_ -> []
1544 | PipeVariableExpression
_ -> []
1545 | SubscriptExpression
{ subscript_index
= { syntax
= Missing
; _ }; _ } ->
1546 [ make_error_from_node node
SyntaxError.instanceof_missing_subscript_index
]
1547 | SubscriptExpression
{ subscript_receiver
; _ } ->
1548 helper subscript_receiver ~inside_scope_resolution
1549 | MemberSelectionExpression
{ member_object
; _ } ->
1550 if inside_scope_resolution
1552 make_error_from_node node
SyntaxError.instanceof_memberselection_inside_scoperesolution
1554 else helper member_object ~inside_scope_resolution
1555 | ScopeResolutionExpression
1557 scope_resolution_qualifier
;
1558 scope_resolution_name
= { syntax
= Token
name; _ };
1560 } when is_good_scope_resolution_qualifier scope_resolution_qualifier
1561 && Token.kind
name = TokenKind.Variable
-> []
1562 | ScopeResolutionExpression
1564 scope_resolution_qualifier
;
1565 scope_resolution_name
= { syntax
= Token
name; _ };
1567 } when Token.kind
name = TokenKind.Variable
->
1568 helper scope_resolution_qualifier ~inside_scope_resolution
:true
1569 | ScopeResolutionExpression
_ ->
1570 [ make_error_from_node node
SyntaxError.instanceof_invalid_scope_resolution
]
1573 let error_msg = SyntaxError.instanceof_unknown_node
(SyntaxKind.to_string
@@ kind node
) in
1574 [ make_error_from_node node
error_msg ]
1576 helper node ~inside_scope_resolution
:false
1578 let class_type_designator_errors node
=
1579 if is_good_scope_resolution_qualifier node
then [] else
1580 match syntax node
with
1581 | ParenthesizedExpression
1583 parenthesized_expression_expression
= {
1584 syntax
= PrefixUnaryExpression
{ prefix_unary_operator
= { syntax
= Token token
; _ }; _ };
1589 when Token.kind token
= TokenKind.Ampersand
->
1590 [make_error_from_node node
SyntaxError.instanceof_reference
]
1591 | ParenthesizedExpression
_ ->
1592 (* A parenthesized expression that evaluates to a string or object is a
1593 valid RHS for instanceof and new. *)
1595 | _ -> new_variable_errors node
1597 let expression_errors env namespace_name node parents
errors =
1598 let is_decimal_or_hexadecimal_literal token
=
1599 match Token.kind token
with
1600 | TokenKind.DecimalLiteral
| TokenKind.HexadecimalLiteral
-> true
1603 match syntax node
with
1604 (* It is ambiguous what `instanceof (A)` means: either instanceof a type A
1605 * or instanceof a type whose name is what the constant A evaluates to.
1606 * We therefore simply disallow this. *)
1607 | InstanceofExpression
1608 { instanceof_right_operand
=
1609 { syntax
= ParenthesizedExpression
1610 { parenthesized_expression_expression
=
1611 { syntax
= Token
_; _ } as in_paren
1614 ; _ } when not env
.codegen
->
1615 let in_paren = text in_paren in
1616 make_error_from_node node
(SyntaxError.instanceof_paren
in_paren) :: errors
1617 (* We parse the right hand side of `new` and `instanceof` as a generic
1618 expression, but PHP (and therefore Hack) only allow a certain subset of
1619 expressions, so we should verify here that the expression we parsed is in
1621 Refer: https://github.com/php/php-langspec/blob/master/spec/10-expressions.md#instanceof-operator*)
1622 | ConstructorCall ctr_call
->
1623 let typechecker_errors =
1624 if is_typechecker env
then
1625 if is_missing ctr_call
.constructor_call_left_paren
||
1626 is_missing ctr_call
.constructor_call_right_paren
1628 let node = ctr_call
.constructor_call_type
in
1629 let constructor_name = text ctr_call
.constructor_call_type
in
1630 [make_error_from_node node (SyntaxError.error2038
constructor_name)]
1634 let designator_errors = class_type_designator_errors ctr_call
.constructor_call_type
in
1635 typechecker_errors @ designator_errors @ errors
1636 | InstanceofExpression
{ instanceof_right_operand
= operand
; _ } ->
1637 (class_type_designator_errors operand
) @ errors
1638 | LiteralExpression
{ literal_expression
= {syntax
= Token token
; _} as e ; _}
1639 when env
.is_hh_file
&& is_decimal_or_hexadecimal_literal token
->
1640 let text = text e in
1641 begin try ignore
(Int64.of_string
text); errors
1644 if Token.kind token
= TokenKind.DecimalLiteral
1645 then SyntaxError.error2071
text
1646 else SyntaxError.error2072
text in
1647 make_error_from_node node error_text :: errors
1649 | SafeMemberSelectionExpression
_ when not
(is_hack env
) ->
1650 make_error_from_node node SyntaxError.error2069
:: errors
1651 | SubscriptExpression
{ subscript_left_bracket
; _}
1652 when (is_typechecker env
)
1653 && is_left_brace subscript_left_bracket
->
1654 make_error_from_node node SyntaxError.error2020
:: errors
1655 | HaltCompilerExpression
{ halt_compiler_argument_list
= args
; _ } ->
1657 if Core_list.is_empty
(syntax_to_list_no_separators args
) then errors
1658 else make_error_from_node node SyntaxError.no_args_in_halt_compiler
:: errors in
1661 (* expression statement -> syntax list -> script *)
1662 | [_; _; _] -> errors
1663 | _ -> make_error_from_node node SyntaxError.halt_compiler_top_level_only
:: errors in
1665 | FunctionCallExpression
{
1666 function_call_argument_list
= arg_list
;
1667 function_call_receiver
; _
1670 match misplaced_variadic_arg arg_list
with
1672 make_error_from_node h
SyntaxError.error2033
:: errors
1675 let arg_list = syntax_to_list_no_separators arg_list in
1676 let errors = Hh_core.List.fold_right
arg_list ~init
:errors
1677 ~f
:(fun p
acc -> function_call_argument_errors p
acc)
1680 function_call_on_xhp_name_errors function_call_receiver
errors in
1682 | ListExpression
{ list_members
; _ }
1683 when is_hhvm_compat env
->
1684 begin match parents
with
1685 | p1
:: _ when is_value_of_foreach node p1
->
1686 begin match list_members
.syntax
with
1688 make_error_from_node ~
error_type:SyntaxError.RuntimeError
node
1689 SyntaxError.error2077
:: errors
1694 | ShapeExpression
{ shape_expression_fields
; _} ->
1695 List.fold_right
(invalid_shape_field_check env
)
1696 (syntax_to_list_no_separators shape_expression_fields
) errors
1697 | DecoratedExpression
1698 { decorated_expression_decorator
= decorator
1699 ; decorated_expression_expression
=
1700 { syntax
= PrefixUnaryExpression
{ prefix_unary_operator
= operator
; _ }
1703 when is_inout decorator
&& is_ampersand operator
->
1704 make_error_from_node node SyntaxError.error2076
:: errors
1705 | VectorIntrinsicExpression
{ vector_intrinsic_members
= m
; _ }
1706 | DictionaryIntrinsicExpression
{ dictionary_intrinsic_members
= m
; _ }
1707 | KeysetIntrinsicExpression
{ keyset_intrinsic_members
= m
; _ } ->
1708 if not
(is_hack env
) then
1709 (* In php, vec[0] would be a subscript, where vec would be a constant *)
1710 match syntax_to_list_no_separators m
with
1711 | _ :: _ :: _ -> (* 2 elements or more *)
1712 make_error_from_node node SyntaxError.list_as_subscript
:: errors
1714 else check_collection_members m
errors
1715 | VarrayIntrinsicExpression
{ varray_intrinsic_members
= m
; _ }
1716 | DarrayIntrinsicExpression
{ darray_intrinsic_members
= m
; _ } ->
1718 if not
(is_hack env
)
1719 then make_error_from_node node SyntaxError.vdarray_in_php
:: errors
1721 check_collection_members m
errors
1722 | YieldFromExpression
_
1723 | YieldExpression
_ ->
1725 if is_in_unyieldable_magic_method parents
then
1726 make_error_from_node node SyntaxError.yield_in_magic_methods
:: errors
1729 if not
(is_in_function parents
) then
1730 make_error_from_node node SyntaxError.yield_outside_function
:: errors
1733 if has_inout_params parents
then
1735 if is_inside_async_method parents
1736 then SyntaxError.inout_param_in_async_generator
1737 else SyntaxError.inout_param_in_generator
in
1738 make_error_from_node ~
error_type:SyntaxError.RuntimeError
node e :: errors
1741 | ScopeResolutionExpression
1742 { scope_resolution_qualifier
= qualifier
1743 ; scope_resolution_name
= name
1745 let is_dynamic_name, is_self_or_parent
, is_valid
=
1746 (* PHP langspec allows string literals, variables
1747 qualified names, static, self and parent as valid qualifiers *)
1748 (* We do not allow string literals in hack *)
1749 match syntax qualifier
, token_kind qualifier
with
1750 | LiteralExpression
_, _ ->
1751 false, false, not
(is_typechecker env
)
1752 | QualifiedName
_, _ -> false, false, true
1753 | _, Some
TokenKind.Name
1754 | _, Some
TokenKind.XHPClassName
1755 | _, Some
TokenKind.Static
-> false, false, true
1756 | _, Some
TokenKind.Self
1757 | _, Some
TokenKind.Parent
-> false, true, true
1759 | PrefixUnaryExpression
{
1760 prefix_unary_operator
= op
; _
1761 }, _ when token_kind op
= Some
TokenKind.Dollar
->
1763 | PipeVariableExpression
_, _
1764 | VariableExpression
_, _
1765 | SimpleTypeSpecifier
_, _
1766 | GenericTypeSpecifier
_, _ -> true, false, true
1767 | _ -> true, false, not
(is_typechecker env
)
1769 let errors = if not is_valid
then
1770 make_error_from_node
1771 node SyntaxError.invalid_scope_resolution_qualifier
:: errors
1773 let is_name_class = String.lowercase_ascii
@@ text name = "class" in
1774 let errors = if is_dynamic_name && is_name_class then
1775 make_error_from_node
1776 node SyntaxError.coloncolonclass_on_dynamic
:: errors
1778 let text_name = text qualifier
in
1779 let is_name_namespace = String.lowercase_ascii
@@ text_name = "namespace" in
1780 let errors = if is_name_namespace
1781 then make_error_from_node ~
error_type:SyntaxError.ParseError
1782 node (SyntaxError.namespace_not_a_classname
)::errors
1784 let errors = if is_self_or_parent
&& is_name_class &&
1785 not
@@ is_in_active_class_scope parents
1786 then make_error_from_node ~
error_type:SyntaxError.RuntimeError
1787 node (SyntaxError.self_or_parent_colon_colon_class_outside_of_class
1788 @@ text qualifier
) :: errors
1791 | PrefixUnaryExpression
{ prefix_unary_operator
; prefix_unary_operand
}
1792 when token_kind prefix_unary_operator
= Some
TokenKind.Ampersand
->
1793 begin match syntax prefix_unary_operand
with
1794 | ScopeResolutionExpression
{ scope_resolution_name
; _}
1795 when token_kind scope_resolution_name
= Some
TokenKind.Name
->
1796 make_error_from_node node
1797 SyntaxError.reference_to_static_scope_resolution
:: errors
1798 | PrefixUnaryExpression
{ prefix_unary_operator
; _ }
1799 when token_kind prefix_unary_operator
<> Some
TokenKind.Dollar
->
1800 make_error_from_node node SyntaxError.nested_unary_reference
:: errors
1803 | PrefixUnaryExpression
{ prefix_unary_operator
; prefix_unary_operand
}
1804 when token_kind prefix_unary_operator
= Some
TokenKind.Dollar
->
1805 let original_node = node in
1806 let rec check_prefix_unary_dollar node =
1807 match syntax
node with
1808 | PrefixUnaryExpression
{ prefix_unary_operator
; prefix_unary_operand
}
1809 when token_kind prefix_unary_operator
= Some
TokenKind.Dollar
->
1810 check_prefix_unary_dollar prefix_unary_operand
1811 | BracedExpression
_
1812 | SubscriptExpression
_
1813 | VariableExpression
_ -> errors (* these ones are valid *)
1814 | LiteralExpression
_
1815 | PipeVariableExpression
_ -> errors (* these ones get caught later *)
1816 | _ -> make_error_from_node original_node SyntaxError.dollar_unary
:: errors
1818 check_prefix_unary_dollar prefix_unary_operand
1819 (* TODO(T21285960): Remove this bug-port, stemming from T22184312 *)
1820 | LambdaExpression
{ lambda_async
; lambda_coroutine
; lambda_signature
; _ }
1821 when is_hhvm_compat env
1822 && not
(is_missing lambda_async
)
1823 && trailing_width lambda_async
= 0
1824 && full_width lambda_coroutine
= 0
1825 && leading_width lambda_signature
= 0
1827 make_error_from_node node
1828 (SyntaxError.error1057
"==>") :: errors
1829 (* End of bug-port *)
1831 { is_right_operand
= hint
1835 { as_right_operand
= hint
1838 let n = match syntax
node with IsExpression
_ -> "is" | _ -> "as" in
1839 begin match syntax hint
with
1840 | ClosureTypeSpecifier
_ when env
.hhvm_compat_mode
<> NoCompat
->
1841 make_error_from_node hint
1842 (SyntaxError.invalid_is_as_expression_hint
n "Callable") :: errors
1843 | SoftTypeSpecifier
_ ->
1844 make_error_from_node hint
1845 (SyntaxError.invalid_is_as_expression_hint
n "Soft") :: errors
1848 | ConditionalExpression
1849 { conditional_consequence
= cons
1851 when is_missing cons
1852 && is_typechecker env
->
1853 make_error_from_node node SyntaxError.elvis_operator_space
:: errors
1855 { lambda_attribute_spec
= s
1856 ; lambda_body
= body
1858 let errors = no_memoize_attribute_on_lambda s errors in
1859 no_async_before_lambda_body env
body errors
1860 | AnonymousFunction
{ anonymous_attribute_spec
= s; _ }
1861 | Php7AnonymousFunction
{ php7_anonymous_attribute_spec
= s; _ }
1862 | AwaitableCreationExpression
{ awaitable_attribute_spec
= s; _ }
1863 -> no_memoize_attribute_on_lambda s errors
1864 | CollectionLiteralExpression
1865 { collection_literal_name
= n
1866 ; collection_literal_initializers
= initializers
1868 let is_standard_collection lc_name
=
1869 lc_name
= "pair" || lc_name
= "vector" || lc_name
= "map" ||
1870 lc_name
= "set" || lc_name
= "immvector" || lc_name
= "immmap" ||
1871 lc_name
= "immset" in
1872 let is_qualified_std_collection l
r =
1873 token_kind l
= Some
TokenKind.Name
&&
1874 token_kind r = Some
TokenKind.Name
&&
1875 String.lowercase_ascii
(text l
) = "hh" &&
1876 is_standard_collection (String.lowercase_ascii
(text r)) in
1879 (* non-qualified name *)
1880 | SimpleTypeSpecifier
{ simple_type_specifier
= ({
1883 | GenericTypeSpecifier
{ generic_class_type
= ({
1886 when Token.kind t
= TokenKind.Name
->
1887 begin match String.lowercase_ascii
(text n) with
1888 | "dict" | "vec" | "keyset" -> `InvalidBraceKind
1889 | n -> if is_standard_collection n then `ValidClass
n else `InvalidClass
1891 (* qualified name *)
1892 | SimpleTypeSpecifier
{ simple_type_specifier
= {
1893 syntax
= QualifiedName
{ qualified_name_parts
= parts
; _ }; _
1895 | GenericTypeSpecifier
{ generic_class_type
= {
1896 syntax
= QualifiedName
{ qualified_name_parts
= parts
; _ }; _
1898 begin match syntax_to_list false parts
with
1899 (* HH\Vector in global namespace *)
1901 when namespace_name
= global_namespace_name &&
1902 is_qualified_std_collection l
r ->
1903 `ValidClass
(String.lowercase_ascii
(text r))
1905 | [{ syntax
= Missing
; _}; l
; r]
1906 when is_qualified_std_collection l
r ->
1907 `ValidClass
(String.lowercase_ascii
(text r))
1908 | _ -> `InvalidClass
1910 | _ -> `InvalidClass
in
1911 let num_initializers =
1912 List.length
(syntax_to_list_no_separators initializers
) in
1913 begin match status with
1914 | `ValidClass
"pair" when num_initializers <> 2 ->
1916 if num_initializers = 0
1917 then SyntaxError.pair_initializer_needed
1918 else SyntaxError.pair_initializer_arity
1921 make_error_from_node node msg ~
error_type:SyntaxError.RuntimeError
in
1923 | `ValidClass
_ -> errors
1924 | `InvalidBraceKind
->
1926 make_error_from_node node SyntaxError.invalid_brace_kind_in_collection_initializer
in
1930 make_error_from_node node SyntaxError.invalid_class_in_collection_initializer
in
1933 | DecoratedExpression
{ decorated_expression_decorator
= op
; _ }
1934 | PrefixUnaryExpression
{ prefix_unary_operator
= op
; _ }
1935 when token_kind op
= Some
TokenKind.Await
->
1936 begin match parents
with
1937 | si
:: le
:: _ when is_simple_initializer si
&& is_let_statement le
->
1939 | le
:: _ when is_lambda_expression le
-> errors
1940 | rs
:: _ when is_return_statement rs
-> errors
1941 | es
:: _ when is_expression_statement es
-> errors
1943 when is_binary_expression be
&& is_assignment be
&&
1944 is_expression_statement es
-> errors
1945 | li
:: l
:: us
:: _
1946 when is_list_item li
&& is_list l
&&
1947 (is_using_statement_block_scoped us
||
1948 is_using_statement_function_scoped us
) -> errors
1949 | be
:: li
:: l
:: us
:: _
1950 when is_binary_expression be
&& is_assignment be
&&
1951 is_list_item li
&& is_list l
&&
1952 (is_using_statement_block_scoped us
||
1953 is_using_statement_function_scoped us
) -> errors
1955 when is_binary_expression be
&& is_assignment be
&&
1956 (is_using_statement_block_scoped us
||
1957 is_using_statement_function_scoped us
) -> errors
1959 when (is_using_statement_block_scoped us
||
1960 is_using_statement_function_scoped us
) -> errors
1961 | _ -> make_error_from_node node SyntaxError.invalid_await_use
:: errors
1963 | _ -> errors (* Other kinds of expressions currently produce no expr errors. *)
1965 let check_repeated_properties namespace_name
class_name (errors, p_names
) prop
=
1966 let full_name = combine_names namespace_name
class_name in
1967 match syntax prop
with
1968 | PropertyDeclaration
{ property_declarators
; _} ->
1969 let declarators = syntax_to_list_no_separators property_declarators
in
1970 Hh_core.List.fold
declarators ~init
:(errors, p_names
)
1971 ~f
:begin fun (errors, p_names
) prop
->
1972 match syntax prop
with
1973 | PropertyDeclarator
{property_name
; _} ->
1974 let prop_name = text property_name
in
1975 (* If the property name is empty, then there was an earlier
1976 parsing error that should supercede this one. *)
1977 if prop_name = "" then errors, p_names
else
1978 let errors, p_names
=
1979 if SSet.mem
prop_name p_names
1980 then make_error_from_node prop
1981 (SyntaxError.redeclaration_error
1982 ((Utils.strip_ns
full_name) ^
"::" ^
prop_name)) :: errors, p_names
1983 else errors, SSet.add
prop_name p_names
in
1985 | _ -> errors, p_names
1987 | _ -> (errors, p_names
)
1988 let require_errors _env
node parents trait_use_clauses
errors =
1989 match syntax
node with
1990 | RequireClause p
->
1991 let name = text p
.require_name
in
1992 let req_kind = token_kind p
.require_kind
in
1993 let trait_use_clauses, errors =
1994 match strmap_get name trait_use_clauses, req_kind with
1995 | None
, Some tk
-> strmap_add name tk
trait_use_clauses, errors
1996 | Some tk1
, Some tk2
when tk1
= tk2
-> (* duplicate, it is okay *)
1997 trait_use_clauses, errors
1998 | _ -> (* Conflicting entry *)
2000 make_error_from_node node
2001 (SyntaxError.conflicting_trait_require_clauses ~
name) :: errors
2004 match (containing_classish_kind parents
, req_kind) with
2005 | (Some
TokenKind.Interface
, Some
TokenKind.Implements
)
2006 | (Some
TokenKind.Class
, Some
TokenKind.Implements
) ->
2007 make_error_from_node node SyntaxError.error2030
:: errors
2010 trait_use_clauses, errors
2011 | _ -> trait_use_clauses, errors
2013 let check_type_name syntax_tree
name namespace_name name_text
location names errors =
2014 begin match strmap_get name_text
names.t_classes
with
2015 | Some
{ f_location
= location; f_kind
; f_name
; _ }
2016 when combine_names namespace_name name_text
<> f_name
&& f_kind
<> Name_def
->
2017 let text = SyntaxTree.text syntax_tree
in
2019 Full_fidelity_source_text.offset_to_position
2020 text location.start_offset in
2021 let long_name_text = combine_names namespace_name name_text
in
2023 make_name_already_used_error name long_name_text name_text
location
2025 | Name_implicit_use
-> SyntaxError.declared_name_is_already_in_use_implicit_hh ~
line_num
2026 | Name_use
-> SyntaxError.declared_name_is_already_in_use ~
line_num
2027 | Name_def
-> SyntaxError.type_name_is_already_in_use
) in
2028 names, error :: errors
2031 make_first_use_or_def ~kind
:Name_def
location namespace_name name_text
in
2034 t_classes
= strmap_add name_text
def names.t_classes
} in
2038 let classish_errors env
node _parents namespace_name
names errors =
2039 match syntax
node with
2040 | ClassishDeclaration cd
->
2041 (* Given a ClassishDeclaration node, test whether or not it's a trait
2042 * invoking the 'extends' keyword. *)
2043 let classish_invalid_extends_keyword _ =
2044 (* Invalid if uses 'extends' and is a trait. *)
2045 token_kind cd
.classish_extends_keyword
= Some
TokenKind.Extends
&&
2046 token_kind cd
.classish_keyword
= Some
TokenKind.Trait
in
2048 (* Given a sealed ClassishDeclaration node, test whether all the params
2049 * are classnames. *)
2050 let classish_sealed_arg_not_classname _env
_ =
2051 match cd
.classish_attribute
.syntax
with
2052 | AttributeSpecification
{ attribute_specification_attributes
= attrs; _ } ->
2053 let attrs = syntax_to_list_no_separators attrs in
2054 Hh_core.List.exists
attrs (fun e ->
2056 | Attribute
{attribute_values
; attribute_name
; _ } ->
2057 text attribute_name
= SN.UserAttributes.uaSealed
&&
2058 Hh_core.List.exists
(syntax_to_list_no_separators attribute_values
) (fun e ->
2060 | ScopeResolutionExpression
{scope_resolution_name
; _ } ->
2061 text scope_resolution_name
<> "class"
2066 let classish_is_sealed =
2067 match cd
.classish_attribute
.syntax
with
2068 | AttributeSpecification
{ attribute_specification_attributes
= attrs; _ } ->
2069 let attrs = syntax_to_list_no_separators attrs in
2070 Hh_core.List.exists
attrs (fun e ->
2072 | Attribute
{attribute_name
; _ } ->
2073 text attribute_name
= SN.UserAttributes.uaSealed
2077 (* Given a ClassishDeclaration node, test whether or not length of
2078 * extends_list is appropriate for the classish_keyword. *)
2079 let classish_invalid_extends_list env
_ =
2080 (* Invalid if is a class and has list of length greater than one. *)
2081 (is_typechecker env
) &&
2082 token_kind cd
.classish_keyword
= Some
TokenKind.Class
&&
2083 token_kind cd
.classish_extends_keyword
= Some
TokenKind.Extends
&&
2084 match syntax_to_list_no_separators cd
.classish_extends_list
with
2086 | _ -> true (* General bc empty list case is already caught by error1007 *) in
2087 let abstract_keyword =
2088 Option.value (extract_keyword is_abstract node) ~default
:node in
2089 let errors = produce_error errors
2090 (is_classish_kind_declared_abstract env
)
2091 node SyntaxError.error2042
abstract_keyword in
2092 (* Given a ClassishDeclaration node, test whether it is sealed and final. *)
2093 let classish_sealed_final _env
_ =
2094 list_contains_predicate is_final cd
.classish_modifiers
&&
2095 classish_is_sealed in
2096 let errors = produce_error errors (classish_invalid_extends_list env
) ()
2097 SyntaxError.error2037 cd
.classish_extends_list
in
2099 produce_error errors
2100 classish_duplicate_modifiers cd
.classish_modifiers
2101 SyntaxError.error2031 cd
.classish_modifiers
in
2103 produce_error errors
2104 (classish_sealed_arg_not_classname env
) ()
2105 SyntaxError.sealed_val_not_classname cd
.classish_attribute
in
2107 produce_error errors
2108 classish_invalid_extends_keyword ()
2109 SyntaxError.error2036 cd
.classish_extends_keyword
in
2111 produce_error errors
2112 (classish_sealed_final env
) ()
2113 SyntaxError.sealed_final cd
.classish_attribute
in
2115 produce_error errors
2116 (is_reserved_keyword env
) cd
.classish_name
2117 SyntaxError.reserved_keyword_as_class_name cd
.classish_name
in
2119 if is_token_kind cd
.classish_keyword
TokenKind.Interface
&&
2120 not
(is_missing cd
.classish_implements_keyword
)
2121 then make_error_from_node node
2122 SyntaxError.interface_implements
:: errors
2124 let name = text cd
.classish_name
in
2126 match syntax cd
.classish_body
with
2127 | ClassishBody
{classish_body_elements
= methods; _} ->
2128 let methods = syntax_to_list_no_separators methods in
2129 let declared_name_str =
2130 Option.value ~default
:"" (Syntax.extract_text cd
.classish_name
) in
2132 Hh_core.List.fold
methods ~f
:(check_repeated_properties namespace_name
declared_name_str)
2133 ~init
:(errors, SSet.empty
) in
2134 let has_abstract_fn =
2135 Hh_core.List.exists
methods ~f
:methodish_contains_abstract in
2136 let has_private_method =
2137 Hh_core.List.exists
methods
2138 ~f
:(methodish_modifier_contains_helper is_private
) in
2139 let has_multiple_xhp_category_decls =
2140 let cats = Hh_core.List.filter
methods ~f
:(fun m
->
2142 | XHPCategoryDeclaration
_ -> true
2148 if has_abstract_fn &&
2149 is_token_kind cd
.classish_keyword
TokenKind.Class
&&
2150 not
(list_contains_predicate is_abstract cd
.classish_modifiers
)
2151 then make_error_from_node node
2152 (SyntaxError.class_with_abstract_method
name) :: errors
2155 if has_private_method &&
2156 is_token_kind cd
.classish_keyword
TokenKind.Interface
2157 then make_error_from_node node
2158 SyntaxError.interface_has_private_method
:: errors
2161 if has_multiple_xhp_category_decls
2162 then make_error_from_node node
2163 SyntaxError.xhp_class_multiple_category_decls
:: errors
2168 match token_kind cd
.classish_keyword
with
2169 | Some
TokenKind.Class
| Some
TokenKind.Trait
2170 when not
(is_missing cd
.classish_name
)->
2171 let location = make_location_of_node cd
.classish_name
in
2172 check_type_name env
.syntax_tree cd
.classish_name namespace_name
name location names errors
2176 | _ -> names, errors
2178 let class_element_errors env
node parents
errors =
2179 match syntax
node with
2180 | ConstDeclaration
_ when is_inside_trait parents
->
2181 make_error_from_node node SyntaxError.const_in_trait
:: errors
2182 | ConstDeclaration
{ const_visibility
; _ }
2183 when not
(is_missing const_visibility
) && env
.is_hh_file
&& not env
.codegen
->
2184 make_error_from_node node SyntaxError.const_visibility
:: errors
2188 let alias_errors env
node namespace_name
names errors =
2189 match syntax
node with
2190 | AliasDeclaration ad
->
2192 if token_kind ad
.alias_keyword
= Some
TokenKind.Type
&&
2193 not
(is_missing ad
.alias_constraint
)
2194 then make_error_from_node ad
.alias_keyword
SyntaxError.error2034
:: errors
2196 if is_missing ad
.alias_name
then names,errors
2198 let name = text ad
.alias_name
in
2199 let location = make_location_of_node ad
.alias_name
in
2200 check_type_name env
.syntax_tree ad
.alias_name namespace_name
name location names errors
2201 | _ -> names, errors
2203 let is_invalid_group_use_clause kind clause
=
2204 match syntax clause
with
2205 | NamespaceUseClause
{ namespace_use_clause_kind
= clause_kind
; _ } ->
2208 begin match syntax clause_kind
with
2210 | Token token
when let k = Token.kind token
in
2211 TokenKind.(k = Function
|| k = Const
) -> false
2214 else not
(is_missing clause_kind
)
2217 let is_invalid_group_use_prefix prefix
=
2218 not
(is_namespace_prefix prefix
)
2220 let group_use_errors _env
node errors =
2221 match syntax
node with
2222 | NamespaceGroupUseDeclaration
2223 { namespace_group_use_prefix
= prefix
2224 ; namespace_group_use_clauses
= clauses
2225 ; namespace_group_use_kind
= kind
2228 let invalid_clauses = List.filter
(is_invalid_group_use_clause kind
)
2229 (syntax_to_list_no_separators clauses
) in
2230 let mapper errors clause
=
2231 make_error_from_node clause
SyntaxError.error2049
:: errors in
2232 List.fold_left
mapper errors invalid_clauses in
2233 produce_error errors is_invalid_group_use_prefix prefix
2234 SyntaxError.error2048 prefix
2237 let use_class_or_namespace_clause_errors
2238 env is_global_namespace namespace_prefix
2239 kind
(names, errors) cl
=
2241 match syntax cl
with
2242 | NamespaceUseClause
{
2243 namespace_use_name
= name;
2244 namespace_use_alias
= alias
;
2245 namespace_use_clause_kind
; _
2246 } when not
(is_missing name) ->
2247 let kind = if is_missing kind then namespace_use_clause_kind
else kind in
2248 let name_text = text name in
2249 let qualified_name =
2250 match namespace_prefix
with
2251 | None
-> combine_names global_namespace_name name_text
2252 | Some p
-> combine_names p
name_text in
2253 let short_name = get_short_name_from_qualified_name name_text (text alias
) in
2255 let do_check ?
(case_sensitive
= false) ~error_on_global_redefinition
names errors
2256 get_map update_map report_error
=
2257 (* We store the original names in the SMap of names for error messaging purposes
2258 but we check for case sensitivity specifically. *)
2259 let find_name name =
2261 then short_name = name
2262 else (String.lowercase_ascii
short_name) = String.lowercase_ascii
name in
2263 let map = get_map
names in
2264 match strmap_find_first_opt find_name map with
2265 | Some
(_, { f_location
= location; f_kind
; f_global
; _ }) ->
2266 if (f_kind
<> Name_def
2267 || (error_on_global_redefinition
&& (is_global_namespace
|| f_global
)))
2270 make_name_already_used_error name name_text
2271 short_name location report_error
in
2272 names, error :: errors
2277 make_first_use_or_def
2279 (make_location_of_node name)
2280 global_namespace_name qualified_name in
2281 update_map
names (strmap_add short_name new_use map), errors
2284 begin match syntax
kind with
2286 let open TokenKind
in
2287 (match Token.kind token
with
2289 do_check ~error_on_global_redefinition
:false names errors
2290 (fun n -> n.t_namespaces
)
2291 (fun n v
-> { n with t_namespaces
= v
})
2292 SyntaxError.namespace_name_is_already_in_use
2295 do_check ~error_on_global_redefinition
:false names errors
2296 (fun n -> n.t_classes
)
2297 (fun n v
-> { n with t_classes
= v
})
2298 SyntaxError.type_name_is_already_in_use
2301 do_check ~error_on_global_redefinition
:true names errors
2302 (fun n -> n.t_functions
)
2303 (fun n v
-> { n with t_functions
= v
})
2304 SyntaxError.function_name_is_already_in_use
2307 do_check ~case_sensitive
:true ~error_on_global_redefinition
:true names errors
2308 (fun n -> n.t_constants
)
2309 (fun n v
-> { n with t_constants
= v
})
2310 SyntaxError.const_name_is_already_in_use
2316 if name_text = "strict"
2319 if is_hack env
then SyntaxError.strict_namespace_hh
2320 else SyntaxError.strict_namespace_not_hh
in
2321 make_error_from_node name message :: errors
2325 let location = make_location_of_node name in
2326 match strmap_get short_name names.t_classes
with
2327 | Some
{ f_location
= loc; f_name
; f_kind
; _ } ->
2328 if qualified_name = f_name
&& f_kind
= Name_def
then names, errors
2331 if is_hack env
&& f_kind
<> Name_def
then
2332 let text = SyntaxTree.text env
.syntax_tree
in
2334 Full_fidelity_source_text.offset_to_position
2335 text loc.start_offset in
2336 if f_kind
= Name_implicit_use
2337 then SyntaxError.name_is_already_in_use_implicit_hh ~
line_num
2338 else SyntaxError.name_is_already_in_use_hh ~
line_num
2339 else SyntaxError.name_is_already_in_use_php
2341 let error = make_name_already_used_error
2342 name name_text short_name loc err_msg in
2343 names, error :: errors
2346 make_first_use_or_def ~
kind:Name_use
location global_namespace_name qualified_name in
2347 let t_classes = strmap_add short_name new_use names.t_classes in
2349 if strmap_mem short_name names.t_namespaces
2350 then names.t_namespaces
2351 else strmap_add short_name new_use names.t_namespaces in
2352 { names with t_classes; t_namespaces }, errors in
2361 let is_global_in_const_decl init
=
2362 match syntax init
with
2363 | SimpleInitializer
{ simple_initializer_value
; _ } ->
2364 begin match syntax simple_initializer_value
with
2365 | VariableExpression
{ variable_expression
} ->
2366 SN.Superglobals.is_superglobal
@@ text variable_expression
2371 let namespace_use_declaration_errors
2372 env
node is_global_namespace
names errors =
2373 match syntax
node with
2374 | NamespaceUseDeclaration
{
2375 namespace_use_kind
= kind;
2376 namespace_use_clauses
= clauses
; _ } ->
2378 use_class_or_namespace_clause_errors
2379 env is_global_namespace None
kind in
2380 List.fold_left
f (names, errors) (syntax_to_list_no_separators clauses
)
2381 | NamespaceGroupUseDeclaration
{
2382 namespace_group_use_kind
= kind;
2383 namespace_group_use_clauses
= clauses
;
2384 namespace_group_use_prefix
= prefix
; _ } ->
2386 use_class_or_namespace_clause_errors
2387 env is_global_namespace
(Some
(text prefix
)) kind in
2388 List.fold_left
f (names, errors) (syntax_to_list_no_separators clauses
)
2389 | _ -> names, errors
2392 let rec check_constant_expression errors node =
2393 let is_namey token
=
2394 match Token.kind token
with
2395 TokenKind.Name
-> true
2398 let is_good_scope_resolution_name node =
2399 match syntax
node with
2400 | QualifiedName
_ -> true
2402 let open TokenKind
in
2403 (match Token.kind token
with
2404 | Name
| Trait
| Extends
| Implements
| Static
2405 | Abstract
| Final
| Private
| Protected
| Public
| Or
| And
| Global
2406 | Goto
| Instanceof
| Insteadof
| Interface
| Namespace
| New
| Try
| Use
2407 | Var
| List
| Clone
| Include
| Include_once
| Throw
| Array
| Tuple
2408 | Print
| Echo
| Require
| Require_once
| Return
| Else
| Elseif
| Default
2409 | Break
| Continue
| Switch
| Yield
| Function
| If
| Finally
| For
2410 | Foreach
| Case
| Do
| While
| As
| Catch
| Empty
| Using
| Class
2411 | NullLiteral
| Super
| Where
2417 match syntax
node with
2420 | LiteralExpression
_
2422 | Token token
when is_namey token
-> errors
2423 | PrefixUnaryExpression
2424 { prefix_unary_operand
2425 ; prefix_unary_operator
= { syntax
= Token token
; _ }
2426 } when ( let open TokenKind
in
2427 match Token.kind token
with
2428 | Exclamation
| Plus
| Minus
| Tilde
-> true
2431 check_constant_expression errors prefix_unary_operand
2433 { binary_left_operand
2434 ; binary_right_operand
2435 ; binary_operator
= { syntax
= Token token
; _ }
2436 ; _ } when ( let open TokenKind
in
2437 match Token.kind token
with
2438 | BarBar
| AmpersandAmpersand
| Carat
| And
| Or
| Xor
2439 | Bar
| Ampersand
| Dot
| Plus
| Minus
| Star
| Slash
| Percent
2440 | LessThanLessThan
| GreaterThanGreaterThan
| StarStar
2441 | EqualEqual
| EqualEqualEqual
| ExclamationEqual
2442 | ExclamationEqualEqual
| GreaterThan
| GreaterThanEqual
2443 | LessThan
| LessThanEqual
| LessThanEqualGreaterThan
2448 let errors = check_constant_expression errors binary_left_operand
in
2449 let errors = check_constant_expression errors binary_right_operand
in
2451 | ConditionalExpression
{
2453 conditional_consequence
;
2454 conditional_alternative
; _
2456 let errors = check_constant_expression errors conditional_test
in
2457 let errors = check_constant_expression errors conditional_consequence
in
2458 let errors = check_constant_expression errors conditional_alternative
in
2460 | SimpleInitializer
{ simple_initializer_value
= e; _ }
2461 | ParenthesizedExpression
{ parenthesized_expression_expression
= e; _} ->
2462 check_constant_expression errors e
2463 | CollectionLiteralExpression
2464 { collection_literal_name
=
2466 ( SimpleTypeSpecifier
2467 { simple_type_specifier
= { syntax
= Token token
; _ } }
2468 | GenericTypeSpecifier
2469 { generic_class_type
= { syntax
= Token token
; _ }; _ }
2473 ; collection_literal_initializers
= lst
2475 } when is_namey token
->
2476 syntax_to_list_no_separators lst
2477 |> Core_list.fold_left ~init
:errors ~
f:check_constant_expression
2478 | TupleExpression
{ tuple_expression_items
= lst
; _ }
2479 | KeysetIntrinsicExpression
{ keyset_intrinsic_members
= lst
; _}
2480 | VarrayIntrinsicExpression
{ varray_intrinsic_members
= lst
; _ }
2481 | DarrayIntrinsicExpression
{ darray_intrinsic_members
= lst
; _ }
2482 | VectorIntrinsicExpression
{ vector_intrinsic_members
= lst
; _ }
2483 | DictionaryIntrinsicExpression
{ dictionary_intrinsic_members
= lst
; _}
2484 | ArrayIntrinsicExpression
{ array_intrinsic_members
= lst
; _}
2485 | ArrayCreationExpression
{ array_creation_members
= lst
; _ }
2486 | ShapeExpression
{ shape_expression_fields
= lst
; _ } ->
2487 syntax_to_list_no_separators lst
2488 |> Core_list.fold_left ~init
:errors ~
f:check_constant_expression
2489 | ElementInitializer
{ element_key
= n; element_value
= v
; _ }
2490 | FieldInitializer
{ field_initializer_name
= n; field_initializer_value
= v
; _ } ->
2491 let errors = check_constant_expression errors n in
2492 let errors = check_constant_expression errors v
in
2494 | ScopeResolutionExpression
2495 { scope_resolution_qualifier
2496 ; scope_resolution_name
2498 ; _ } when is_good_scope_resolution_qualifier scope_resolution_qualifier
&&
2499 is_good_scope_resolution_name scope_resolution_name
2502 (make_error_from_node node SyntaxError.invalid_constant_initializer
) :: errors
2504 let check_static_in_constant_decl constant_declarator_initializer
=
2505 match syntax constant_declarator_initializer
with
2506 | SimpleInitializer
{
2507 simple_initializer_value
= {
2508 syntax
= ScopeResolutionExpression
{
2509 scope_resolution_qualifier
= { syntax
= Token t
; _ };
2510 scope_resolution_name
= name;
2513 begin match Token.kind t
with
2514 | TokenKind.Static
-> true
2515 | TokenKind.Parent
when (String.lowercase_ascii
@@ text name = "class") -> true
2520 let const_decl_errors _env
node parents namespace_name
names errors =
2521 match syntax
node with
2522 | ConstantDeclarator cd
->
2524 produce_error_parents errors constant_abstract_with_initializer
2525 cd
.constant_declarator_initializer parents
2526 SyntaxError.error2051 cd
.constant_declarator_initializer
in
2528 produce_error_parents errors constant_concrete_without_initializer
2529 cd
.constant_declarator_initializer parents
SyntaxError.error2050
2530 cd
.constant_declarator_initializer
in
2532 produce_error errors is_global_in_const_decl cd
.constant_declarator_initializer
2533 SyntaxError.global_in_const_decl cd
.constant_declarator_initializer
in
2535 check_constant_expression errors cd
.constant_declarator_initializer
in
2537 produce_error errors check_static_in_constant_decl cd
.constant_declarator_initializer
2538 SyntaxError.parent_static_const_decl cd
.constant_declarator_initializer
in
2540 match syntax cd
.constant_declarator_initializer
with
2541 | SimpleInitializer
{ simple_initializer_value
= { syntax
=
2542 LiteralExpression
{ literal_expression
= { syntax
=
2543 SyntaxList
_; _}}; _}; _} ->
2544 make_error_from_node
2545 node SyntaxError.invalid_constant_initializer
:: errors
2547 if is_missing cd
.constant_declarator_name
2550 let constant_name = text cd
.constant_declarator_name
in
2551 let location = make_location_of_node cd
.constant_declarator_name
in
2553 make_first_use_or_def ~
kind:Name_def
location namespace_name
constant_name in
2555 match strmap_get constant_name names.t_constants
with
2558 (* Only error if this is inside a class *)
2559 begin match first_parent_class_name parents
with
2561 | Some
class_name ->
2562 let full_name = class_name ^
"::" ^
constant_name in
2563 make_error_from_node
2564 node (SyntaxError.redeclaration_error
full_name) :: errors
2568 names with t_constants
=
2569 strmap_add constant_name def names.t_constants
} in
2571 | _ -> names, errors
2574 let class_property_multiple_visibility_error _env
node parents
errors =
2575 match syntax
node with
2576 | PropertyDeclaration cd
->
2577 let first_parent_name = Option.value (first_parent_class_name parents
) ~default
:"" in
2578 produce_error errors
2579 declaration_multiple_visibility node
2580 (SyntaxError.property_has_multiple_visibilities
first_parent_name) cd
.property_modifiers
2584 let mixed_namespace_errors env
node parents namespace_type
errors =
2585 match syntax
node with
2586 | NamespaceBody
{ namespace_left_brace
; namespace_right_brace
; _ } ->
2587 let s = start_offset namespace_left_brace
in
2588 let e = end_offset namespace_right_brace
in
2589 begin match namespace_type
with
2590 | Unbracketed
{ start_offset; end_offset } ->
2592 (SyntaxError.make
start_offset end_offset SyntaxError.error2057
)
2594 SyntaxError.make ~
child s e SyntaxError.error2052
:: errors
2597 | NamespaceEmptyBody
{ namespace_semicolon
; _ } ->
2598 let s = start_offset namespace_semicolon
in
2599 let e = end_offset namespace_semicolon
in
2600 begin match namespace_type
with
2601 | Bracketed
{ start_offset; end_offset } ->
2603 (SyntaxError.make
start_offset end_offset SyntaxError.error2056
)
2605 SyntaxError.make ~
child s e SyntaxError.error2052
:: errors
2608 | NamespaceDeclaration
{ namespace_body
; _ } ->
2609 let is_first_decl, has_code_outside_namespace
=
2611 | [{ syntax
= SyntaxList
_; _} as decls
; { syntax
= Script
_; _}] ->
2612 let decls = syntax_to_list_no_separators decls in
2613 let decls = if not
(is_systemlib_compat env
) then decls else
2614 (* Drop everything before yourself *)
2615 fst
@@ Hh_core.List.fold_right
decls
2617 ~
f:(fun n (l
, seen
as acc) ->
2618 if seen
then acc else (n::l
, n == node))
2620 let rec is_first l
=
2622 | { syntax
= MarkupSection
{markup_text
; _}; _} :: rest
2623 when width markup_text
= 0 || is_hashbang markup_text
->
2625 | { syntax
= DeclareDirectiveStatement
_; _} :: rest
2626 | { syntax
= DeclareBlockStatement
_; _} :: rest
2627 | { syntax
= NamespaceUseDeclaration
_; _} :: rest
-> is_first rest
2628 | { syntax
= NamespaceDeclaration
_; _} :: _ -> true
2631 let has_code_outside_namespace =
2632 not
(is_namespace_empty_body namespace_body
) &&
2633 Hh_core.List.exists
decls
2634 ~
f:(function | { syntax
= MarkupSection
{ markup_text
; _}; _}
2635 when width markup_text
= 0
2636 || is_hashbang markup_text
-> false
2637 | { syntax
= NamespaceDeclaration
_; _}
2638 | { syntax
= DeclareDirectiveStatement
_; _}
2639 | { syntax
= DeclareBlockStatement
_; _}
2640 | { syntax
= ExpressionStatement
{
2641 expression_statement_expression
=
2642 { syntax
= HaltCompilerExpression
_; _}; _}; _}
2643 | { syntax
= EndOfFile
_; _}
2644 | { syntax
= NamespaceUseDeclaration
_; _} -> false
2647 is_first decls, has_code_outside_namespace
2650 let errors = if not
is_first_decl then
2651 make_error_from_node node
2652 SyntaxError.namespace_decl_first_statement
:: errors else errors
2654 let errors = if has_code_outside_namespace then
2655 make_error_from_node node
2656 SyntaxError.code_outside_namespace
:: errors else errors
2661 let enum_errors node errors =
2662 match syntax
node with
2663 | Enumerator
{ enumerator_name
= name; enumerator_value
= value; _} ->
2664 let errors = if String.lowercase_ascii
@@ text name = "class" then
2665 make_error_from_node node SyntaxError.enum_elem_name_is_class
:: errors
2667 let errors = check_constant_expression errors value in
2671 let does_op_create_write_on_left = function
2672 | Some
(TokenKind.Equal
2673 | TokenKind.BarEqual
2674 | TokenKind.PlusEqual
2675 | TokenKind.StarEqual
2676 | TokenKind.StarStarEqual
2677 | TokenKind.SlashEqual
2678 | TokenKind.DotEqual
2679 | TokenKind.MinusEqual
2680 | TokenKind.PercentEqual
2681 | TokenKind.CaratEqual
2682 | TokenKind.AmpersandEqual
2683 | TokenKind.LessThanLessThanEqual
2684 | TokenKind.GreaterThanGreaterThanEqual
2685 | TokenKind.PlusPlus
2686 | TokenKind.MinusMinus
2687 | TokenKind.Inout
) -> true
2690 let assignment_errors _env
node errors =
2691 let append_errors node errors error =
2692 make_error_from_node node error :: errors
2694 let rec check_lvalue ?
(allow_reassign_this
=false) loperand
errors : SyntaxError.t list
=
2695 let err = append_errors loperand
errors in
2696 match syntax loperand
with
2697 | ListExpression
{ list_members
= members
; _ } ->
2698 let members = syntax_to_list_no_separators members in
2699 List.fold_left
(fun e n -> check_lvalue n e) errors members
2700 | SafeMemberSelectionExpression
_ ->
2701 err (SyntaxError.not_allowed_in_write
"?-> operator")
2702 | MemberSelectionExpression
{ member_name
; _ }
2703 when token_kind member_name
= Some
TokenKind.XHPClassName
->
2704 err (SyntaxError.not_allowed_in_write
"->: operator")
2705 | VariableExpression
{ variable_expression
}
2706 when not allow_reassign_this
2707 && String.lowercase_ascii
(text variable_expression
) = SN.SpecialIdents.this
->
2708 err SyntaxError.reassign_this
2709 | DecoratedExpression
{ decorated_expression_decorator
= op
; _ }
2710 when token_kind op
= Some
TokenKind.Clone
->
2711 err (SyntaxError.not_allowed_in_write
"Clone")
2712 | DecoratedExpression
{ decorated_expression_decorator
= op
; _ }
2713 when token_kind op
= Some
TokenKind.Await
->
2714 err (SyntaxError.not_allowed_in_write
"Await")
2715 | DecoratedExpression
{ decorated_expression_decorator
= op
; _ }
2716 when token_kind op
= Some
TokenKind.Suspend
->
2717 err (SyntaxError.not_allowed_in_write
"Suspend")
2718 | DecoratedExpression
{ decorated_expression_decorator
= op
; _ }
2719 when token_kind op
= Some
TokenKind.QuestionQuestion
->
2720 err (SyntaxError.not_allowed_in_write
"?? operator")
2721 | DecoratedExpression
{ decorated_expression_decorator
= op
; _ }
2722 when token_kind op
= Some
TokenKind.BarGreaterThan
->
2723 err (SyntaxError.not_allowed_in_write
"|> operator")
2724 | DecoratedExpression
{ decorated_expression_decorator
= op
; _ }
2725 when token_kind op
= Some
TokenKind.Inout
->
2726 err (SyntaxError.not_allowed_in_write
"Inout")
2727 | LambdaExpression
_ | AnonymousFunction
_ | Php7AnonymousFunction
_
2728 | ArrayIntrinsicExpression
_ | ArrayCreationExpression
_
2729 | DarrayIntrinsicExpression
_
2730 | VarrayIntrinsicExpression
_
2732 | CollectionLiteralExpression
_
2733 | GenericTypeSpecifier
_
2734 | YieldExpression
_ | YieldFromExpression
_
2736 | BinaryExpression
_
2737 | ConditionalExpression
_
2738 | InstanceofExpression
_
2740 | AsExpression
_ | NullableAsExpression
_
2741 | ConstructorCall
_ | AnonymousClass
_
2743 | InclusionExpression
_
2745 | LiteralExpression
_ ->
2746 let kind = kind loperand
in
2747 let kind_str = Full_fidelity_syntax_kind.to_string
kind in
2748 err (SyntaxError.not_allowed_in_write
kind_str)
2749 | (PrefixUnaryExpression
{ prefix_unary_operator
= op
; _ }
2750 | PostfixUnaryExpression
{ postfix_unary_operator
= op
; _ }) ->
2751 begin match token_kind op
with
2752 | Some
TokenKind.At
| Some
TokenKind.Dollar
-> errors
2753 | _ -> err (SyntaxError.not_allowed_in_write
"Unary expression")
2755 (* FIXME: Array_get ((_, Class_const _), _) is not a valid lvalue. *)
2757 (* Ideally we should put all the rest of the syntax here so everytime
2758 * a new syntax is added people need to consider whether the syntax
2759 * can be a valid lvalue or not. However, there are too many of them. *)
2761 match syntax
node with
2762 | (PrefixUnaryExpression
2763 { prefix_unary_operator
= op
2764 ; prefix_unary_operand
= loperand
2766 | PostfixUnaryExpression
2767 { postfix_unary_operator
= op
2768 ; postfix_unary_operand
= loperand
2770 | DecoratedExpression
2771 { decorated_expression_decorator
= op
2772 ; decorated_expression_expression
= loperand
2773 }) when does_op_create_write_on_left (token_kind op
) ->
2774 check_lvalue ~allow_reassign_this
:true loperand
errors
2776 { binary_left_operand
= loperand
2777 ; binary_operator
= op
2778 ; binary_right_operand
= roperand
2779 } when does_op_create_write_on_left (token_kind op
) ->
2780 let errors = check_lvalue loperand
errors in
2781 let errors = match syntax roperand
with
2782 | PrefixUnaryExpression
2783 { prefix_unary_operator
= op
2784 ; prefix_unary_operand
= operand
2785 } when token_kind op
= Some
TokenKind.Ampersand
->
2786 begin match syntax operand
with
2787 | FunctionCallExpression
_
2788 | FunctionCallWithTypeArgumentsExpression
_
2789 | MemberSelectionExpression
_
2790 | ObjectCreationExpression
_
2791 | SafeMemberSelectionExpression
_
2792 | ScopeResolutionExpression
_
2793 | SubscriptExpression
_
2794 | VariableExpression
_ -> errors
2795 | PrefixUnaryExpression
{
2796 prefix_unary_operator
= { syntax
= Token token
; _ };
2797 prefix_unary_operand
= {
2798 syntax
= PrefixUnaryExpression
{ prefix_unary_operator
= op
; _ };
2801 } when Token.kind token
= TokenKind.Dollar
&& token_kind op
= Some
TokenKind.Dollar
->
2803 | PrefixUnaryExpression
{
2804 prefix_unary_operator
= { syntax
= Token token
; _ };
2805 prefix_unary_operand
= { syntax
= BracedExpression
_ | VariableExpression
_; _ }
2806 } when Token.kind token
= TokenKind.Dollar
-> errors
2807 | _ -> (make_error_from_node operand
SyntaxError.incorrect_byref_assignment
) :: errors
2817 let allow_ref node errors = match syntax
node with
2818 | PrefixUnaryExpression
2819 { prefix_unary_operator
= op
2820 ; prefix_unary_operand
= loperand
2821 } when token_kind op
= Some
(TokenKind.Ampersand
) ->
2822 check_lvalue loperand
errors
2824 | _loperand
-> check_lvalue node errors
2826 let errors = allow_ref k errors in
2827 let errors = allow_ref v
errors in
2832 let declare_errors _env
node parents
errors =
2833 match syntax
node with
2834 | DeclareDirectiveStatement
{ declare_directive_expression
= expr
; _}
2835 | DeclareBlockStatement
{ declare_block_expression
= expr
; _} ->
2837 match syntax expr
with
2838 | BinaryExpression
{ binary_right_operand
= r; _ } ->
2839 check_constant_expression errors r
2842 match syntax expr
with
2844 { binary_left_operand
= loper
2845 ; binary_operator
= op
2846 ; _} when token_kind op
= Some
TokenKind.Equal
2847 && String.lowercase_ascii
@@ text loper
= "strict_types" ->
2848 (* Checks if there are only other declares nodes
2849 * in front of the node in question *)
2850 let rec is_only_declares_nodes = function
2851 | ({ syntax
= DeclareDirectiveStatement
_; _} as e) :: es
2852 | ({ syntax
= DeclareBlockStatement
_; _} as e) :: es
->
2853 e == node || is_only_declares_nodes es
2858 | [{ syntax
= SyntaxList
(
2859 { syntax
= MarkupSection
{markup_text
; _}; _} :: items
); _} ; _]
2860 when width markup_text
= 0 && is_only_declares_nodes items
->
2863 make_error_from_node
2864 node SyntaxError.strict_types_first_statement
:: errors
2872 let get_namespace_name parents current_namespace_name
=
2874 | { syntax
= NamespaceDeclaration
{ namespace_name
= ns
; _ }; _ } :: _ ->
2875 if is_missing ns
then current_namespace_name
2876 else combine_names current_namespace_name
(text ns
)
2877 | _ -> current_namespace_name
2879 let is_invalid_hack_mode env
errors =
2880 let mode = FileInfo.parse_mode
@@ SyntaxTree.mode env
.syntax_tree
in
2881 if Option.is_none
mode then
2882 let root = SyntaxTree.root env
.syntax_tree
in
2883 let e = make_error_from_node root SyntaxError.invalid_hack_mode
in
2888 let find_syntax_errors env
=
2889 let rec folder acc node parents
=
2894 ; trait_require_clauses
2897 parameter_errors env
node parents namespace_name
names errors in
2898 let trait_require_clauses, names, errors =
2899 match syntax
node with
2901 | UsingStatementFunctionScoped
_
2903 let errors = statement_errors env
node parents
errors in
2904 trait_require_clauses, names, errors
2905 | MethodishDeclaration
_
2906 | FunctionDeclarationHeader
_ ->
2908 redeclaration_errors env
node parents namespace_name
names errors in
2910 methodish_errors env
node parents
errors in
2911 trait_require_clauses, names, errors
2912 | InstanceofExpression
_
2913 | LiteralExpression
_
2914 | SafeMemberSelectionExpression
_
2915 | HaltCompilerExpression
_
2916 | FunctionCallExpression
_
2919 | DecoratedExpression
_
2920 | VectorIntrinsicExpression
_
2921 | DictionaryIntrinsicExpression
_
2922 | KeysetIntrinsicExpression
_
2923 | VarrayIntrinsicExpression
_
2924 | DarrayIntrinsicExpression
_
2925 | YieldFromExpression
_
2927 | ScopeResolutionExpression
_
2928 | PrefixUnaryExpression
_
2929 | LambdaExpression
_
2932 | AnonymousFunction
_
2933 | Php7AnonymousFunction
_
2934 | SubscriptExpression
_
2936 | AwaitableCreationExpression
_
2937 | ConditionalExpression
_
2938 | CollectionLiteralExpression
_ ->
2940 expression_errors env namespace_name
node parents
errors in
2941 let errors = assignment_errors env
node errors in
2942 trait_require_clauses, names, errors
2943 | RequireClause
_ ->
2944 let trait_require_clauses, errors =
2945 require_errors env
node parents
trait_require_clauses errors in
2946 trait_require_clauses, names, errors
2947 | ClassishDeclaration
_ ->
2949 classish_errors env
node parents namespace_name
names errors in
2950 trait_require_clauses, names, errors
2951 | ConstDeclaration
_ ->
2953 class_element_errors env
node parents
errors in
2954 trait_require_clauses, names, errors
2955 | AliasDeclaration
_ ->
2956 let names, errors = alias_errors env
node namespace_name
names errors in
2957 trait_require_clauses, names, errors
2958 | ConstantDeclarator
_ ->
2960 const_decl_errors env
node parents namespace_name
names errors in
2961 trait_require_clauses, names, errors
2963 | NamespaceEmptyBody
_
2964 | NamespaceDeclaration
_ ->
2966 mixed_namespace_errors env
node parents namespace_type
errors in
2967 trait_require_clauses, names, errors
2968 | NamespaceUseDeclaration
_
2969 | NamespaceGroupUseDeclaration
_ ->
2970 let errors = group_use_errors env
node errors in
2972 namespace_use_declaration_errors env
node
2973 (namespace_name
= global_namespace_name) names errors in
2974 trait_require_clauses, names, errors
2975 | PropertyDeclaration
_ ->
2977 class_property_multiple_visibility_error env
node parents
errors in
2978 trait_require_clauses, names, errors
2980 let errors = enum_errors node errors in
2981 trait_require_clauses, names, errors
2982 | PostfixUnaryExpression
_
2983 | BinaryExpression
_
2984 | ForeachStatement
_ ->
2985 let errors = assignment_errors env
node errors in
2986 trait_require_clauses, names, errors
2987 | DeclareDirectiveStatement
_
2988 | DeclareBlockStatement
_ ->
2989 let errors = declare_errors env
node parents
errors in
2990 trait_require_clauses, names, errors
2992 | XHPExpression
_ ->
2993 let errors = xhp_errors env
node errors in
2994 trait_require_clauses, names, errors
2995 | PropertyDeclarator
{ property_initializer
= init
; _ }
2996 | StaticDeclarator
{ static_initializer
= init
; _ }
2997 | XHPClassAttribute
{ xhp_attribute_decl_initializer
= init
; _ } ->
2998 let errors = check_constant_expression errors init
in
2999 trait_require_clauses, names, errors
3000 | _ -> trait_require_clauses, names, errors in
3002 match syntax
node with
3003 | NamespaceBody
{ namespace_left_brace
; namespace_right_brace
; _ } ->
3004 let namespace_type =
3005 if namespace_type = Unspecified
3006 then Bracketed
(make_location namespace_left_brace namespace_right_brace
)
3007 else namespace_type in
3008 (* reset names/namespace_type before diving into namespace body,
3009 keeping global function names *)
3010 let namespace_name = get_namespace_name parents
namespace_name in
3011 let is_global _ f = f.f_global
in
3012 let global_funs names = strmap_filter is_global names.t_functions
in
3013 let new_names = {empty_names with t_functions
= global_funs names} in
3016 acc errors namespace_type new_names
3017 namespace_name empty_trait_require_clauses
3019 let acc1 = fold_child_nodes folder node parents
acc1 in
3020 (* add newly declared global functions to the old set of names *)
3022 {acc.names with t_functions
=
3023 strmap_union (global_funs acc1.names) acc.names.t_functions
}
3025 (* resume with old set of names and pull back
3026 accumulated errors/last seen namespace type *)
3028 acc acc1.errors namespace_type old_names
3029 acc.namespace_name acc.trait_require_clauses
3030 | NamespaceEmptyBody
{ namespace_semicolon
; _ } ->
3031 let namespace_type =
3032 if namespace_type = Unspecified
3033 then Unbracketed
(make_location_of_node namespace_semicolon
)
3036 let namespace_name = get_namespace_name parents
namespace_name in
3037 (* consider the rest of file to be the part of the namespace:
3038 reset names and namespace type, keep errors *)
3041 acc errors namespace_type empty_names
3042 namespace_name empty_trait_require_clauses
3044 fold_child_nodes folder node parents
acc
3045 | ClassishDeclaration
_
3046 | AnonymousClass
_ ->
3047 (* Reset the trait require clauses *)
3048 (* Reset the const declarations *)
3049 (* Reset the function declarations *)
3052 { new_acc
with names =
3053 { new_acc
.names with t_constants
= acc.names.t_constants
;
3054 t_functions
= acc.names.t_functions
}} in
3055 let names = { names with t_constants
= YesCase
SMap.empty
;
3056 t_functions
= NoCase
LSMap.empty
} in
3059 acc errors namespace_type names
3060 namespace_name empty_trait_require_clauses
3062 fold_child_nodes ~
cleanup folder node parents
acc
3066 acc errors namespace_type names
3067 namespace_name trait_require_clauses
3069 fold_child_nodes folder node parents
acc in
3071 if is_typechecker env
then is_invalid_hack_mode env
[]
3074 let acc = fold_child_nodes folder (SyntaxTree.root env
.syntax_tree
) []
3076 ; namespace_type = Unspecified
3077 ; names = empty_names
3078 ; namespace_name = global_namespace_name
3079 ; trait_require_clauses = empty_trait_require_clauses
3083 let parse_errors_impl env
=
3085 Minimum: suppress cascading errors; no second-pass errors if there are
3086 any first-pass errors.
3087 Typical: suppress cascading errors; give second pass errors always.
3090 let errors1 = match env
.level
with
3091 | Maximum
-> SyntaxTree.all_errors env
.syntax_tree
3092 | _ -> SyntaxTree.errors env
.syntax_tree
in
3094 if env
.level
= Minimum
&& errors1 <> [] then []
3095 else find_syntax_errors env
in
3096 List.sort
SyntaxError.compare (Core_list.append
errors1 errors2)
3098 let parse_errors env
=
3099 Stats_container.wrap_nullary_fn_timing
3100 ?stats
:(Stats_container.get_instance
())
3101 ~key
:"full_fidelity_parse_errors:parse_errors"
3102 ~
f:(fun () -> parse_errors_impl env
)
3104 end (* WithSmartConstructors *)
3106 include WithSmartConstructors
(SyntaxSmartConstructors.WithSyntax
(Syntax
))
3108 end (* WithSyntax *)