Disallow `$` as a unary operator unless as part of a variable variable variable.
[hiphop-php.git] / hphp / hack / src / parser / full_fidelity_parser_errors.ml
blob3ee6e688e5aee58298cd8e723de43d638d6d38fb
1 (**
2 * Copyright (c) 2016, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
8 *)
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
15 ) = struct
17 open Syntax
19 module SyntaxTree_ = Full_fidelity_syntax_tree
20 .WithSyntax(Syntax)
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
30 type location = {
31 start_offset: int;
32 end_offset: int
35 let text node =
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
40 | Some s, Some e ->
41 let start_offset, _ = Pos.info_raw s in
42 let _, end_offset = Pos.info_raw e in
43 { start_offset ; end_offset }
44 | _ ->
45 failwith "Could not determine positions of parse tree nodes."
47 let make_location_of_node n =
48 make_location n n
50 let start_offset n =
51 let s = Syntax.position Relative_path.default n in
52 let s, _ = Pos.info_raw (Option.value ~default:Pos.none s) in
55 let end_offset n =
56 let e = Syntax.position Relative_path.default n in
57 let _, e = Pos.info_raw (Option.value ~default:Pos.none e) in
60 type namespace_type =
61 | Unspecified
62 | Bracketed of location
63 | Unbracketed of location
65 type name_kind =
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 = {
71 f_location: location;
72 f_kind: name_kind;
73 f_name: string;
74 f_global: bool;
77 type error_level = Minimum | Typical | Maximum
79 type hhvm_compat_mode = NoCompat | HHVMCompat | SystemLibCompat
81 type env =
82 { syntax_tree : SyntaxTree.t
83 ; level : error_level
84 ; hhvm_compat_mode : hhvm_compat_mode
85 ; enable_hh_syntax : bool
86 ; is_hh_file : bool
87 ; is_strict : bool
88 ; codegen : bool
91 let make_env
92 ?(level = Typical )
93 ?(hhvm_compat_mode = NoCompat )
94 ?(enable_hh_syntax = false )
95 (syntax_tree : SyntaxTree.t)
96 ~(codegen : bool)
97 : env
98 = { syntax_tree
99 ; level
100 ; hhvm_compat_mode
101 ; enable_hh_syntax
102 ; is_hh_file = SyntaxTree.is_hack syntax_tree
103 ; is_strict = SyntaxTree.is_strict syntax_tree
104 ; codegen
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
124 | _ -> n1 ^ n2
126 let make_first_use_or_def ~kind ?(is_method=false) location namespace_name name =
128 f_location = location;
129 f_kind = kind;
130 f_name = combine_names namespace_name name;
131 f_global = not is_method && namespace_name = global_namespace_name;
134 type 'a strmap =
135 | YesCase of 'a SMap.t
136 | NoCase of 'a LSMap.t
139 type used_names = {
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 *)
146 let empty_names = {
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 =
154 fun k m ->
155 begin match m with
156 | NoCase m -> LSMap.mem k m
157 | YesCase m -> SMap.mem k m
160 let strmap_add : string -> 'a -> 'a strmap -> 'a strmap =
161 fun k v m ->
162 begin match m with
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 =
168 fun k m ->
169 begin match m with
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 =
175 fun k m ->
176 begin match m with
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 =
182 fun f m ->
183 begin match m with
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 =
189 fun x y ->
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
201 else
203 let i = String.rindex name '\\' in
204 String.sub name (i + 1) (String.length name - i - 1)
205 with Not_found -> name
207 type accumulator = {
208 errors : SyntaxError.t list;
209 namespace_type : namespace_type;
210 namespace_name: string;
211 names: used_names;
212 trait_require_clauses: TokenKind.t strmap;
215 let make_acc
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
222 then acc
223 else { errors
224 ; namespace_type
225 ; names
226 ; namespace_name
227 ; trait_require_clauses
230 let fold_child_nodes ?(cleanup = (fun x -> x)) f node parents acc =
231 Syntax.children node
232 |> Core_list.fold_left ~init:acc ~f:(fun acc c -> f acc c (node :: parents))
233 |> cleanup
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
240 | [] -> acc
241 | h :: t ->
242 begin
243 match syntax h with
244 | ListItem { list_item; list_separator } ->
245 let acc = list_item :: acc in
246 let acc =
247 if include_separators then (list_separator :: acc ) else acc in
248 aux acc t
249 | _ -> aux (h :: acc) t
250 end in
251 match syntax node with
252 | Missing -> [ ]
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 ]
256 | _ -> [ node ]
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 =
262 let rec aux lst =
263 match lst with
264 | []
265 | _ :: [] -> None
266 | h :: _ when assert_fun h -> Some h
267 | _ :: t -> aux t in
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
274 | _ -> false
277 let test_decorated_expression_child ~f node =
278 begin match syntax node with
279 | DecoratedExpression { decorated_expression_expression; _ } ->
280 f decorated_expression_expression
281 | _ -> false
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
315 | _ -> false
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 =
326 let rec aux params =
327 match params with
328 | [] -> None
329 | x :: y :: [] when is_variadic_parameter_declaration x && is_comma y ->
330 Some y
331 | _ :: t -> aux t in
332 aux (syntax_to_list_with_separators params)
334 (* Extract variadic parameter from a parameter list *)
335 let variadic_param params =
336 let rec aux params =
337 match params with
338 | [] -> None
339 | x :: _ when is_variadic_parameter_declaration x -> Some x
340 | _ :: t -> aux t in
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)
347 | _ -> false
349 (* True or false: the first item in this list matches the predicate? *)
350 let matches_first f items =
351 match items with
352 | h :: _ when f h -> true
353 | _ -> false
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
359 | SyntaxList lst ->
360 List.exists p lst
361 | _ -> false
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
367 | SyntaxList lst ->
368 let count_fun acc el = if p el then acc + 1 else acc in
369 (List.fold_left count_fun 0 lst) > 1
370 | _ -> false
372 let list_contains_duplicate node =
373 let module SyntaxMap = Map.Make (
374 struct
375 type t = Syntax.t
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
381 ) in
382 match syntax node with
383 | SyntaxList lst ->
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
389 result
390 | _ -> false
392 let token_kind node =
393 match syntax node with
394 | Token t -> Some (Token.kind t)
395 | _ -> None
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 =
402 match parents with
403 | [] -> None
404 | h :: t ->
405 begin
406 match syntax h with
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)
422 | _ -> None
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 =
459 match node with
460 | FunctionDeclarationHeader node ->
461 let label = node.function_name in
462 (f label) &&
463 (matches_first (methodish_contains_static) parents)
464 | _ -> false
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 *)
473 let is_clone label =
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 =
489 match node with
490 | FunctionDeclarationHeader node ->
491 let has_visibility node =
492 match syntax node with
493 | ParameterDeclaration { parameter_visibility; _ } ->
494 parameter_visibility |> is_missing |> not
495 | _ -> false
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)
500 | _ -> false
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
505 else
506 match node with
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
515 | _ -> false
517 (is_construct label || is_destruct label) &&
518 not (is_missing || is_void)
519 | _ -> false
520 let async_magic_method node _parents =
521 match node with
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
528 | _ -> false
530 | _ -> false
533 let clone_destruct_takes_no_arguments _method_name node _parents =
534 match node with
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
538 | _ -> false
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)
551 | _ -> false
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"
563 | _ -> false)
564 | _ -> false
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 =
569 match parents with
570 | _ :: _ :: p3 :: _ ->
571 begin match syntax p3 with
572 | ClassishDeclaration { classish_keyword; _ } ->
573 is_token_kind classish_keyword TokenKind.Interface
574 | _ -> false
576 | _ -> false
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 =
603 match parents with
604 (* using is allowed in the toplevel, and also in toplevel async blocks *)
605 | _ ::
606 { syntax = CompoundStatement _; _ } ::
607 { syntax = (
608 FunctionDeclaration _ |
609 MethodishDeclaration _ |
610 AnonymousFunction _ |
611 LambdaExpression _ |
612 AwaitableCreationExpression _); _ } :: _ -> true
613 | _ -> false
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
626 | Token t -> begin
627 Full_fidelity_token_kind.(match Token.kind t with
628 | DecimalLiteral | SingleQuotedStringLiteral
629 | DoubleQuotedStringLiteral -> false
630 | _ -> true)
632 | _ -> true
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
638 | _ -> true
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
653 | XHPExpression
654 { xhp_open =
655 { syntax = XHPOpen { xhp_open_name; _ }; _ }
656 ; xhp_close =
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
662 | _ -> 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 =
672 if check node then
673 (make_error_from_node error_node error) :: acc
674 else acc
676 let produce_error_from_check acc check node error =
677 match check node with
678 | Some error_node ->
679 (make_error_from_node error_node error) :: acc
680 | _ -> 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
685 else 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
693 error error_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"
703 | "static" -> true
704 | "using" | "inout" when is_hack env -> true
705 | _ -> false
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
716 | _ -> None
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
726 | _ -> None
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
734 else
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
740 | _ -> false
742 let rec is_immediately_in_lambda = function
743 | { syntax = LambdaExpression _; _} :: _ -> true
744 | [] | { syntax = (FunctionDeclaration _ | MethodishDeclaration _); _} :: _
745 -> false
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
753 | _ -> false
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
763 | _ -> None
766 (* Return, as a string opt, the name of the earliest Class in the list of
767 * parents. *)
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
782 | _ -> None
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 ; _ } ->
795 aux modifiers_list
796 | _ ->
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
805 * interface. *)
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
810 * trait. *)
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
822 * input. *)
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)
838 | _ -> None
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)
844 | _ -> None
846 | _ -> None
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; _ }; _ }; _ } ->
858 let attrs =
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)
863 | _ -> 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
874 | _ -> false
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
881 | _ -> false
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
886 | None -> false
888 let make_name_already_used_error node name short_name original_location
889 report_error =
890 let name = Utils.strip_ns name in
891 let original_location_error =
892 SyntaxError.make
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
898 SyntaxError.make
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
904 then names, errors
905 else
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
908 names, errors
910 let check_type_hint env node names errors =
911 let rec check (names, errors) node =
912 let names, errors =
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
918 | _ ->
919 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
928 | None -> false
929 | Some async_node ->
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
941 | _ -> None
943 (* Test if a list_expression is the value clause of a foreach_statement *)
944 let is_value_of_foreach le_node p1 =
945 match syntax p1 with
946 | ForeachStatement { foreach_value; _ } -> le_node == foreach_value
947 | _ -> false
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)
953 | _ -> false
955 (* Given a ConstDeclarator node, test whether it is abstract, but has an
956 initializer. *)
957 let constant_abstract_with_initializer init parents =
958 let is_abstract =
959 match parents with
960 | _p_list_item :: _p_syntax_list :: p_const_declaration :: _
961 when is_abstract_const p_const_declaration -> true
962 | _ -> false
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
972 | _ -> false
974 (* Given a ConstDeclarator node, test whether it is concrete, but has no
975 initializer. *)
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
980 | _ -> false in
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
998 | _ -> false
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
1009 | None -> name
1010 | Some c_name -> c_name ^ "::" ^ name ^ "()"
1012 let s = String.lowercase_ascii name in
1013 let num_args_opt =
1014 match s with
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
1021 | _ -> None
1023 let errors = match num_args_opt with
1024 | None -> errors
1025 | Some n ->
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
1038 else errors
1040 errors
1041 | _ -> 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; _} ->
1047 let errors =
1048 produce_error_for_header errors
1049 (class_constructor_destructor_has_non_void_type env)
1050 node parents SyntaxError.error2018 function_type in
1051 let errors =
1052 produce_error_for_header errors class_non_constructor_has_visibility_param
1053 node parents SyntaxError.error2010 function_parameter_list in
1054 errors
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)
1059 ~default:"" in
1060 let method_name = Option.value (extract_function_name
1061 md.methodish_function_decl_header) ~default:"" in
1062 let errors =
1063 produce_error_for_header errors
1064 (class_constructor_has_static) header_node
1065 [node] (SyntaxError.error2009 class_name method_name) modifiers in
1066 let errors =
1067 produce_error_for_header errors
1068 (class_destructor_cannot_be_static)
1069 header_node [node]
1070 (SyntaxError.class_destructor_cannot_be_static class_name method_name) modifiers in
1071 let errors =
1072 produce_error_for_header errors async_magic_method header_node [node]
1073 (SyntaxError.async_magic_method ~name:method_name) modifiers in
1074 let errors =
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
1078 let errors =
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
1081 let errors =
1082 produce_error errors declaration_multiple_visibility node
1083 SyntaxError.error2017 modifiers in
1084 let errors =
1085 produce_error errors methodish_duplicate_modifier node
1086 SyntaxError.error2013 modifiers in
1087 let fun_semicolon = md.methodish_semicolon in
1088 let errors =
1089 produce_error errors
1090 (methodish_non_abstract_without_body_not_native node) parents
1091 (SyntaxError.error2015 class_name method_name) fun_semicolon in
1092 let errors =
1093 produce_error errors
1094 methodish_abstract_conflict_with_private
1095 node (SyntaxError.error2016 class_name method_name) modifiers in
1096 let errors =
1097 produce_error errors
1098 methodish_abstract_conflict_with_final
1099 node (SyntaxError.error2019 class_name method_name) modifiers in
1100 let errors =
1101 let async_annotation = Option.value (extract_async_node node)
1102 ~default:node in
1103 produce_error errors
1104 (is_abstract_and_async_method node) parents
1105 SyntaxError.error2046 async_annotation in
1106 let errors =
1107 if is_typechecker env
1108 then produce_error errors
1109 contains_async_not_last
1110 modifiers SyntaxError.async_not_last modifiers
1111 else errors in
1112 let errors =
1113 special_method_param_errors
1114 md.methodish_function_decl_header parents errors in
1115 errors
1116 | _ -> errors
1118 let is_hashbang text =
1119 match Syntax.extract_text text with
1120 | None -> false
1121 | Some text ->
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
1132 | _ -> false)
1134 let class_has_a_construct_method parents =
1135 match first_parent_classish_node TokenKind.Class parents with
1136 | Some ({ syntax = ClassishDeclaration
1137 { classish_body =
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
1147 | _ -> false)
1148 | _ -> false
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
1153 | None, _ -> 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
1161 | _ -> false
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
1178 | _ -> None
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
1186 | _ -> None
1188 let params_errors _env params _namespace_name names errors =
1189 let errors =
1190 produce_error_from_check errors ends_with_variadic_comma
1191 params SyntaxError.error2022 in
1192 let errors =
1193 produce_error_from_check errors misplaced_variadic_param
1194 params SyntaxError.error2021 in
1195 let errors =
1196 produce_error_from_check errors variadic_param_with_default_value
1197 params SyntaxError.error2065 in
1198 let errors =
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
1215 else errors
1217 names, 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
1222 errors
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
1229 |> text in
1230 let errors =
1231 produce_error_from_check errors param_with_callconv_has_default
1232 node (SyntaxError.error2074 callconv_text) in
1233 let errors =
1234 produce_error_from_check errors param_with_callconv_is_byref
1235 node (SyntaxError.error2075 callconv_text) in
1236 let names, errors =
1237 check_type_hint env p.parameter_type names errors in
1238 let errors = if is_parameter_with_callconv node then
1239 begin
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
1243 else errors in
1244 let 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
1248 else errors in
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
1254 else errors in
1255 errors
1256 end else errors
1258 let 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
1268 else errors in
1269 let errors =
1270 if is_reference_variadic p.parameter_name then
1271 make_error_from_node node SyntaxError.variadic_reference :: errors
1272 else errors in
1273 names, 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
1278 | LambdaExpression
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
1298 | _ -> false
1300 let def = make_first_use_or_def ~is_method
1301 ~kind:Name_def location namespace_name function_name in
1302 let errors =
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
1307 let line, _ =
1308 Full_fidelity_source_text.offset_to_position text start_offset in
1309 let path =
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
1315 | None ->
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
1324 | _ -> errors
1326 { names with
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
1336 | _ -> false
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)
1349 | _ -> None in
1350 match result with
1351 | None -> errors
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 =
1360 match syntax m with
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
1365 | _ -> errors
1367 let check_collection_member errors m =
1368 match syntax m with
1369 | ElementInitializer { element_key; element_value; _ } ->
1370 let errors =
1371 check_collection_element element_key
1372 SyntaxError.reference_not_allowed_on_key errors in
1373 let errors =
1374 check_collection_element element_value
1375 SyntaxError.reference_not_allowed_on_value errors in
1376 errors
1377 | _ ->
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 } ->
1388 let is_str =
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
1394 | _ -> false
1397 if not is_str
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
1402 else errors
1404 | ScopeResolutionExpression _ -> errors
1405 | QualifiedName _ ->
1406 if is_typechecker env then
1407 make_error_from_node node SyntaxError.invalid_shape_field_name :: errors
1408 else 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
1412 else
1413 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
1424 | None -> false
1425 | Some s ->
1426 let s = String.lowercase_ascii s in
1427 begin match s with
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
1440 | _ -> false
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 ->
1449 let result =
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 = {
1464 syntax =
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)
1471 | _ -> None
1473 begin match result with
1474 | None -> errors
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
1480 | _ -> 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 ->
1488 let e =
1489 make_error_from_node node SyntaxError.method_calls_on_xhp_attributes in
1490 e :: errors
1491 | _ -> errors
1493 | _ -> errors
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)
1499 :: errors
1500 | _ -> errors
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 ->
1506 match syntax n with
1507 | ListItem {
1508 list_item = ({ syntax = Attribute { attribute_name; _ }; _ } as attr);_
1509 } ->
1510 begin match Syntax.extract_text attribute_name with
1511 | Some n when n = SN.UserAttributes.uaMemoize ->
1512 let e =
1513 make_error_from_node attr SyntaxError.memoize_on_lambda in
1514 e::errors
1515 | _ -> errors
1517 | _ -> errors
1519 | _ -> errors
1521 let is_assignment node =
1522 match syntax node with
1523 | BinaryExpression { binary_operator = { syntax = Token token; _ }; _ } ->
1524 Token.kind token = TokenKind.Equal
1525 | _ -> false
1527 let is_good_scope_resolution_qualifier node =
1528 match syntax node with
1529 | QualifiedName _ -> true
1530 | Token token ->
1531 let open TokenKind in
1532 (match Token.kind token with
1533 | XHPClassName | Name | Self | Parent | Static -> true
1534 | _ -> false
1536 | _ -> false
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
1551 then [
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 ]
1572 | _ ->
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
1601 | _ -> false
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
1612 ; _ }
1613 ; _ }
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
1620 that subset.
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
1627 then
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)]
1631 else []
1632 else []
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
1642 with _ ->
1643 let error_text =
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; _ } ->
1656 let errors =
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
1659 let errors =
1660 match parents with
1661 (* expression statement -> syntax list -> script *)
1662 | [_; _; _] -> errors
1663 | _ -> make_error_from_node node SyntaxError.halt_compiler_top_level_only :: errors in
1664 errors
1665 | FunctionCallExpression {
1666 function_call_argument_list = arg_list;
1667 function_call_receiver; _
1668 } ->
1669 let errors =
1670 match misplaced_variadic_arg arg_list with
1671 | Some h ->
1672 make_error_from_node h SyntaxError.error2033 :: errors
1673 | None -> 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)
1679 let errors =
1680 function_call_on_xhp_name_errors function_call_receiver errors in
1681 errors
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
1687 | Missing ->
1688 make_error_from_node ~error_type:SyntaxError.RuntimeError node
1689 SyntaxError.error2077 :: errors
1690 | _ -> errors
1692 | _ -> 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; _ }
1701 ; _ }
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
1713 | _ -> errors
1714 else check_collection_members m errors
1715 | VarrayIntrinsicExpression { varray_intrinsic_members = m; _ }
1716 | DarrayIntrinsicExpression { darray_intrinsic_members = m; _ } ->
1717 let errors =
1718 if not (is_hack env)
1719 then make_error_from_node node SyntaxError.vdarray_in_php :: errors
1720 else errors in
1721 check_collection_members m errors
1722 | YieldFromExpression _
1723 | YieldExpression _ ->
1724 let errors =
1725 if is_in_unyieldable_magic_method parents then
1726 make_error_from_node node SyntaxError.yield_in_magic_methods :: errors
1727 else errors in
1728 let errors =
1729 if not (is_in_function parents) then
1730 make_error_from_node node SyntaxError.yield_outside_function :: errors
1731 else errors in
1732 let errors =
1733 if has_inout_params parents then
1734 let e =
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
1739 else errors in
1740 errors
1741 | ScopeResolutionExpression
1742 { scope_resolution_qualifier = qualifier
1743 ; scope_resolution_name = name
1744 ; _ } ->
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
1758 (* ${}::class *)
1759 | PrefixUnaryExpression {
1760 prefix_unary_operator = op; _
1761 }, _ when token_kind op = Some TokenKind.Dollar ->
1762 true, false, true
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
1772 else errors in
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
1777 else errors in
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
1783 else errors in
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
1789 else errors in
1790 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
1801 | _ -> 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 *)
1830 | IsExpression
1831 { is_right_operand = hint
1834 | AsExpression
1835 { as_right_operand = hint
1837 } ->
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
1846 | _ -> errors
1848 | ConditionalExpression
1849 { conditional_consequence = cons
1850 ; _ }
1851 when is_missing cons
1852 && is_typechecker env ->
1853 make_error_from_node node SyntaxError.elvis_operator_space :: errors
1854 | LambdaExpression
1855 { lambda_attribute_spec = s
1856 ; lambda_body = body
1857 ; _ } ->
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
1867 ; _ } ->
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
1877 let status =
1878 match syntax n with
1879 (* non-qualified name *)
1880 | SimpleTypeSpecifier { simple_type_specifier = ({
1881 syntax = Token t; _
1882 } as n);_ }
1883 | GenericTypeSpecifier { generic_class_type = ({
1884 syntax = Token t; _
1885 } as n);_ }
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; _ }; _
1894 };_ }
1895 | GenericTypeSpecifier { generic_class_type = {
1896 syntax = QualifiedName { qualified_name_parts = parts; _ }; _
1897 };_ } ->
1898 begin match syntax_to_list false parts with
1899 (* HH\Vector in global namespace *)
1900 | [l; r]
1901 when namespace_name = global_namespace_name &&
1902 is_qualified_std_collection l r ->
1903 `ValidClass (String.lowercase_ascii (text r))
1904 (* \HH\Vector *)
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 ->
1915 let msg =
1916 if num_initializers = 0
1917 then SyntaxError.pair_initializer_needed
1918 else SyntaxError.pair_initializer_arity
1920 let e =
1921 make_error_from_node node msg ~error_type:SyntaxError.RuntimeError in
1922 e :: errors
1923 | `ValidClass _ -> errors
1924 | `InvalidBraceKind ->
1925 let e =
1926 make_error_from_node node SyntaxError.invalid_brace_kind_in_collection_initializer in
1927 e :: errors
1928 | `InvalidClass ->
1929 let e =
1930 make_error_from_node node SyntaxError.invalid_class_in_collection_initializer in
1931 e :: errors
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 ->
1938 errors
1939 | le :: _ when is_lambda_expression le -> errors
1940 | rs :: _ when is_return_statement rs -> errors
1941 | es :: _ when is_expression_statement es -> errors
1942 | be :: es :: _
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
1954 | be :: us :: _
1955 when is_binary_expression be && is_assignment be &&
1956 (is_using_statement_block_scoped us ||
1957 is_using_statement_function_scoped us) -> errors
1958 | us :: _
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
1984 errors, p_names
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 *)
1999 trait_use_clauses,
2000 make_error_from_node node
2001 (SyntaxError.conflicting_trait_require_clauses ~name) :: errors
2003 let 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
2008 | _ -> 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
2018 let line_num, _ =
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
2022 let error =
2023 make_name_already_used_error name long_name_text name_text location
2024 (match f_kind with
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
2029 | _ ->
2030 let def =
2031 make_first_use_or_def ~kind:Name_def location namespace_name name_text in
2032 let names =
2033 { names with
2034 t_classes = strmap_add name_text def names.t_classes} in
2035 names, errors
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 ->
2055 match syntax e with
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 ->
2059 match syntax e with
2060 | ScopeResolutionExpression {scope_resolution_name; _ } ->
2061 text scope_resolution_name <> "class"
2062 | _ -> true)
2063 | _ -> false)
2064 | _ -> false in
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 ->
2071 match syntax e with
2072 | Attribute {attribute_name; _ } ->
2073 text attribute_name = SN.UserAttributes.uaSealed
2074 | _ -> false)
2075 | _ -> false in
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
2085 | [_] -> false
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
2098 let errors =
2099 produce_error errors
2100 classish_duplicate_modifiers cd.classish_modifiers
2101 SyntaxError.error2031 cd.classish_modifiers in
2102 let errors =
2103 produce_error errors
2104 (classish_sealed_arg_not_classname env) ()
2105 SyntaxError.sealed_val_not_classname cd.classish_attribute in
2106 let errors =
2107 produce_error errors
2108 classish_invalid_extends_keyword ()
2109 SyntaxError.error2036 cd.classish_extends_keyword in
2110 let errors =
2111 produce_error errors
2112 (classish_sealed_final env) ()
2113 SyntaxError.sealed_final cd.classish_attribute in
2114 let errors =
2115 produce_error errors
2116 (is_reserved_keyword env) cd.classish_name
2117 SyntaxError.reserved_keyword_as_class_name cd.classish_name in
2118 let errors =
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
2123 else errors in
2124 let name = text cd.classish_name in
2125 let errors =
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
2131 let errors, _ =
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 ->
2141 match syntax m with
2142 | XHPCategoryDeclaration _ -> true
2143 | _ -> false) in
2144 match cats with
2145 | [] | [_] -> false
2146 | _ -> true in
2147 let errors =
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
2153 else errors in
2154 let 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
2159 else errors in
2160 let errors =
2161 if has_multiple_xhp_category_decls
2162 then make_error_from_node node
2163 SyntaxError.xhp_class_multiple_category_decls :: errors
2164 else errors in
2165 errors
2166 | _ -> errors in
2167 let names, 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
2173 | _ ->
2174 names, errors in
2175 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
2185 | _ -> errors
2188 let alias_errors env node namespace_name names errors =
2189 match syntax node with
2190 | AliasDeclaration ad ->
2191 let errors =
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
2195 else errors in
2196 if is_missing ad.alias_name then names,errors
2197 else
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; _ } ->
2206 if is_missing kind
2207 then
2208 begin match syntax clause_kind with
2209 | Missing -> false
2210 | Token token when let k = Token.kind token in
2211 TokenKind.(k = Function || k = Const) -> false
2212 | _ -> true
2214 else not (is_missing clause_kind)
2215 | _ -> false
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
2226 ; _} ->
2227 let errors =
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
2235 | _ -> errors
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 =
2260 if case_sensitive
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)))
2268 then
2269 let error =
2270 make_name_already_used_error name name_text
2271 short_name location report_error in
2272 names, error :: errors
2273 else
2274 names, errors
2275 | None ->
2276 let new_use =
2277 make_first_use_or_def
2278 ~kind:Name_use
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
2285 | Token token ->
2286 let open TokenKind in
2287 (match Token.kind token with
2288 | Namespace ->
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
2294 | Type ->
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
2300 | Function ->
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
2306 | Const ->
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
2311 | _ ->
2312 names, errors
2314 | Missing ->
2315 let errors =
2316 if name_text = "strict"
2317 then
2318 let message =
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
2322 else errors in
2324 let names, 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
2329 else
2330 let err_msg =
2331 if is_hack env && f_kind <> Name_def then
2332 let text = SyntaxTree.text env.syntax_tree in
2333 let line_num, _ =
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
2344 | None ->
2345 let new_use =
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
2348 let t_namespaces =
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
2354 names, errors
2355 | _ ->
2356 names, errors
2358 | _ ->
2359 names, errors
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
2367 | _ -> false
2369 | _ -> false
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; _ } ->
2377 let f =
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; _ } ->
2385 let f =
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
2396 | _ -> false
2398 let is_good_scope_resolution_name node =
2399 match syntax node with
2400 | QualifiedName _ -> true
2401 | Token token ->
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
2412 -> true
2413 | _ -> false
2415 | _ -> false
2417 match syntax node with
2418 | Missing
2419 | QualifiedName _
2420 | LiteralExpression _
2421 -> errors
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
2429 | _ -> false
2430 ) ->
2431 check_constant_expression errors prefix_unary_operand
2432 | BinaryExpression
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
2444 | QuestionColon
2445 -> true
2446 | _ -> false
2447 ) ->
2448 let errors = check_constant_expression errors binary_left_operand in
2449 let errors = check_constant_expression errors binary_right_operand in
2450 errors
2451 | ConditionalExpression {
2452 conditional_test;
2453 conditional_consequence;
2454 conditional_alternative; _
2455 } ->
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
2459 errors
2460 | SimpleInitializer { simple_initializer_value = e; _ }
2461 | ParenthesizedExpression { parenthesized_expression_expression = e; _} ->
2462 check_constant_expression errors e
2463 | CollectionLiteralExpression
2464 { collection_literal_name =
2465 { syntax =
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
2493 errors
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
2500 -> errors
2501 | _ ->
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;
2511 _}; _}; _
2512 } ->
2513 begin match Token.kind t with
2514 | TokenKind.Static -> true
2515 | TokenKind.Parent when (String.lowercase_ascii @@ text name = "class") -> true
2516 | _ -> false
2518 | _ -> false
2520 let const_decl_errors _env node parents namespace_name names errors =
2521 match syntax node with
2522 | ConstantDeclarator cd ->
2523 let errors =
2524 produce_error_parents errors constant_abstract_with_initializer
2525 cd.constant_declarator_initializer parents
2526 SyntaxError.error2051 cd.constant_declarator_initializer in
2527 let errors =
2528 produce_error_parents errors constant_concrete_without_initializer
2529 cd.constant_declarator_initializer parents SyntaxError.error2050
2530 cd.constant_declarator_initializer in
2531 let errors =
2532 produce_error errors is_global_in_const_decl cd.constant_declarator_initializer
2533 SyntaxError.global_in_const_decl cd.constant_declarator_initializer in
2534 let errors =
2535 check_constant_expression errors cd.constant_declarator_initializer in
2536 let errors =
2537 produce_error errors check_static_in_constant_decl cd.constant_declarator_initializer
2538 SyntaxError.parent_static_const_decl cd.constant_declarator_initializer in
2539 let errors =
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
2546 | _ -> errors in
2547 if is_missing cd.constant_declarator_name
2548 then names, errors
2549 else
2550 let constant_name = text cd.constant_declarator_name in
2551 let location = make_location_of_node cd.constant_declarator_name in
2552 let def =
2553 make_first_use_or_def ~kind:Name_def location namespace_name constant_name in
2554 let errors =
2555 match strmap_get constant_name names.t_constants with
2556 | None -> errors
2557 | Some _ ->
2558 (* Only error if this is inside a class *)
2559 begin match first_parent_class_name parents with
2560 | None -> errors
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
2567 let names = {
2568 names with t_constants =
2569 strmap_add constant_name def names.t_constants } in
2570 names, errors
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
2581 | _ -> errors
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 } ->
2591 let child = Some
2592 (SyntaxError.make start_offset end_offset SyntaxError.error2057)
2594 SyntaxError.make ~child s e SyntaxError.error2052 :: errors
2595 | _ -> 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 } ->
2602 let child = Some
2603 (SyntaxError.make start_offset end_offset SyntaxError.error2056)
2605 SyntaxError.make ~child s e SyntaxError.error2052 :: errors
2606 | _ -> errors
2608 | NamespaceDeclaration { namespace_body; _ } ->
2609 let is_first_decl, has_code_outside_namespace =
2610 match parents with
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
2616 ~init:([], false)
2617 ~f:(fun n (l, seen as acc) ->
2618 if seen then acc else (n::l, n == node))
2620 let rec is_first l =
2621 match l with
2622 | { syntax = MarkupSection {markup_text; _}; _} :: rest
2623 when width markup_text = 0 || is_hashbang markup_text ->
2624 is_first rest
2625 | { syntax = DeclareDirectiveStatement _; _} :: rest
2626 | { syntax = DeclareBlockStatement _; _} :: rest
2627 | { syntax = NamespaceUseDeclaration _; _} :: rest -> is_first rest
2628 | { syntax = NamespaceDeclaration _; _} :: _ -> true
2629 | _ -> false
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
2645 | _ -> true)
2647 is_first decls, has_code_outside_namespace
2648 | _ -> true, false
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
2658 errors
2659 | _ -> 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
2666 else errors in
2667 let errors = check_constant_expression errors value in
2668 errors
2669 | _ -> errors
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
2688 | _ -> false
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 _
2731 | ShapeExpression _
2732 | CollectionLiteralExpression _
2733 | GenericTypeSpecifier _
2734 | YieldExpression _ | YieldFromExpression _
2735 | CastExpression _
2736 | BinaryExpression _
2737 | ConditionalExpression _
2738 | InstanceofExpression _
2739 | IsExpression _
2740 | AsExpression _ | NullableAsExpression _
2741 | ConstructorCall _ | AnonymousClass _
2742 | XHPExpression _
2743 | InclusionExpression _
2744 | TupleExpression _
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")
2754 end (* match *)
2755 (* FIXME: Array_get ((_, Class_const _), _) is not a valid lvalue. *)
2756 | _ -> errors
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
2775 | BinaryExpression
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 ->
2802 errors
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
2809 | _ -> errors
2811 errors
2812 | ForeachStatement
2813 { foreach_key = k;
2814 foreach_value = v;
2816 } ->
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
2823 | Missing -> errors
2824 | _loperand -> check_lvalue node errors
2826 let errors = allow_ref k errors in
2827 let errors = allow_ref v errors in
2828 errors
2829 | _ -> errors
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; _} ->
2836 let errors =
2837 match syntax expr with
2838 | BinaryExpression { binary_right_operand = r; _ } ->
2839 check_constant_expression errors r
2840 | _ -> errors in
2841 let errors =
2842 match syntax expr with
2843 | BinaryExpression
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
2854 | _ -> false
2856 let errors =
2857 match parents with
2858 | [{ syntax = SyntaxList (
2859 { syntax = MarkupSection {markup_text; _}; _} :: items); _} ; _]
2860 when width markup_text = 0 && is_only_declares_nodes items ->
2861 errors
2862 | _ ->
2863 make_error_from_node
2864 node SyntaxError.strict_types_first_statement :: errors
2866 errors
2867 | _ -> errors
2869 errors
2870 | _ -> errors
2872 let get_namespace_name parents current_namespace_name =
2873 match parents with
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
2884 e::errors
2885 else
2886 errors
2888 let find_syntax_errors env =
2889 let rec folder acc node parents =
2890 let { errors
2891 ; namespace_type
2892 ; names
2893 ; namespace_name
2894 ; trait_require_clauses
2895 } = acc in
2896 let names, errors =
2897 parameter_errors env node parents namespace_name names errors in
2898 let trait_require_clauses, names, errors =
2899 match syntax node with
2900 | TryStatement _
2901 | UsingStatementFunctionScoped _
2902 | ForStatement _ ->
2903 let errors = statement_errors env node parents errors in
2904 trait_require_clauses, names, errors
2905 | MethodishDeclaration _
2906 | FunctionDeclarationHeader _ ->
2907 let names, errors =
2908 redeclaration_errors env node parents namespace_name names errors in
2909 let errors =
2910 methodish_errors env node parents errors in
2911 trait_require_clauses, names, errors
2912 | InstanceofExpression _
2913 | LiteralExpression _
2914 | SafeMemberSelectionExpression _
2915 | HaltCompilerExpression _
2916 | FunctionCallExpression _
2917 | ListExpression _
2918 | ShapeExpression _
2919 | DecoratedExpression _
2920 | VectorIntrinsicExpression _
2921 | DictionaryIntrinsicExpression _
2922 | KeysetIntrinsicExpression _
2923 | VarrayIntrinsicExpression _
2924 | DarrayIntrinsicExpression _
2925 | YieldFromExpression _
2926 | YieldExpression _
2927 | ScopeResolutionExpression _
2928 | PrefixUnaryExpression _
2929 | LambdaExpression _
2930 | IsExpression _
2931 | AsExpression _
2932 | AnonymousFunction _
2933 | Php7AnonymousFunction _
2934 | SubscriptExpression _
2935 | ConstructorCall _
2936 | AwaitableCreationExpression _
2937 | ConditionalExpression _
2938 | CollectionLiteralExpression _ ->
2939 let errors =
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 _ ->
2948 let names, errors =
2949 classish_errors env node parents namespace_name names errors in
2950 trait_require_clauses, names, errors
2951 | ConstDeclaration _ ->
2952 let errors =
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 _ ->
2959 let names, errors =
2960 const_decl_errors env node parents namespace_name names errors in
2961 trait_require_clauses, names, errors
2962 | NamespaceBody _
2963 | NamespaceEmptyBody _
2964 | NamespaceDeclaration _ ->
2965 let errors =
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
2971 let names, errors =
2972 namespace_use_declaration_errors env node
2973 (namespace_name = global_namespace_name) names errors in
2974 trait_require_clauses, names, errors
2975 | PropertyDeclaration _ ->
2976 let errors =
2977 class_property_multiple_visibility_error env node parents errors in
2978 trait_require_clauses, names, errors
2979 | Enumerator _ ->
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
2991 | XHPEnumType _
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
3014 let acc1 =
3015 make_acc
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 *)
3021 let old_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 *)
3027 make_acc
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)
3034 else namespace_type
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 *)
3039 let acc =
3040 make_acc
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 *)
3050 let cleanup =
3051 fun new_acc ->
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
3057 let acc =
3058 make_acc
3059 acc errors namespace_type names
3060 namespace_name empty_trait_require_clauses
3062 fold_child_nodes ~cleanup folder node parents acc
3063 | _ ->
3064 let acc =
3065 make_acc
3066 acc errors namespace_type names
3067 namespace_name trait_require_clauses
3069 fold_child_nodes folder node parents acc in
3070 let errors =
3071 if is_typechecker env then is_invalid_hack_mode env []
3072 else []
3074 let acc = fold_child_nodes folder (SyntaxTree.root env.syntax_tree) []
3075 { errors
3076 ; namespace_type = Unspecified
3077 ; names = empty_names
3078 ; namespace_name = global_namespace_name
3079 ; trait_require_clauses = empty_trait_require_clauses
3080 } in
3081 acc.errors
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.
3088 Maximum: all errors
3090 let errors1 = match env.level with
3091 | Maximum -> SyntaxTree.all_errors env.syntax_tree
3092 | _ -> SyntaxTree.errors env.syntax_tree in
3093 let errors2 =
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 *)