this repo has no description
1#if OCAML_VERSION >= (4, 14, 0)
2
3let rec is_persistent : Path.t -> bool = function
4 | Path.Pident id -> Ident_env.ident_is_global_or_predef id
5 | Path.Pdot(p, _) -> is_persistent p
6 | Path.Papply(p, _) -> is_persistent p
7#if OCAML_VERSION >= (5,1,0)
8 | Path.Pextra_ty (p, _) -> is_persistent p
9#endif
10
11let pos_of_loc (loc : Warnings.loc) = {
12 Odoc_model.Lang.Source_info.loc_start = {
13 pos_cnum = loc.loc_start.pos_cnum ;
14 pos_lnum = loc.loc_start.pos_lnum
15 } ;
16 loc_end = {
17 pos_cnum = loc.loc_start.pos_cnum ;
18 pos_lnum = loc.loc_start.pos_lnum
19 }
20}
21
22let counter =
23 let c = ref 0 in
24 fun () ->
25 incr c;
26 !c
27
28module Env = struct
29 open Typedtree
30 open Odoc_model.Paths
31
32 let rec structure env parent str =
33 let env' = Ident_env.add_structure_tree_items parent str env in
34 List.iter (structure_item env' parent) str.str_items
35
36 and signature env parent sg =
37 let env' = Ident_env.add_signature_tree_items parent sg env in
38 List.iter (signature_item env' parent) sg.sig_items
39
40 and signature_item env parent item =
41 match item.sig_desc with
42 | Tsig_module mb -> module_declaration env parent mb
43 | Tsig_recmodule mbs -> module_declarations env parent mbs
44 | Tsig_modtype mtd -> module_type_declaration env parent mtd
45 | Tsig_modtypesubst mtd -> module_type_declaration env parent mtd
46 | Tsig_value _ | Tsig_type _ | Tsig_typesubst _ | Tsig_typext _
47 | Tsig_exception _ | Tsig_modsubst _ | Tsig_open _ | Tsig_include _
48 | Tsig_class _ | Tsig_class_type _ | Tsig_attribute _ ->
49 ()
50
51 and module_declaration env _parent md =
52 match md.md_id with
53 | None -> ()
54 | Some mb_id ->
55 let id = Ident_env.find_module_identifier env mb_id in
56 module_type env (id :> Identifier.Signature.t) md.md_type
57
58 and module_declarations env parent mds =
59 List.iter (module_declaration env parent) mds
60
61 and module_type_declaration env _parent mtd =
62 let id = Ident_env.find_module_type env mtd.mtd_id in
63 match mtd.mtd_type with
64 | None -> ()
65 | Some mty -> module_type env (id :> Identifier.Signature.t) mty
66
67 and structure_item env parent item =
68 match item.str_desc with
69 | Tstr_module mb -> module_binding env parent mb
70 | Tstr_recmodule mbs -> module_bindings env parent mbs
71 | Tstr_modtype mtd -> module_type_declaration env parent mtd
72 | Tstr_open _ | Tstr_value _ | Tstr_class _ | Tstr_eval _
73 | Tstr_class_type _ | Tstr_include _ | Tstr_attribute _ | Tstr_primitive _
74 | Tstr_type _ | Tstr_typext _ | Tstr_exception _ ->
75 ()
76
77 and module_type env (parent : Identifier.Signature.t) mty =
78 match mty.mty_desc with
79 | Tmty_signature sg -> signature env (parent : Identifier.Signature.t) sg
80 | Tmty_with (mty, _) -> module_type env parent mty
81 | Tmty_functor (_, t) -> module_type env parent t
82#if defined OXCAML
83 | Tmty_strengthen (t, _, _) -> module_type env parent t
84#endif
85 | Tmty_ident _ | Tmty_alias _ | Tmty_typeof _ -> ()
86
87 and module_bindings env parent mbs = List.iter (module_binding env parent) mbs
88
89 and module_binding env _parent mb =
90 match mb.mb_id with
91 | None -> ()
92 | Some id ->
93 let id = Ident_env.find_module_identifier env id in
94 let id = (id :> Identifier.Module.t) in
95 let inner =
96 match unwrap_module_expr_desc mb.mb_expr.mod_desc with
97 | Tmod_ident (_p, _) -> ()
98 | _ ->
99 let id = (id :> Identifier.Signature.t) in
100 module_expr env id mb.mb_expr
101 in
102 inner
103
104 and module_expr env parent mexpr =
105 match mexpr.mod_desc with
106 | Tmod_ident _ -> ()
107 | Tmod_structure str -> structure env parent str
108 | Tmod_functor (parameter, res) ->
109 let open Odoc_model.Names in
110 let env =
111 match parameter with
112 | Unit -> env
113 | Named (id_opt, _, arg) -> (
114 match id_opt with
115 | Some id ->
116 let env =
117 Ident_env.add_parameter parent id (ModuleName.of_ident id)
118 env
119 in
120 let id = Ident_env.find_module_identifier env id in
121 module_type env (id :> Identifier.Signature.t) arg;
122 env
123 | None -> env)
124 in
125 module_expr env (Odoc_model.Paths.Identifier.Mk.result parent) res
126 | Tmod_constraint (me, _, constr, _) ->
127 let () =
128 match constr with
129 | Tmodtype_implicit -> ()
130 | Tmodtype_explicit mt -> module_type env parent mt
131 in
132 module_expr env parent me
133 | _ -> ()
134
135 and unwrap_module_expr_desc = function
136 | Tmod_constraint (mexpr, _, Tmodtype_implicit, _) ->
137 unwrap_module_expr_desc mexpr.mod_desc
138 | desc -> desc
139
140 let of_structure (id : Odoc_model.Paths.Identifier.RootModule.t)
141 (s : Typedtree.structure) =
142 let env = Ident_env.empty () in
143 let () = structure env (id :> Odoc_model.Paths.Identifier.Signature.t) s in
144 env
145end
146
147module LocHashtbl = Hashtbl.Make (struct
148 type t = Location.t
149 let equal l1 l2 = l1 = l2
150 let hash = Hashtbl.hash
151end)
152
153module IdentHashtbl = Hashtbl.Make (struct
154 type t = Ident.t
155 let equal l1 l2 = l1 = l2
156 let hash = Hashtbl.hash
157end)
158
159module AnnotHashtbl = Hashtbl.Make (struct
160 type t =
161 Odoc_model.Lang.Source_info.annotation Odoc_model.Lang.Source_info.with_pos
162 let equal l1 l2 = l1 = l2
163 let hash = Hashtbl.hash
164end)
165
166module UidHashtbl = Shape.Uid.Tbl
167
168(* Adds the local definitions found in traverse infos to the [loc_to_id] and
169 [ident_to_id] tables. *)
170let populate_local_defs source_id poses loc_to_id local_ident_to_loc =
171 List.iter
172 (function
173 | Typedtree_traverse.Analysis.LocalDefinition id, loc ->
174 let name =
175 Odoc_model.Names.LocalName.make_std
176 (Printf.sprintf "local_%s_%d" (Ident.name id) (counter ()))
177 in
178 let identifier =
179 Odoc_model.Paths.Identifier.Mk.source_location_int (source_id, name)
180 in
181 LocHashtbl.add loc_to_id loc identifier;
182 IdentHashtbl.add local_ident_to_loc id loc
183 | _ -> ())
184 poses
185
186(* In order to turn an identifier into a source identifier, we need to generate
187 a unique anchor for any identifier. *)
188let anchor_of_identifier id =
189 let open Odoc_document.Url in
190 let open Odoc_model.Paths in
191 let open Odoc_model.Names in
192 let rec anchor_of_identifier acc (id : Identifier.t) =
193 let continue anchor parent =
194 anchor_of_identifier (anchor :: acc) (parent :> Identifier.t)
195 in
196 let anchor kind name =
197 Printf.sprintf "%s-%s" (Anchor.string_of_kind kind) name
198 in
199 match id.iv with
200 | `InstanceVariable (parent, name) ->
201 let anchor = anchor `Val (InstanceVariableName.to_string name) in
202 continue anchor parent
203 | `Parameter (parent, name) as iv ->
204 let arg_num =
205 Identifier.FunctorParameter.functor_arg_pos { id with iv }
206 in
207 let kind = `Parameter arg_num in
208 let anchor = anchor kind (ModuleName.to_string name) in
209 continue anchor parent
210 | `Module (parent, name) ->
211 let anchor = anchor `Module (ModuleName.to_string name) in
212 continue anchor parent
213 | `ModuleType (parent, name) ->
214 let anchor = anchor `ModuleType (ModuleTypeName.to_string name) in
215 continue anchor parent
216 | `Method (parent, name) ->
217 let anchor = anchor `Method (MethodName.to_string name) in
218 continue anchor parent
219 | `AssetFile _ -> assert false
220 | `Field (parent, name) ->
221 let anchor = anchor `Field (FieldName.to_string name) in
222 continue anchor parent
223 | `UnboxedField (parent, name) ->
224 let anchor = anchor `UnboxedField (UnboxedFieldName.to_string name) in
225 continue anchor parent
226 | `SourceLocationMod _ -> assert false
227 | `Result parent -> anchor_of_identifier acc (parent :> Identifier.t)
228 | `SourceLocationInternal _ -> assert false
229 | `Type (parent, name) ->
230 let anchor = anchor `Type (TypeName.to_string name) in
231 continue anchor parent
232 | `Label _ -> assert false
233 | `Exception (parent, name) ->
234 let anchor = anchor `Exception (ExceptionName.to_string name) in
235 continue anchor parent
236 | `Class (parent, name) ->
237 let anchor = anchor `Class (TypeName.to_string name) in
238 continue anchor parent
239 | `Page _ -> assert false
240 | `LeafPage _ -> assert false
241 | `SourceLocation _ -> assert false
242 | `ClassType (parent, name) ->
243 let anchor = anchor `ClassType (TypeName.to_string name) in
244 continue anchor parent
245 | `SourcePage _ -> assert false
246 | `Value (parent, name) ->
247 let anchor = anchor `Val (ValueName.to_string name) in
248 continue anchor parent
249 | `Constructor (parent, name) ->
250 let anchor = anchor `Constructor (ConstructorName.to_string name) in
251 continue anchor parent
252 | `Root _ ->
253 (* We do not need to include the "container" root module in the anchor
254 to have unique anchors. *)
255 acc
256 | `Extension (parent, name) ->
257 let anchor = anchor `Extension (ExtensionName.to_string name) in
258 continue anchor parent
259 | `ExtensionDecl (parent, name, _) ->
260 let anchor = anchor `ExtensionDecl (ExtensionName.to_string name) in
261 continue anchor parent
262 in
263 anchor_of_identifier [] id |> String.concat "."
264
265(* Adds the global definitions, found in the [uid_to_loc], to the [loc_to_id]
266 and [uid_to_id] tables. *)
267let populate_global_defs env source_id loc_to_id uid_to_loc uid_to_id =
268 let mk_src_id id =
269 let name = Odoc_model.Names.DefName.make_std (anchor_of_identifier id) in
270 (Odoc_model.Paths.Identifier.Mk.source_location (source_id, name)
271 :> Odoc_model.Paths.Identifier.SourceLocation.t)
272 in
273 let () =
274 Ident_env.iter_located_identifier env @@ fun loc id ->
275 LocHashtbl.add loc_to_id loc (mk_src_id id)
276 in
277 let mk_src_id () =
278 let name =
279 Odoc_model.Names.DefName.make_std (Printf.sprintf "def_%d" (counter ()))
280 in
281 (Odoc_model.Paths.Identifier.Mk.source_location (source_id, name)
282 :> Odoc_model.Paths.Identifier.SourceLocation.t)
283 in
284 Shape.Uid.Tbl.iter
285 (fun uid loc ->
286 if loc.Location.loc_ghost then ()
287 else
288 match LocHashtbl.find_opt loc_to_id loc with
289 | Some id -> UidHashtbl.add uid_to_id uid id
290 | None -> (
291 (* In case there is no entry for the location of the uid, we add one. *)
292 match uid with
293 | Item _ ->
294 let id = mk_src_id () in
295 LocHashtbl.add loc_to_id loc id;
296 UidHashtbl.add uid_to_id uid id
297 | Compilation_unit _ -> ()
298 | _ -> ()))
299 uid_to_loc
300
301(* Extract [Typedtree_traverse] occurrence information and turn them into proper
302 source infos *)
303let process_occurrences env poses loc_to_id local_ident_to_loc =
304 let open Odoc_model.Lang.Source_info in
305 (* Ensure source infos are not repeated by putting them in a Set (a unit hashtbl) *)
306 let occ_tbl = AnnotHashtbl.create 100 in
307 let process p find_in_env =
308 match p with
309 | Path.Pident id when IdentHashtbl.mem local_ident_to_loc id -> (
310 match
311 LocHashtbl.find_opt loc_to_id
312 (IdentHashtbl.find local_ident_to_loc id)
313 with
314 | None -> None
315 | Some id ->
316 let documentation = None and implementation = Some (Resolved id) in
317 Some { documentation; implementation })
318 | p -> (
319 match find_in_env env p with
320 | path ->
321 let documentation = if is_persistent p then Some path else None
322 and implementation = Some (Unresolved path) in
323 Some { documentation; implementation }
324 | exception _ -> None)
325 in
326 List.iter
327 (function
328 | Typedtree_traverse.Analysis.Value p, loc ->
329 process p Ident_env.Path.read_value
330 |> Option.iter @@ fun l ->
331 AnnotHashtbl.replace occ_tbl (Value l, pos_of_loc loc) ()
332 | Module p, loc ->
333 process p Ident_env.Path.read_module
334 |> Option.iter @@ fun l ->
335 AnnotHashtbl.replace occ_tbl (Module l, pos_of_loc loc) ()
336 | ModuleType p, loc ->
337 process p Ident_env.Path.read_module_type
338 |> Option.iter @@ fun l ->
339 AnnotHashtbl.replace occ_tbl (ModuleType l, pos_of_loc loc) ()
340 | Type p, loc ->
341 process p Ident_env.Path.read_type
342 |> Option.iter @@ fun l ->
343 AnnotHashtbl.replace occ_tbl (Type l, pos_of_loc loc) ()
344 | LocalDefinition _, _ -> ())
345 poses;
346 AnnotHashtbl.fold (fun k () acc -> k :: acc) occ_tbl []
347
348(* Add definition source info from the [loc_to_id] table *)
349let add_definitions loc_to_id occurrences =
350 LocHashtbl.fold
351 (fun loc id acc ->
352 (Odoc_model.Lang.Source_info.Definition id, pos_of_loc loc) :: acc)
353 loc_to_id occurrences
354
355let read_cmt_infos source_id shape_info impl digest root imports =
356 match shape_info with
357 | Some (shape, uid_to_loc) ->
358 let fake_root_id =
359 Odoc_model.Paths.Identifier.Mk.root
360 (None, Odoc_model.Names.ModuleName.make_std "fake_root")
361 in
362 let env = Env.of_structure fake_root_id impl in
363 let traverse_infos =
364 Typedtree_traverse.of_cmt env impl |> List.rev
365 (* Information are accumulated in a list. We need to have the
366 first info first in the list, to assign anchors with increasing
367 numbers, so that adding some content at the end of a file does
368 not modify the anchors for existing anchors. *)
369 in
370 let loc_to_id = LocHashtbl.create 10
371 and local_ident_to_loc = IdentHashtbl.create 10
372 and uid_to_id = UidHashtbl.create 10 in
373 let () =
374 match source_id with
375 | None -> ()
376 | Some source_id ->
377 populate_local_defs source_id traverse_infos loc_to_id
378 local_ident_to_loc;
379 populate_global_defs env source_id loc_to_id uid_to_loc uid_to_id
380 in
381 let source_infos =
382 process_occurrences env traverse_infos loc_to_id local_ident_to_loc
383 |> add_definitions loc_to_id
384 in
385 let shape_info = Some (shape, Shape.Uid.Tbl.to_map uid_to_id) in
386 {
387 Odoc_model.Lang.Implementation.id = source_id;
388 source_info = source_infos;
389 digest;
390 root;
391 linked = false;
392 shape_info;
393 imports;
394 }
395 | None as shape_info ->
396 {
397 Odoc_model.Lang.Implementation.id = source_id;
398 source_info = [];
399 digest;
400 root;
401 linked = false;
402 shape_info;
403 imports;
404 }
405
406
407#else
408
409let read_cmt_infos source_id shape_info _impl digest root imports =
410 {
411 Odoc_model.Lang.Implementation.id = source_id;
412 source_info = [];
413 digest;
414 root;
415 linked = false;
416 shape_info;
417 imports;
418 }
419
420#endif