123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454(*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)openFlow_asttype'locbinding='loc*stringtype'locident='loc*string[@@derivingshow]type'locsource='loc*string[@@derivingshow]letrecfold_bindings_of_pattern=Pattern.(letpropertyfacc=Object.(function|Property(_,{Property.pattern=p;_})|RestElement(_,{RestElement.argument=p;comments=_})->fold_bindings_of_patternfaccp)inletelementfacc=Array.(function|Hole_->acc|Element(_,{Element.argument=p;default=_})|RestElement(_,{RestElement.argument=p;comments=_})->fold_bindings_of_patternfaccp)infunfacc->function|(_,Identifier{Identifier.name;_})->faccname|(_,Object{Object.properties;_})->List.fold_left(propertyf)accproperties|(_,Array{Array.elements;_})->List.fold_left(elementf)accelements(* This is for assignment and default param destructuring `[a.b=1]=c`, ignore these for now. *)|(_,Expression_)->acc)letfold_bindings_of_variable_declarationsfaccdeclarations=letopenFlow_ast.Statement.VariableDeclarationinList.fold_left(funacc->function|(_,{Declarator.id=pattern;_})->lethas_anno=(* Only the toplevel annotation in a pattern is meaningful *)letopenFlow_ast.Patterninmatchpatternwith|(_,Array{Array.annot=Flow_ast.Type.Available_;_})|(_,Object{Object.annot=Flow_ast.Type.Available_;_})|(_,Identifier{Identifier.annot=Flow_ast.Type.Available_;_})->true|_->falseinfold_bindings_of_pattern(fhas_anno)accpattern)accdeclarationsletrecpattern_has_binding=letopenPatterninletproperty=letopenObjectinfunction|Property(_,{Property.pattern=p;_})|RestElement(_,{RestElement.argument=p;comments=_})->pattern_has_bindingpinletelement=letopenArrayinfunction|Hole_->false|Element(_,{Element.argument=p;default=_})|RestElement(_,{RestElement.argument=p;comments=_})->pattern_has_bindingpinfunction|(_,Identifier_)->true|(_,Object{Object.properties;_})->List.existspropertyproperties|(_,Array{Array.elements;_})->List.existselementelements|(_,Expression_)->falseletpartition_directivesstatements=letopenFlow_ast.Statementinletrechelperdirectives=function|((_,Expression{Expression.directive=Some_;_})asdirective)::rest->helper(directive::directives)rest|rest->(List.revdirectives,rest)inhelper[]statementslethoist_function_and_component_declarationsstmts=letopenFlow_ast.Statementinlet(func_and_component_decs,other_stmts)=List.partition(function(* function f() {} / component F() {} *)|(_,(FunctionDeclaration{Flow_ast.Function.id=Some_;_}|ComponentDeclaration_))(* export function f() {} / export component F() {} *)|(_,ExportNamedDeclaration{ExportNamedDeclaration.declaration=Some(_,(FunctionDeclaration{Flow_ast.Function.id=Some_;_}|ComponentDeclaration_));_;})(* export default function f() {} / export default component F() {} *)|(_,ExportDefaultDeclaration{ExportDefaultDeclaration.declaration=ExportDefaultDeclaration.Declaration(_,(FunctionDeclaration{Flow_ast.Function.id=Some_;_}|ComponentDeclaration_));_;})(* TODO(jmbrown): Hoist declared components *)(* declare function f(): void; *)|(_,DeclareFunction_)(* declare export function f(): void; *)|(_,DeclareExportDeclarationDeclareExportDeclaration.{declaration=Some(Function_);_})->true|_->false)stmtsinfunc_and_component_decs@other_stmtsletnegate_raw_litraw=letraw_len=String.lengthrawinifraw_len>0&&raw.[0]='-'thenString.subraw1(raw_len-1)else"-"^rawletnegate_number_literal(value,raw)=(~-.value,negate_raw_litraw)letnegate_bigint_literal(value,raw)=matchvaluewith|None->(None,raw)|Somevalue->(Some(Int64.negvalue),negate_raw_litraw)letis_call_to_invariantcallee=matchcalleewith|(_,Expression.Identifier(_,{Identifier.name="invariant";_}))->true|_->falseletis_call_to_is_arraycallee=matchcalleewith|(_,Flow_ast.Expression.Member{Flow_ast.Expression.Member._object=(_,Flow_ast.Expression.Identifier(_,{Flow_ast.Identifier.name="Array";comments=_}));property=Flow_ast.Expression.Member.PropertyIdentifier(_,{Flow_ast.Identifier.name="isArray";comments=_});comments=_;})->true|_->falseletis_call_to_object_dot_freezecallee=matchcalleewith|(_,Flow_ast.Expression.Member{Flow_ast.Expression.Member._object=(_,Flow_ast.Expression.Identifier(_,{Flow_ast.Identifier.name="Object";comments=_}));property=Flow_ast.Expression.Member.PropertyIdentifier(_,{Flow_ast.Identifier.name="freeze";comments=_});comments=_;})->true|_->falseletis_call_to_object_static_methodcallee=matchcalleewith|(_,Flow_ast.Expression.Member{Flow_ast.Expression.Member._object=(_,Flow_ast.Expression.Identifier(_,{Flow_ast.Identifier.name="Object";comments=_}));property=Flow_ast.Expression.Member.PropertyIdentifier_;comments=_;})->true|_->falseletis_super_member_access=function|{Flow_ast.Expression.Member._object=(_,Flow_ast.Expression.Super_);_}->true|_->falseletloc_of_statement=fstletloc_of_expression=fstletloc_of_pattern=fstletloc_of_ident=fstletname_of_ident(_,{Identifier.name;comments=_})=nameletsource_of_ident(loc,{Identifier.name;comments=_})=(loc,name)letident_of_source?comments(loc,name)=(loc,{Identifier.name;comments})letmk_comments?(leading=[])?(trailing=[])a={Syntax.leading;trailing;internal=a}letmk_comments_opt?(leading=[])?(trailing=[])()=match(leading,trailing)with|([],[])->None|(_,_)->Some(mk_comments~leading~trailing())letmk_comments_with_internal_opt?(leading=[])?(trailing=[])~internal()=match(leading,trailing,internal)with|([],[],[])->None|_->Some(mk_comments~leading~trailinginternal)letmerge_comments~inner~outer=letopenSyntaxinmatch(inner,outer)with|(None,c)|(c,None)->c|(Someinner,Someouter)->mk_comments_opt~leading:(outer.leading@inner.leading)~trailing:(inner.trailing@outer.trailing)()letmerge_comments_with_internal~inner~outer=match(inner,outer)with|(inner,None)->inner|(None,Some{Syntax.leading;trailing;_})->mk_comments_with_internal_opt~leading~trailing~internal:[]()|(Some{Syntax.leading=inner_leading;trailing=inner_trailing;internal},Some{Syntax.leading=outer_leading;trailing=outer_trailing;_})->mk_comments_with_internal_opt~leading:(outer_leading@inner_leading)~trailing:(inner_trailing@outer_trailing)~internal()letsplit_commentscomments=matchcommentswith|None->(None,None)|Some{Syntax.leading;trailing;_}->(mk_comments_opt~leading(),mk_comments_opt~trailing())letstring_of_assignment_operatorop=letopenFlow_ast.Expression.Assignmentinmatchopwith|PlusAssign->"+="|MinusAssign->"-="|MultAssign->"*="|ExpAssign->"**="|DivAssign->"/="|ModAssign->"%="|LShiftAssign->"<<="|RShiftAssign->">>="|RShift3Assign->">>>="|BitOrAssign->"|="|BitXorAssign->"^="|BitAndAssign->"&="|NullishAssign->"??="|AndAssign->"&&="|OrAssign->"||="letstring_of_binary_operatorop=letopenFlow_ast.Expression.Binaryinmatchopwith|Equal->"=="|NotEqual->"!="|StrictEqual->"==="|StrictNotEqual->"!=="|LessThan->"<"|LessThanEqual->"<="|GreaterThan->">"|GreaterThanEqual->">="|LShift->"<<"|RShift->">>"|RShift3->">>>"|Plus->"+"|Minus->"-"|Mult->"*"|Exp->"**"|Div->"/"|Mod->"%"|BitOr->"|"|Xor->"^"|BitAnd->"&"|In->"in"|Instanceof->"instanceof"moduleExpressionSort=structtypet=|Array|ArrowFunction|Assignment|Binary|Call|Class|Conditional|Function|Identifier|Import|JSXElement|JSXFragment|Literal|Logical|Member|MetaProperty|New|Object|OptionalCall|OptionalMember|Sequence|Super|TaggedTemplate|TemplateLiteral|This|TypeCast|Unary|Update|Yield[@@derivingshow]letto_string=function|Array->"array"|ArrowFunction->"arrow function"|Assignment->"assignment expression"|Binary->"binary expression"|Call->"call expression"|Class->"class"|Conditional->"conditional expression"|Function->"function"|Identifier->"identifier"|Import->"import expression"|JSXElement->"JSX element"|JSXFragment->"JSX fragment"|Literal->"literal"|Logical->"logical expression"|Member->"member expression"|MetaProperty->"metaproperty expression"|New->"new expression"|Object->"object"|OptionalCall->"optional call expression"|OptionalMember->"optional member expression"|Sequence->"sequence"|Super->"`super` reference"|TaggedTemplate->"tagged template expression"|TemplateLiteral->"template literal"|This->"`this` reference"|TypeCast->"type cast"|Unary->"unary expression"|Update->"update expression"|Yield->"yield expression"endletloc_of_annotation_or_hint=letopenFlow_ast.Typeinfunction|Missingloc|Available(_,(loc,_))->locletloc_of_return_annot=letopenFlow_ast.Function.ReturnAnnotinfunction|Missingloc|Available(_,(loc,_))|TypeGuard(loc,_)->loc(* Apply type [t] at the toplevel of expression [exp]. This is straightforward overall
* except for the case of Identifier and Member, where we push the type within the
* identifier and member property type position as well. This is to ensure that
* type-at-pos searcher will detect the updated type. *)letpush_toplevel_typetexp=letopenFlow_ast.Expressioninletpush_toplevel_identifierid=let((id_loc,_),id)=idin((id_loc,t),id)inletpush_to_membermem=matchmemwith|{Member.property=Member.PropertyIdentifierid;_}->{memwithMember.property=Member.PropertyIdentifier(push_toplevel_identifierid)}|p->pinlet((loc,_),e)=expinlete'=matchewith|Identifierid->Identifier(push_toplevel_identifierid)|Membermember->Member(push_to_membermember)|OptionalMember({OptionalMember.member;_}asomem)->OptionalMember{omemwithOptionalMember.member=push_to_membermember}|_->ein((loc,t),e')lethook_names=letis_A_to_Zc=c>='A'&&c<='Z'inString.starts_with~prefix:"use"s&&(String.lengths=3||is_A_to_Zs.[3])lethook_function{Flow_ast.Function.id;_}=matchidwith|Some(loc,{Flow_ast.Identifier.name;_})whenhook_namename->Someloc|_->Nonelethook_call{Flow_ast.Expression.Call.callee;_}=(* A.B.C.useFoo() is a hook, A().useFoo() is not *)letopenFlow_ast.Expressioninletrechook_calleetopexp=matchexpwith|(_,Identifier(_,{Flow_ast.Identifier.name;_}))->hook_namename||nottop|(_,Member{Member._object;property=Member.PropertyIdentifier(_,{Flow_ast.Identifier.name;_});_;})->(hook_namename||nottop)&&hook_calleefalse_object|_->falseinhook_calleetruecallee