Source file browse_tree.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
open Std
let default_loc = Location.none
let default_env = Env.empty
type t =
{ t_node : Mbrowse.node;
t_loc : Location.t;
t_env : Env.t;
t_children : t list lazy_t
}
let of_node ?(env = default_env) node =
let rec one t_env t_node =
let t_loc = Mbrowse.node_loc t_node in
let rec t = { t_node; t_env; t_loc; t_children = lazy (aux t) } in
t
and aux t =
Mbrowse.fold_node
(fun env node acc -> one env node :: acc)
t.t_env t.t_node []
in
one (Browse_raw.node_update_env env node) node
let of_browse b =
let env, node = Mbrowse.leaf_node b in
of_node ~env node
let dummy =
{ t_node = Browse_raw.Dummy;
t_loc = default_loc;
t_env = default_env;
t_children = lazy []
}
let rec normalize_type_expr env type_expr =
match Types.get_desc type_expr with
| Types.Tconstr (path, _, _) ->
normalize_type_decl env (Env.find_type path env)
| _ -> raise Not_found
and normalize_type_decl env decl =
match decl.Types.type_manifest with
| Some expr -> normalize_type_expr env expr
| None -> decl
let id_of_constr_decl c = `Id c.Types.cd_id
let same_constructor env a b =
let name = function
| `Description d -> d.Types.cstr_name
| `Declaration d -> Ident.name d.Typedtree.cd_id
| `Extension_constructor ec -> Ident.name ec.Typedtree.ext_id
in
if name a <> name b then false
else begin
let get_decls = function
| `Description d ->
let ty = normalize_type_expr env d.Types.cstr_res in
begin
match ty.Types.type_kind with
| Types.Type_variant (decls, _) -> List.map decls ~f:id_of_constr_decl
| Type_open -> [ `Uid d.cstr_uid ]
| _ -> assert false
end
| `Declaration d -> [ `Id d.Typedtree.cd_id ]
| `Extension_constructor ext_cons ->
let des = Env.find_ident_constructor ext_cons.Typedtree.ext_id env in
[ `Uid des.cstr_uid ]
in
let a = get_decls a in
let b = get_decls b in
let same a b =
match (a, b) with
| `Id a, `Id b -> Ident.same a b
| `Uid a, `Uid b -> Shape.Uid.equal a b
| _, _ -> false
in
List.exists a ~f:(fun id -> List.exists b ~f:(same id))
end
let all_occurrences path =
let rec aux acc t =
let acc =
let paths = Browse_raw.node_paths t.t_node in
let same l = Path.same path l.Location.txt in
match List.filter ~f:same paths with
| [] -> acc
| paths -> (t, paths) :: acc
in
if Browse_raw.has_attr ~name:"merlin.hide" t.t_node then acc
else List.fold_left ~f:aux ~init:acc (Lazy.force t.t_children)
in
aux []
let all_constructor_occurrences ({ t_env = env; _ }, d) t =
let rec aux acc t =
let acc =
match Browse_raw.node_is_constructor t.t_node with
| Some d'
when
try same_constructor env d d'.Location.txt
with Not_found -> same_constructor t.t_env d d'.Location.txt ->
{ d' with Location.txt = t } :: acc
| _ -> acc
in
if Browse_raw.has_attr ~name:"merlin.hide" t.t_node then acc
else List.fold_left ~f:aux ~init:acc (Lazy.force t.t_children)
in
aux [] t
let all_occurrences_of_prefix path node =
let rec path_prefix ~prefix path =
Path.same prefix path
||
match path with
| Pdot (p, _) -> path_prefix ~prefix p
| _ -> false
in
let rec aux env node acc =
let acc =
let paths_and_lids = Browse_raw.node_paths_and_longident node in
let has_prefix ({ Location.txt; _ }, _) =
match txt with
| Path.Pdot (p, _) -> path_prefix ~prefix:path p
| _ -> false
in
List.fold_right paths_and_lids ~init:acc ~f:(fun elt acc ->
if has_prefix elt then elt :: acc else acc)
in
Browse_raw.fold_node aux env node acc
in
aux Env.empty node []