2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
10 /** Module consisting of the special names known to the typechecker */
13 pub const PARENT: &str = "parent";
15 pub const STATIC: &str = "static";
17 pub const SELF: &str = "self";
19 pub const UNKNOWN: &str = "\\*Unknown*";
21 /* Used for dynamic classnames, e.g. new $foo(); */
23 pub const AWAITABLE: &str = "\\HH\\Awaitable";
25 pub const GENERATOR: &str = "\\Generator";
27 pub const ASYNC_GENERATOR: &str = "\\HH\\AsyncGenerator";
29 pub const HH_FORMAT_STRING: &str = "\\HH\\FormatString";
31 pub fn is_format_string(x: &str) -> bool {
33 HH_FORMAT_STRING => true,
38 pub const HH_BUILTIN_ENUM: &str = "\\HH\\BuiltinEnum";
40 pub const HH_BUILTIN_ENUM_CLASS: &str = "\\HH\\BuiltinEnumClass";
42 pub const THROWABLE: &str = "\\Throwable";
44 pub const STD_CLASS: &str = "\\stdClass";
46 pub const DATE_TIME: &str = "\\DateTime";
48 pub const DATE_TIME_IMMUTABLE: &str = "\\DateTimeImmutable";
50 pub const ASYNC_ITERATOR: &str = "\\HH\\AsyncIterator";
52 pub const ASYNC_KEYED_ITERATOR: &str = "\\HH\\AsyncKeyedIterator";
54 pub const STRINGISH: &str = "\\Stringish";
56 pub const XHP_CHILD: &str = "\\XHPChild";
58 pub const IMEMOIZE_PARAM: &str = "\\HH\\IMemoizeParam";
60 pub const CLASS_NAME: &str = "\\HH\\classname";
62 pub const TYPE_NAME: &str = "\\HH\\typename";
64 pub const IDISPOSABLE: &str = "\\IDisposable";
66 pub const IASYNC_DISPOSABLE: &str = "\\IAsyncDisposable";
68 pub const MEMBER_OF: &str = "\\HH\\MemberOf";
72 /* concrete classes */
73 pub const VECTOR: &str = "\\HH\\Vector";
75 pub const IMM_VECTOR: &str = "\\HH\\ImmVector";
77 pub const SET: &str = "\\HH\\Set";
79 pub const IMM_SET: &str = "\\HH\\ImmSet";
81 pub const MAP: &str = "\\HH\\Map";
83 pub const IMM_MAP: &str = "\\HH\\ImmMap";
85 pub const PAIR: &str = "\\HH\\Pair";
88 pub const CONTAINER: &str = "\\HH\\Container";
90 pub const KEYED_CONTAINER: &str = "\\HH\\KeyedContainer";
92 pub const TRAVERSABLE: &str = "\\HH\\Traversable";
94 pub const KEYED_TRAVERSABLE: &str = "\\HH\\KeyedTraversable";
96 pub const COLLECTION: &str = "\\Collection";
98 pub const CONST_VECTOR: &str = "\\ConstVector";
100 pub const CONST_MAP: &str = "\\ConstMap";
102 pub const CONST_COLLECTION: &str = "\\ConstCollection";
104 pub const DICT: &str = "\\HH\\dict";
106 pub const VEC: &str = "\\HH\\vec";
108 pub const KEYSET: &str = "\\HH\\keyset";
112 use lazy_static::lazy_static;
113 use std::collections::HashMap;
114 use std::collections::HashSet;
116 pub const M_CLASS: &str = "class";
118 pub const __CONSTRUCT: &str = "__construct";
120 pub const __DESTRUCT: &str = "__destruct";
122 pub const __CALL: &str = "__call";
124 pub const __CALL_STATIC: &str = "__callStatic";
126 pub const __CLONE: &str = "__clone";
128 pub const __DEBUG_INFO: &str = "__debugInfo";
130 pub const __DISPOSE: &str = "__dispose";
132 pub const __DISPOSE_ASYNC: &str = "__disposeAsync";
134 pub const __GET: &str = "__get";
136 pub const __INVOKE: &str = "__invoke";
138 pub const __ISSET: &str = "__isset";
140 pub const __SET: &str = "__set";
142 pub const __SET_STATE: &str = "__set_state";
144 pub const __SLEEP: &str = "__sleep";
146 pub const __TO_STRING: &str = "__toString";
148 pub const __UNSET: &str = "__unset";
150 pub const __WAKEUP: &str = "__wakeup";
153 static ref AS_SET: HashSet<&'static str> = vec![
174 pub static ref AS_LOWERCASE_SET: HashSet<String> = {
177 .fold(HashSet::<String>::new(), |mut set, special_name| {
178 set.insert(special_name.to_ascii_lowercase());
182 pub static ref UNSUPPORTED_MAP: HashMap<String, &'static str> = {
183 vec![__CALL, __CALL_STATIC, __GET, __ISSET, __SET, __UNSET]
186 HashMap::<String, &'static str>::new(),
187 |mut set, special_name| {
188 set.insert(special_name.to_ascii_lowercase(), special_name);
195 /* Any data- or aria- attribute is always valid, even if it is not declared
196 * for a given XHP element */
197 pub fn is_special_xhp_attribute(s: &str) -> bool {
200 ":data-" | ":aria-" => true,
206 pub mod user_attributes {
207 use lazy_static::lazy_static;
208 use std::collections::HashSet;
210 pub const OVERRIDE: &str = "__Override";
212 pub const CONSISTENT_CONSTRUCT: &str = "__ConsistentConstruct";
214 pub const CONST: &str = "__Const";
216 pub const CONST_FUN: &str = "__ConstFun";
218 pub const DEPRECATED: &str = "__Deprecated";
220 pub const ENTRY_POINT: &str = "__EntryPoint";
222 pub const MEMOIZE: &str = "__Memoize";
224 pub const MEMOIZE_LSB: &str = "__MemoizeLSB";
226 pub const PHP_STD_LIB: &str = "__PHPStdLib";
228 pub const HIPHOP_SPECIFIC: &str = "__HipHopSpecific";
230 pub const ACCEPT_DISPOSABLE: &str = "__AcceptDisposable";
232 pub const RETURN_DISPOSABLE: &str = "__ReturnDisposable";
234 pub const LSB: &str = "__LSB";
236 pub const SEALED: &str = "__Sealed";
238 pub const LATE_INIT: &str = "__LateInit";
240 pub const NEWABLE: &str = "__Newable";
242 pub const ENFORCEABLE: &str = "__Enforceable";
244 pub const EXPLICIT: &str = "__Explicit";
246 pub const SOFT: &str = "__Soft";
248 pub const WARN: &str = "__Warn";
250 pub const MOCK_CLASS: &str = "__MockClass";
252 pub const PROVENANCE_SKIP_FRAME: &str = "__ProvenanceSkipFrame";
254 pub const DYNAMICALLY_CALLABLE: &str = "__DynamicallyCallable";
256 pub const DYNAMICALLY_CONSTRUCTIBLE: &str = "__DynamicallyConstructible";
258 pub const REIFIABLE: &str = "__Reifiable";
260 pub const NEVER_INLINE: &str = "__NEVER_INLINE";
262 pub const ENABLE_UNSTABLE_FEATURES: &str = "__EnableUnstableFeatures";
264 pub const ENUM_CLASS: &str = "__EnumClass";
266 pub const ATOM: &str = "__Atom";
268 pub const POLICIED: &str = "__Policied";
270 pub const INFERFLOWS: &str = "__InferFlows";
272 pub const EXTERNAL: &str = "__External";
275 static ref AS_SET: HashSet<&'static str> = vec![
277 CONSISTENT_CONSTRUCT,
296 PROVENANCE_SKIP_FRAME,
297 DYNAMICALLY_CALLABLE,
298 DYNAMICALLY_CONSTRUCTIBLE,
301 ENABLE_UNSTABLE_FEATURES,
312 pub fn is_memoized(name: &str) -> bool {
313 name == MEMOIZE || name == MEMOIZE_LSB
316 // TODO(hrust) these should probably be added to the above map/fields, too
318 pub fn is_native(name: &str) -> bool {
322 pub fn is_foldable(name: &str) -> bool {
323 name == "__IsFoldable"
326 pub fn is_meth_caller(name: &str) -> bool {
327 name == "__MethCaller"
330 pub fn is_reserved(name: &str) -> bool {
331 name.starts_with("__")
334 pub fn is_soft(name: &str) -> bool {
339 pub mod attribute_kinds {
340 use lazy_static::lazy_static;
341 use std::collections::HashMap;
343 pub const CLS: &str = "\\HH\\ClassAttribute";
345 pub const ENUM: &str = "\\HH\\EnumAttribute";
347 pub const TYPE_ALIAS: &str = "\\HH\\TypeAliasAttribute";
349 pub const FN: &str = "\\HH\\FunctionAttribute";
351 pub const MTHD: &str = "\\HH\\MethodAttribute";
353 pub const INST_PROPERTY: &str = "\\HH\\InstancePropertyAttribute";
355 pub const STATIC_PROPERTY: &str = "\\HH\\StaticPropertyAttribute";
357 pub const PARAMETER: &str = "\\HH\\ParameterAttribute";
359 pub const TYPE_PARAM: &str = "\\HH\\TypeParameterAttribute";
361 pub const FILE: &str = "\\HH\\FileAttribute";
363 pub const TYPE_CONST: &str = "\\HH\\TypeConstantAttribute";
365 pub const LAMBDA: &str = "\\HH\\LambdaAttribute";
367 pub static PLAIN_ENGLISH: &[(&str, &str)] = &[
370 (TYPE_ALIAS, "a typealias"),
373 (INST_PROPERTY, "an instance property"),
374 (STATIC_PROPERTY, "a static property"),
375 (PARAMETER, "a parameter"),
376 (TYPE_PARAM, "a type parameter"),
378 (TYPE_CONST, "a type constant"),
379 (LAMBDA, "a lambda expression"),
383 pub static ref PLAIN_ENGLISH_MAP: HashMap<&'static str, &'static str> =
384 PLAIN_ENGLISH.iter().copied().collect();
388 /* Tested before \\-prepending name-canonicalization */
389 pub mod special_functions {
390 use lazy_static::lazy_static;
392 pub const TUPLE: &str = "tuple"; /* pseudo-function */
394 pub const ECHO: &str = "echo"; /* pseudo-function */
396 pub const HHAS_ADATA: &str = "__hhas_adata";
398 pub fn is_special_function(x: &str) -> bool {
400 static ref ALL_SPECIAL_FUNCTIONS: Vec<&'static str> =
401 vec![TUPLE, ECHO, HHAS_ADATA,].into_iter().collect();
403 ALL_SPECIAL_FUNCTIONS.contains(&x)
407 pub mod autoimported_functions {
408 pub const INVARIANT: &str = "\\HH\\invariant";
410 pub const INVARIANT_VIOLATION: &str = "\\HH\\invariant_violation";
412 pub const FUN_: &str = "\\HH\\fun";
414 pub const INST_METH: &str = "\\HH\\inst_meth";
416 pub const CLASS_METH: &str = "\\HH\\class_meth";
418 pub const METH_CALLER: &str = "\\HH\\meth_caller";
421 pub mod special_idents {
422 pub const THIS: &str = "$this";
424 pub const PLACEHOLDER: &str = "$_";
426 pub const DOLLAR_DOLLAR: &str = "$$";
428 /* Intentionally using an invalid variable name to ensure it's translated */
429 pub const TMP_VAR_PREFIX: &str = "__tmp$";
431 pub fn is_tmp_var(name: &str) -> bool {
432 name.len() > 6 && &name.as_bytes()[..6] == TMP_VAR_PREFIX.as_bytes()
435 pub fn assert_tmp_var(name: &str) {
436 assert!(is_tmp_var(name))
440 pub mod pseudo_functions {
441 use lazy_static::lazy_static;
442 use std::collections::HashSet;
444 pub const ISSET: &str = "\\isset";
446 pub const UNSET: &str = "\\unset";
448 pub const HH_SHOW: &str = "\\hh_show";
450 pub const HH_SHOW_ENV: &str = "\\hh_show_env";
452 pub const HH_LOG_LEVEL: &str = "\\hh_log_level";
454 pub const HH_FORCE_SOLVE: &str = "\\hh_force_solve";
456 pub const HH_LOOP_FOREVER: &str = "\\hh_loop_forever";
458 pub const ECHO: &str = "\\echo";
460 pub const ECHO_NO_NS: &str = "echo";
462 pub const EMPTY: &str = "\\empty";
464 pub const EXIT: &str = "\\exit";
466 pub const DIE: &str = "\\die";
468 pub static ALL_PSEUDO_FUNCTIONS: &[&str] = &[
483 static ref PSEUDO_SET: HashSet<&'static str> =
484 ALL_PSEUDO_FUNCTIONS.iter().copied().collect();
487 pub fn is_pseudo_function(x: &str) -> bool {
488 PSEUDO_SET.contains(x)
492 pub mod std_lib_functions {
493 pub const IS_ARRAY: &str = "\\is_array";
495 pub const IS_NULL: &str = "\\is_null";
497 pub const GET_CLASS: &str = "\\get_class";
499 pub const ARRAY_FILTER: &str = "\\array_filter";
501 pub const ARRAY_MAP: &str = "\\array_map";
503 pub const CALL_USER_FUNC: &str = "\\call_user_func";
505 pub const TYPE_STRUCTURE: &str = "\\HH\\type_structure";
507 pub const ARRAY_MARK_LEGACY: &str = "\\HH\\array_mark_legacy";
509 pub const ARRAY_UNMARK_LEGACY: &str = "\\HH\\array_unmark_legacy";
513 use lazy_static::lazy_static;
514 use std::collections::HashSet;
516 pub const NULL: &str = "null";
518 pub const VOID: &str = "void";
520 pub const RESOURCE: &str = "resource";
522 pub const NUM: &str = "num";
524 pub const ARRAYKEY: &str = "arraykey";
526 pub const NORETURN: &str = "noreturn";
528 pub const MIXED: &str = "mixed";
530 pub const NONNULL: &str = "nonnull";
532 pub const THIS: &str = "this";
534 pub const DYNAMIC: &str = "dynamic";
536 pub const NOTHING: &str = "nothing";
538 pub const INT: &str = "int";
540 pub const BOOL: &str = "bool";
542 pub const FLOAT: &str = "float";
544 pub const STRING: &str = "string";
546 pub const DARRAY: &str = "darray";
548 pub const VARRAY: &str = "varray";
550 pub const VARRAY_OR_DARRAY: &str = "varray_or_darray";
552 pub const CALLABLE: &str = "callable";
554 pub const OBJECT_CAST: &str = "object";
556 pub const WILDCARD: &str = "_";
558 pub fn is_reserved_type_hint(x: &str) -> bool {
560 static ref RESERVED_TYPEHINTS: HashSet<&'static str> = vec![
586 RESERVED_TYPEHINTS.contains(x)
590 static ref RESERVED_GLOBAL_NAMES: HashSet<&'static str> =
591 vec![CALLABLE, crate::classes::SELF, crate::classes::PARENT]
596 pub fn is_reserved_global_name(x: &str) -> bool {
597 RESERVED_GLOBAL_NAMES.contains(x)
601 static ref RESERVED_HH_NAMES: HashSet<&'static str> = vec![
602 VOID, NORETURN, INT, BOOL, FLOAT, NUM, STRING, RESOURCE, MIXED, ARRAYKEY, DYNAMIC,
603 WILDCARD, NULL, NONNULL, NOTHING, THIS
609 pub fn is_reserved_hh_name(x: &str) -> bool {
610 RESERVED_HH_NAMES.contains(x)
613 // This function checks if this is a namespace of the "(not HH)\\(...)*\\(reserved_name)"
614 pub fn is_namespace_with_reserved_hh_name(x: &str) -> bool {
615 // This splits the string into its namespaces
616 fn unqualify(x: &str) -> (Vec<&str>, &str) {
617 let mut as_list = x.split('\\').collect::<Vec<&str>>();
618 // Retain if not empty
619 as_list.retain(|&split| match split {
623 let last_split = match as_list.pop() {
628 (as_list, last_split)
631 // This returns a bool whether or not the list is just the string "HH"
632 fn is_hh(qualifier: &[&str]) -> bool {
633 match qualifier.len() {
634 1 => qualifier[0] == "HH",
638 let (qualifier, name) = unqualify(x);
639 !is_hh(&qualifier) && !qualifier.is_empty() && is_reserved_hh_name(name)
644 pub const TRUE: &str = "true";
645 pub const FALSE: &str = "false";
646 pub const NULL: &str = "null";
649 pub mod pseudo_consts {
650 use lazy_static::lazy_static;
651 use std::collections::HashSet;
653 pub const G__LINE__: &str = "\\__LINE__";
655 pub const G__CLASS__: &str = "\\__CLASS__";
657 pub const G__TRAIT__: &str = "\\__TRAIT__";
659 pub const G__FILE__: &str = "\\__FILE__";
661 pub const G__DIR__: &str = "\\__DIR__";
663 pub const G__FUNCTION__: &str = "\\__FUNCTION__";
665 pub const G__METHOD__: &str = "\\__METHOD__";
667 pub const G__NAMESPACE__: &str = "\\__NAMESPACE__";
669 pub const G__COMPILER_FRONTEND__: &str = "\\__COMPILER_FRONTEND__";
671 pub const G__FUNCTION_CREDENTIAL__: &str = "\\__FUNCTION_CREDENTIAL__";
673 pub const DIE: &str = "\\die";
675 pub const EXIT: &str = "\\exit";
677 pub static ALL_PSEUDO_CONSTS: &[&str] = &[
686 G__COMPILER_FRONTEND__,
687 G__FUNCTION_CREDENTIAL__,
693 static ref PSEUDO_SET: HashSet<&'static str> = ALL_PSEUDO_CONSTS.iter().copied().collect();
696 pub fn is_pseudo_const(x: &str) -> bool {
697 PSEUDO_SET.contains(x)
702 pub const ENUM: &str = "\\Enum";
704 pub const IDX: &str = "\\HH\\idx";
706 pub const TYPE_STRUCTURE: &str = "\\HH\\TypeStructure";
708 pub const INCORRECT_TYPE: &str = "\\HH\\INCORRECT_TYPE";
710 pub const INCORRECT_TYPE_NO_NS: &str = "HH\\INCORRECT_TYPE";
714 pub const CONTAINS: &str = "\\HH\\Lib\\C\\contains";
716 pub const CONTAINS_KEY: &str = "\\HH\\Lib\\C\\contains_key";
720 pub const IS_ENABLED: &str = "\\HH\\Rx\\IS_ENABLED";
723 pub const DEFAULTS: &str = "defaults";
725 pub const RX_LOCAL: &str = "rx_local";
727 pub const RX_SHALLOW: &str = "rx_shallow";
729 pub const RX: &str = "rx";
731 pub const WRITE_PROPS: &str = "write_props";
733 pub const POLICIED_LOCAL: &str = "policied_local";
735 pub const POLICIED_SHALLOW: &str = "policied_shallow";
737 pub const POLICIED: &str = "policied";
739 pub const POLICIED_OF_LOCAL: &str = "policied_of_local";
741 pub const POLICIED_OF_SHALLOW: &str = "policied_of_shallow";
743 pub const POLICIED_OF: &str = "policied_of";
745 pub const PURE: &str = "pure";
749 pub const SHAPES: &str = "\\HH\\Shapes";
751 pub const IDX: &str = "idx";
753 pub const AT: &str = "at";
755 pub const KEY_EXISTS: &str = "keyExists";
757 pub const REMOVE_KEY: &str = "removeKey";
759 pub const TO_ARRAY: &str = "toArray";
761 pub const TO_DICT: &str = "toDict";
764 pub mod superglobals {
765 use lazy_static::lazy_static;
766 use std::collections::HashSet;
767 pub const GLOBALS: &str = "$GLOBALS";
769 pub static SUPERGLOBALS: &[&str] = &[
780 static ref SUPERGLOBALS_SET: HashSet<&'static str> = SUPERGLOBALS.iter().copied().collect();
782 pub fn is_superglobal(x: &str) -> bool {
783 SUPERGLOBALS_SET.contains(x)
785 pub fn is_any_global(x: &str) -> bool {
786 is_superglobal(x) || x == GLOBALS
791 pub const PCDATA: &str = "pcdata";
792 pub const ANY: &str = "any";
793 pub const EMPTY: &str = "empty";
794 pub fn is_reserved(x: &str) -> bool {
795 x == PCDATA || x == ANY || x == EMPTY
797 pub fn is_xhp_category(x: &str) -> bool {
803 pub const T_PATTERN: &str = "\\HH\\Lib\\Regex\\Pattern";
806 pub mod emitter_special_functions {
807 pub const EVAL: &str = "\\eval";
808 pub const SET_FRAME_METADATA: &str = "\\HH\\set_frame_metadata";
809 pub const SYSTEMLIB_REIFIED_GENERICS: &str = "\\__systemlib_reified_generics";
813 pub const NAN: &str = "NAN";
814 pub const INF: &str = "INF";
815 pub const NEG_INF: &str = "-INF";
820 use crate::members::is_special_xhp_attribute;
821 use crate::members::AS_LOWERCASE_SET;
822 use crate::members::UNSUPPORTED_MAP;
823 use crate::special_idents::is_tmp_var;
824 use crate::typehints::is_namespace_with_reserved_hh_name;
827 fn test_special_idents_is_tmp_var() {
828 assert!(!is_tmp_var("_tmp$Blah"));
829 assert!(!is_tmp_var("__tmp$"));
830 assert!(!is_tmp_var("О БОЖЕ"));
832 assert!(is_tmp_var("__tmp$Blah"));
836 fn test_members_as_lowercase_set() {
837 assert!(AS_LOWERCASE_SET.contains("__tostring"));
838 assert!(!AS_LOWERCASE_SET.contains("__toString"));
842 fn test_members_unsupported_map() {
843 assert_eq!(UNSUPPORTED_MAP.get("__callstatic"), Some(&"__callStatic"));
844 assert!(!UNSUPPORTED_MAP.contains_key("__callStatic"));
848 fn test_members_is_special_xhp_attribute() {
849 assert!(is_special_xhp_attribute(":data-blahblah"));
850 assert!(is_special_xhp_attribute(":aria-blahblah"));
852 assert!(!is_special_xhp_attribute(":arla-blahblah"));
853 assert!(!is_special_xhp_attribute(":aria"));
857 fn test_typehint_is_namespace_with_reserved_hh_name() {
858 assert!(!is_namespace_with_reserved_hh_name("HH\\void"));
859 assert!(!is_namespace_with_reserved_hh_name("void"));
860 assert!(!is_namespace_with_reserved_hh_name("ReturnType\\Lloyd"));
861 assert!(!is_namespace_with_reserved_hh_name("Lloyd"));
863 assert!(is_namespace_with_reserved_hh_name("Anything\\Else\\void"));