this repo has no description
at main 420 lines 15 kB view raw
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