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.
11 open Reordered_argument_collections
13 module Parser
= Full_fidelity_ast
15 let modifiers_of_ast_kinds l
=
16 List.map l
begin function
18 | Ast.Static
-> Static
19 | Ast.Abstract
-> Abstract
20 | Ast.Private
-> Private
21 | Ast.Public
-> Public
22 | Ast.Protected
-> Protected
25 let get_full_name class_name name
=
28 | Some class_name
-> class_name ^
"::" ^ name
30 let summarize_property class_name kinds var
=
31 let modifiers = modifiers_of_ast_kinds kinds
in
32 let span, (pos
, name
), _expr_opt
= var
in
33 let kind = Property
in
34 let id = get_symbol_id
kind (Some class_name
) name
in
35 let full_name = get_full_name (Some class_name
) name
in
49 let maybe_summarize_property class_name ~skip kinds var
=
50 let _, (_, name
), _ = var
in
51 if SSet.mem skip name
then [] else [summarize_property class_name kinds var
]
53 let summarize_const class_name
((pos
, name
), (expr_pos
, _)) =
54 let span = (Pos.btw pos expr_pos
) in
56 let id = get_symbol_id
kind (Some class_name
) name
in
57 let full_name = get_full_name (Some class_name
) name
in
71 let summarize_abs_const class_name
(pos
, name
) =
73 let id = get_symbol_id
kind (Some class_name
) name
in
74 let full_name = get_full_name (Some class_name
) name
in
82 modifiers = [Abstract
];
88 let modifier_of_fun_kind acc
= function
89 | Ast.FAsync
| Ast.FAsyncGenerator
-> Async
:: acc
92 let modifier_of_param_kind acc
= function
93 | Some
Ast.Pinout
-> Inout
:: acc
96 let summarize_typeconst class_name t
=
97 let pos, name
= t
.Ast.tconst_name
in
98 let kind = Typeconst
in
99 let id = get_symbol_id
kind (Some class_name
) name
in
100 let full_name = get_full_name (Some class_name
) name
in
107 span = t
.Ast.tconst_span
;
108 modifiers = if t
.Ast.tconst_abstract
then [Abstract
] else [];
114 let summarize_param param
=
115 let pos, name
= param
.Ast.param_id
in
116 let param_start = Option.value_map param
.Ast.param_hint ~f
:fst ~default
:pos in
117 let param_end = Option.value_map param
.Ast.param_expr ~f
:fst ~default
:pos in
118 let modifiers = modifier_of_param_kind [] param
.Ast.param_callconv
in
119 let param_vis = Option.to_list param
.Ast.param_modifier
in
120 let modifiers = (modifiers_of_ast_kinds param_vis) @ modifiers in
122 let id = get_symbol_id
kind None name
in
123 let full_name = get_full_name None name
in
130 span = Pos.btw
param_start param_end;
137 let summarize_method class_name m
=
138 let modifiers = modifier_of_fun_kind [] m
.Ast.m_fun_kind
in
139 let modifiers = (modifiers_of_ast_kinds m
.Ast.m_kind
) @ modifiers in
140 let params = Some
(List.map m
.Ast.m_params
summarize_param) in
141 let name = snd m
.Ast.m_name
in
143 let id = get_symbol_id
kind (Some class_name
) name in
144 let full_name = get_full_name (Some class_name
) name in
150 pos = (fst m
.Ast.m_name
);
158 (* Parser synthesizes AST nodes for implicit properties (defined in constructor
159 * parameter lists. We don't want them to show up in outline view *)
160 let params_implicit_fields params =
161 List.filter_map
params ~f
:begin function
162 | { Ast.param_modifier
= Some _vis
; param_id
; _ } ->
163 Some
(String_utils.lstrip
(snd param_id
) "$" )
167 let class_implicit_fields class_
=
168 List.concat_map class_
.Ast.c_body ~f
:begin function
169 | Ast.Method
{ Ast.m_name
= _, "__construct"; m_params
; _ } ->
170 params_implicit_fields m_params
174 let summarize_class class_ ~no_children
=
175 let class_name = Utils.strip_ns
(snd class_
.Ast.c_name
) in
176 let class_name_pos = fst class_
.Ast.c_name
in
177 let c_span = class_
.Ast.c_span in
179 if class_
.Ast.c_final
then [Final
] else []
181 let modifiers = match class_
.Ast.c_kind
with
182 | Ast.Cabstract
-> Abstract
:: modifiers
185 let children = if no_children
then None
else begin
186 let implicit_props = List.fold
(class_implicit_fields class_
)
187 ~f
:SSet.add ~init
:SSet.empty
189 Some
(List.concat_map class_
.Ast.c_body ~f
:begin function
190 | Ast.Method m
-> [summarize_method class_name m
]
191 | Ast.ClassVars
{ Ast.cv_kinds
= kinds
; Ast.cv_names
= vars
; _ } ->
193 ~f
:(maybe_summarize_property class_name ~skip
:implicit_props kinds
)
194 | Ast.XhpAttr
(_, var
, _, _) ->
195 maybe_summarize_property class_name ~skip
:implicit_props [] var
196 | Ast.Const
(_, cl
) -> List.map cl ~f
:(summarize_const class_name)
197 | Ast.AbsConst
(_, id) -> [summarize_abs_const class_name id]
198 | Ast.TypeConst t
-> [summarize_typeconst class_name t
]
202 let kind = match class_
.Ast.c_kind
with
203 | Ast.Cinterface
-> Interface
204 | Ast.Ctrait
-> Trait
208 let name = class_name in
209 let id = get_symbol_id
kind None
name in
210 let full_name = get_full_name None
name in
216 pos = class_name_pos;
224 let typedef_kind_pos tk
=
226 | Ast.Alias
(pos,_) -> pos
227 | Ast.NewType
(pos,_) -> pos
230 let summarize_typedef tdef
=
231 let kind = Typedef
in
232 let name = Utils.strip_ns
(snd tdef
.Ast.t_id
) in
233 let id = get_symbol_id
kind None
name in
234 let full_name = get_full_name None
name in
235 let pos = fst tdef
.Ast.t_id
in
236 let kind_pos = typedef_kind_pos tdef
.Ast.t_kind
in
237 let span = (Pos.btw
pos kind_pos) in
251 let summarize_fun f
=
252 let modifiers = modifier_of_fun_kind [] f
.Ast.f_fun_kind
in
253 let params = Some
(List.map f
.Ast.f_params
summarize_param) in
254 let kind = Function
in
255 let name = Utils.strip_ns
(snd f
.Ast.f_name
) in
256 let id = get_symbol_id
kind None
name in
257 let full_name = get_full_name None
name in
263 pos = fst f
.Ast.f_name
;
271 let summarize_gconst cst
=
272 let pos = fst cst
.Ast.cst_name
in
273 let gconst_start = Option.value_map cst
.Ast.cst_type ~f
:fst ~default
:pos in
274 let gconst_end = fst cst
.Ast.cst_value
in
276 let name = Utils.strip_ns
(snd cst
.Ast.cst_name
) in
277 let id = get_symbol_id
kind None
name in
278 let full_name = get_full_name None
name in
285 span = Pos.btw
gconst_start gconst_end;
292 let summarize_local name span =
293 let kind = LocalVar
in
294 let id = get_symbol_id
kind None
name in
295 let full_name = get_full_name None
name in
309 let outline_ast ast
=
310 let outline = List.filter_map ast ~f
:begin function
311 | Ast.Fun f
-> Some
(summarize_fun f
)
312 | Ast.Class c
-> Some
(summarize_class c ~no_children
:false)
315 List.map
outline SymbolDefinition.to_absolute
317 let should_add_docblock = function
318 | Function
| Class
| Method
| Property
| Const
| Enum
319 | Interface
| Trait
| Typeconst
| Typedef
-> true
320 | LocalVar
| Param
-> false
322 let add_def_docblock finder previous_def_line def
=
323 let line = Pos.line def
.pos in
324 let docblock = if should_add_docblock def
.kind
325 then Docblock_finder.find_docblock finder previous_def_line
line
328 line, { def
with docblock }
330 let add_docblocks defs comments
=
331 let finder = Docblock_finder.make_docblock_finder comments
in
333 let rec map_def f
(acc
: int) (def
: string SymbolDefinition.t
) =
334 let acc, def
= f
acc def
in
335 let acc, children = Option.value_map def
.children
337 let acc, defs
= map_def_list f
acc defs
in
341 acc, { def
with children }
343 and map_def_list f
(acc : int) (defs
: string SymbolDefinition.t list
) =
344 let acc, defs
= List.fold_left defs
345 ~f
:(fun (acc, defs
) def
->
346 let acc, def
= map_def f
acc def
in
352 snd
(map_def_list
(add_def_docblock finder) 0 defs
)
354 let outline popt content
=
355 let env = Parser.make_env
357 ~include_line_comments
:true
359 Relative_path.default
361 let {Parser_hack.ast
; comments
; _} = Parser.from_text_with_legacy
env content
in
362 let result = outline_ast ast
in
363 add_docblocks result comments
365 let rec print_def ~short_pos indent def
=
367 {name; kind; id; pos; span; modifiers; children; params; docblock;
370 let print_pos, print_span
= if short_pos
371 then Pos.string_no_file
, Pos.multiline_string_no_file
372 else Pos.string, Pos.multiline_string
374 Printf.printf
"%s%s\n" indent
name;
375 Printf.printf
"%s kind: %s\n" indent
(string_of_kind
kind);
376 Option.iter
id (fun id -> Printf.printf
"%s id: %s\n" indent
id);
377 Printf.printf
"%s position: %s\n" indent
(print_pos pos);
378 Printf.printf
"%s span: %s\n" indent
(print_span
span);
379 Printf.printf
"%s modifiers: " indent
;
381 (fun x
-> Printf.printf
"%s " (string_of_modifier x
));
383 Option.iter
params (fun x
->
384 Printf.printf
"%s params:\n" indent
;
385 print ~short_pos
(indent ^
" ") x
;
387 Option.iter
docblock (fun x
->
388 Printf.printf
"%s docblock:\n" indent
;
389 Printf.printf
"%s\n" x
;
392 Option.iter
children (fun x
->
393 print ~short_pos
(indent ^
" ") x
396 and print ~short_pos indent defs
=
397 List.iter defs ~f
:(print_def ~short_pos indent
)
399 let print_def ?short_pos
:(short_pos
= false) = print_def ~short_pos
400 let print ?short_pos
:(short_pos
= false) = print ~short_pos
""