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.
13 (* Given a Ast.program, give me the list of entities it defines *)
15 (* fold_right traverses the file from top to bottom, and as such gives nicer
16 * error messages than fold_left. E.g. in the case where a function is
17 * declared twice in the same file, the error will say that the declaration
18 * with the larger line number is a duplicate. *)
19 let rec get_defs ast acc
=
20 List.fold_right ast ~init
:acc
21 ~f
:(fun def
((acc1
, acc2
, acc3
, acc4
) as acc
) ->
24 (FileInfo.pos_full f
.Ast.f_name
:: acc1
, acc2
, acc3
, acc4
)
26 (acc1
, FileInfo.pos_full c
.Ast.c_name
:: acc2
, acc3
, acc4
)
28 (acc1
, acc2
, FileInfo.pos_full t
.Ast.t_id
:: acc3
, acc4
)
30 (acc1
, acc2
, acc3
, FileInfo.pos_full cst
.Ast.cst_name
:: acc4
)
31 | Ast.Namespace
(_
, defs
) -> get_defs defs acc
32 | Ast.NamespaceUse _
| Ast.SetNamespaceEnv _
-> acc
33 (* toplevel statements are ignored *)
34 | Ast.FileAttributes _
| Ast.Stmt _
-> acc
)
36 get_defs ast
([], [], [], [])
38 (* Utility functions for getting all nodes of a particular type *)
39 class ast_get_defs_visitor
=
41 inherit [Ast.def list
] Ast_visitor.ast_visitor
43 method! on_def acc def
= def
:: acc
46 let ast_no_pos_or_docblock_mapper =
48 inherit [_
] Ast.endo
as super
50 method! private on_pos
() _pos
= Pos.none
52 method! on_fun_ env f
= super#on_fun_ env
{ f
with f_doc_comment
= None
}
54 method! on_class_ env c
=
55 super#on_class_ env
{ c
with c_doc_comment
= None
}
57 method! on_class_vars_ env cv
=
58 super#on_class_vars_ env
{ cv
with cv_doc_comment
= None
}
60 method! on_method_ env m
=
61 super#on_method_ env
{ m
with m_doc_comment
= None
}
63 (* Skip all blocks because we don't care about method bodies *)
64 method! on_block env _
=
65 self#on_list self#on_stmt env
[(Pos.none
, Ast.Noop
)]
68 (* Given an AST, return an AST with no position or docblock info *)
69 let remove_pos_and_docblock ast
=
70 ast_no_pos_or_docblock_mapper#on_program
() ast
72 type ignore_attribute_env
= { ignored_attributes
: string list
}
74 let ast_deregister_attributes_mapper =
76 inherit [_
] Ast.endo
as super
78 method ignored_attr env l
=
79 List.exists l
(fun attr
->
80 List.mem env
.ignored_attributes
(snd attr
.ua_name
) ~equal
:( = ))
82 (* Filter all functions and classes with the user attributes banned *)
83 method! on_program env toplevels
=
85 List.filter
toplevels (fun toplevel
->
87 | Fun f
when self#ignored_attr env f
.f_user_attributes
-> false
88 | Class c
when self#ignored_attr env c
.c_user_attributes
-> false
91 super#on_program env
toplevels
93 method! on_class_ env this
=
94 (* Filter out class elements which are methods with wrong attributes *)
95 let body = this
.c_body
in
97 List.filter
body (fun elt
->
99 | Method m
when self#ignored_attr env m
.m_user_attributes
-> false
100 | ClassVars cv
when self#ignored_attr env cv
.cv_user_attributes
->
104 let this = { this with c_body
= body } in
105 super#on_class_ env
this
108 let deregister_ignored_attributes ast
=
111 (* For now, only ignore the __PHPStdLib *)
112 ignored_attributes
= [Naming_special_names.UserAttributes.uaPHPStdLib
];
115 ast_deregister_attributes_mapper#on_program
env ast
117 (* Given an AST, generate a unique hash for its decl tree. *)
118 let generate_ast_decl_hash ast
=
119 (* Why we marshal it into a string first: regular Hashtbl.hash will
120 collide improperly because it doesn't compare ADTs with strings correctly.
121 Using Marshal, we guarantee that the two ASTs are represented by a single
122 primitive type, which we hash.
124 let str = Marshal.to_string
(remove_pos_and_docblock ast
) [] in
125 OpaqueDigest.string str
127 let get_def_nodes ast
= List.rev
((new ast_get_defs_visitor
)#on_program
[] ast
)
129 class ast_get_class_elts_visitor
=
131 inherit [Ast.class_elt list
] Ast_visitor.ast_visitor
133 method! on_class_elt acc elt
= elt
:: acc
136 let get_class_elts ast
=
137 List.rev
((new ast_get_class_elts_visitor
)#on_program
[] ast
)
139 (* Helpers for XHP attributes *)
140 let map_xhp_attr (f
: id
-> id
) (g
: expr
-> expr
) = function
141 | Xhp_simple
(id
, e
) -> Xhp_simple
(f id
, g e
)
142 | Xhp_spread e
-> Xhp_spread
(g e
)