Skip to content

Commit 979fe9c

Browse files
authored
Occurrences patches (#18)
1 parent b7a2762 commit 979fe9c

File tree

10 files changed

+257
-141
lines changed

10 files changed

+257
-141
lines changed

src/occurrences/dune

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
(library
22
(name odoc_occurrences)
33
(public_name odoc.occurrences)
4-
(libraries odoc_model))
4+
(libraries fpath odoc_model unix))
Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,82 @@
11
module Table = Table
22

3-
let of_impl ~include_hidden unit htbl =
4-
let incr tbl p =
3+
let of_impl ~include_hidden unit htbl deftbl =
4+
let incr tbl p src_loc =
55
let open Odoc_model.Paths.Path.Resolved in
66
let p = (p :> t) in
77
let id = identifier p in
88
match id with
9-
| Some id when (not (is_hidden p)) || include_hidden -> Table.add tbl id
9+
| Some id when (not (is_hidden p)) || include_hidden -> Table.add tbl id src_loc
1010
| _ -> ()
1111
in
12+
let add_item p implementation =
13+
let src_loc =
14+
match implementation with
15+
| Some (Odoc_model.Lang.Source_info.Resolved impl) ->
16+
Table.Deftbl.get deftbl impl
17+
| _ -> None
18+
in
19+
incr htbl p src_loc
20+
in
1221
let open Odoc_model.Lang in
1322
List.iter
1423
(function
15-
| Source_info.Module { documentation = Some (`Resolved p); _ }, _ ->
16-
incr htbl p
17-
| Value { documentation = Some (`Resolved p); _ }, _ -> incr htbl p
18-
| ModuleType { documentation = Some (`Resolved p); _ }, _ -> incr htbl p
19-
| Type { documentation = Some (`Resolved p); _ }, _ -> incr htbl p
24+
| Source_info.Module { documentation = Some (`Resolved p); implementation }, _ ->
25+
add_item p implementation
26+
| Value { documentation = Some (`Resolved p); implementation }, _ ->
27+
add_item p implementation
28+
| ModuleType { documentation = Some (`Resolved p); implementation }, _ ->
29+
add_item p implementation
30+
| Type { documentation = Some (`Resolved p); implementation }, _ ->
31+
add_item p implementation
32+
| Definition _, _ -> ()
2033
| _ -> ())
2134
unit.Implementation.source_info
2235

23-
let aggregate ~tbl ~data =
24-
Table.iter
25-
(fun id { Table.direct; _ } -> Table.add ~quantity:direct tbl id)
26-
data
36+
let aggregate ~tbl ~data = Table.merge_into ~src:data ~dst:tbl
37+
38+
type hg_revision = string
39+
40+
let unspecified_hg_revision : hg_revision = ""
41+
42+
(* TODO: The [revision] field is really a temporary hack and should be replaced
43+
by a dummy with an opaque type. Annoyingly, just removing the field would
44+
risk causing segfaults due to unmarshalling.
45+
*)
46+
type t = {table : Table.t; revision: hg_revision; max_occurrences: int}
47+
48+
let from_file file : t =
49+
Odoc_utils.Io_utils.unmarshal (Fpath.to_string file)
50+
;;
51+
52+
(* FIXME: Copied from [Odoc_odoc.Fs], which should probably just all be moved into
53+
[Odoc_utils]. *)
54+
let mkdir_p dir =
55+
let open StdLabels in
56+
let mkdir d =
57+
try Unix.mkdir (Fpath.to_string d) 0o755 with
58+
| Unix.Unix_error (Unix.EEXIST, _, _) -> ()
59+
| exn -> raise exn
60+
in
61+
let rec dirs_to_create p acc =
62+
if Sys.file_exists (Fpath.to_string p) then acc
63+
else dirs_to_create (Fpath.parent p) (p :: acc)
64+
in
65+
List.iter (dirs_to_create dir []) ~f:mkdir
66+
;;
67+
68+
let to_file (t : t) file =
69+
mkdir_p (Fpath.parent file);
70+
Odoc_utils.Io_utils.marshal (Fpath.to_string file) t;
71+
;;
72+
73+
let from_occtbl occtbl revision : t =
74+
let get_max tbl =
75+
let max = ref 0 in
76+
let f _key (item : Table.item) =
77+
max := Int.max (!max) (item.direct + item.indirect)
78+
in
79+
Table.iter f tbl; !max
80+
in
81+
let revision = revision |> Option.value ~default:unspecified_hg_revision in
82+
{table = occtbl; max_occurrences = get_max occtbl; revision}

src/occurrences/odoc_occurrences.mli

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,21 @@ open Odoc_model.Lang
22

33
module Table = Table
44

5-
val of_impl : include_hidden:bool -> Implementation.t -> Table.t -> unit
5+
val of_impl : include_hidden:bool -> Implementation.t -> Table.t -> Table.Deftbl.t -> unit
66
(** Add all occurrences from implementation of a compilation unit into a table
77
*)
88

99
val aggregate : tbl:Table.t -> data:Table.t -> unit
1010
(** Aggregate [data] into [tbl] *)
11+
12+
type hg_revision = string
13+
14+
val unspecified_hg_revision : hg_revision
15+
16+
type t = {table : Table.t; revision: hg_revision; max_occurrences: int}
17+
18+
val from_file : Fpath.t -> t
19+
20+
val to_file : t -> Fpath.t -> unit
21+
22+
val from_occtbl : Table.t -> hg_revision option -> t

src/occurrences/table.ml

Lines changed: 52 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,37 @@
1-
module H = Hashtbl.Make (Odoc_model.Paths.Identifier)
1+
let get_key (id : Odoc_model.Paths.Identifier.t) = id.ikey
22

3-
type t = internal_item H.t
4-
and internal_item = { direct : int; indirect : int; sub : t }
5-
type key = Odoc_model.Paths.Identifier.t
3+
module H = Hashtbl.Make (String)
64

7-
type item = { direct : int; indirect : int }
5+
type impl_src = {filepath: string list; line_number: int}
6+
type t = item H.t
7+
and item = { direct : int; indirect : int ; impl_src : impl_src option }
8+
type key = string
9+
type identifier = Odoc_model.Paths.Identifier.t
810

9-
let internal_to_item : internal_item -> item =
10-
fun { direct; indirect; _ } -> { direct; indirect }
11-
12-
let v_item () = { direct = 0; indirect = 0; sub = H.create 0 }
11+
let v_item () = { direct = 0; indirect = 0; impl_src = None }
1312

1413
let v () = H.create 0
1514

16-
let add ?(quantity = 1) tbl id =
15+
let add ?(quantity = 1) tbl id impl_src =
1716
let rec add ?(kind = `Indirect) id =
18-
let incr htbl id =
19-
let { direct; indirect; sub } =
20-
try H.find htbl id with Not_found -> v_item ()
17+
let incr id =
18+
let { direct; indirect ; impl_src=impl_src_old} =
19+
try H.find tbl (get_key id) with Not_found -> v_item ()
2120
in
21+
let impl_src =
22+
if Option.is_none impl_src || kind <> `Direct
23+
then impl_src_old
24+
else impl_src in
2225
let direct, indirect =
2326
match kind with
2427
| `Direct -> (direct + quantity, indirect)
2528
| `Indirect -> (direct, indirect + quantity)
2629
in
27-
H.replace htbl id { direct; indirect; sub };
28-
sub
30+
H.replace tbl (get_key id) { direct; indirect ; impl_src };
2931
in
3032
let do_ parent =
31-
let htbl = add (parent :> key) in
32-
incr htbl id
33+
add (parent :> identifier);
34+
incr id
3335
in
3436
match id.iv with
3537
| `InstanceVariable (parent, _) -> do_ parent
@@ -38,6 +40,7 @@ let add ?(quantity = 1) tbl id =
3840
| `ModuleType (parent, _) -> do_ parent
3941
| `Method (parent, _) -> do_ parent
4042
| `Field (parent, _) -> do_ parent
43+
| `UnboxedField (parent, _) -> do_ parent
4144
| `Extension (parent, _) -> do_ parent
4245
| `Type (parent, _) -> do_ parent
4346
| `Constructor (parent, _) -> do_ parent
@@ -46,49 +49,43 @@ let add ?(quantity = 1) tbl id =
4649
| `Class (parent, _) -> do_ parent
4750
| `Value (parent, _) -> do_ parent
4851
| `ClassType (parent, _) -> do_ parent
49-
| `Root _ -> incr tbl id
52+
| `Root _ -> incr id
5053
| `SourcePage _ | `Page _ | `LeafPage _ | `SourceLocation _ | `Label _
5154
| `SourceLocationMod _ | `Result _ | `AssetFile _
5255
| `SourceLocationInternal _ ->
5356
assert false
5457
in
55-
let _htbl = add ~kind:`Direct id in
56-
()
58+
add ~kind:`Direct id
5759

58-
let rec get t id =
59-
let do_ parent =
60-
get t (parent :> key) |> function
61-
| None -> None
62-
| Some { sub; _ } -> ( try Some (H.find sub id) with Not_found -> None)
63-
in
64-
match id.iv with
65-
| `InstanceVariable (parent, _) -> do_ parent
66-
| `Parameter (parent, _) -> do_ parent
67-
| `Module (parent, _) -> do_ parent
68-
| `ModuleType (parent, _) -> do_ parent
69-
| `Method (parent, _) -> do_ parent
70-
| `Field (parent, _) -> do_ parent
71-
| `Extension (parent, _) -> do_ parent
72-
| `ExtensionDecl (parent, _, _) -> do_ parent
73-
| `Type (parent, _) -> do_ parent
74-
| `Constructor (parent, _) -> do_ parent
75-
| `Exception (parent, _) -> do_ parent
76-
| `Class (parent, _) -> do_ parent
77-
| `Value (parent, _) -> do_ parent
78-
| `ClassType (parent, _) -> do_ parent
79-
| `Root _ -> ( try Some (H.find t id) with Not_found -> None)
80-
| `SourcePage _ | `Page _ | `LeafPage _ | `SourceLocation _ | `Label _
81-
| `SourceLocationMod _ | `Result _ | `AssetFile _ | `SourceLocationInternal _
82-
->
83-
None
60+
let add_entries item item_opt =
61+
match item_opt with
62+
| Some { direct; indirect ; impl_src } ->
63+
let direct = item.direct + direct in
64+
let indirect = item.indirect + indirect in
65+
let impl_src = if Option.is_some item.impl_src then item.impl_src else impl_src in
66+
{direct ; indirect ; impl_src}
67+
| None -> item
68+
69+
let get t id = H.find_opt t (get_key id)
70+
71+
let iter = H.iter
72+
73+
let merge_into ~src ~dst =
74+
iter (fun key item ->
75+
let dst_item = H.find_opt dst key in
76+
let new_item = add_entries item dst_item in
77+
H.replace dst key new_item
78+
) src
79+
80+
module Deftbl = struct
81+
type key = Odoc_model.Paths.Identifier.SourceLocation.t
82+
type item = impl_src
83+
module H = Hashtbl.Make (String)
84+
type t = item H.t
85+
86+
let v () = H.create 0
8487

85-
let get t id =
86-
match get t id with None -> None | Some i -> Some (internal_to_item i)
88+
let add t (k: key) (v: item) = H.add t k.ikey v
8789

88-
let rec iter f tbl =
89-
H.iter
90-
(fun id v ->
91-
iter f v.sub;
92-
let v = internal_to_item v in
93-
f id v)
94-
tbl
90+
let get t (k: key) = H.find_opt t k.ikey
91+
end

src/occurrences/table.mli

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,28 @@
11
type t
2-
type item = { direct : int; indirect : int }
3-
type key = Odoc_model.Paths.Identifier.t
2+
type impl_src = {filepath: string list; line_number: int}
3+
type item = { direct : int; indirect : int ; impl_src : impl_src option}
4+
type key = string
5+
type identifier = Odoc_model.Paths.Identifier.t
46

57
val v : unit -> t
8+
val v_item : unit -> item
69

7-
val add : ?quantity:int -> t -> key -> unit
10+
val add : ?quantity:int -> t -> identifier -> impl_src option -> unit
811

912
val iter : (key -> item -> unit) -> t -> unit
1013

11-
val get : t -> key -> item option
14+
val get : t -> identifier -> item option
15+
16+
val merge_into: src:t -> dst:t -> unit
17+
18+
module Deftbl : sig
19+
type key = Odoc_model.Paths.Identifier.SourceLocation.t
20+
type item = impl_src
21+
type t
22+
23+
val v : unit -> t
24+
25+
val add : t -> key -> item -> unit
26+
27+
val get : t -> key -> item option
28+
end

src/odoc/bin/main.ml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,9 +1568,9 @@ module Occurrences = struct
15681568
else Ok f
15691569

15701570
module Count = struct
1571-
let count directories dst warnings_options include_hidden =
1571+
let count directories dst revision warnings_options include_hidden =
15721572
dst_of_string dst >>= fun dst ->
1573-
Occurrences.count ~dst ~warnings_options directories include_hidden
1573+
Occurrences.count ~dst ~warnings_options ~revision directories include_hidden
15741574

15751575
let cmd =
15761576
let dst =
@@ -1580,6 +1580,13 @@ module Occurrences = struct
15801580
& opt (some string) None
15811581
& info ~docs ~docv:"PATH" ~doc [ "o" ])
15821582
in
1583+
let revision =
1584+
let doc = "Current hg revision id" in
1585+
Arg.(
1586+
value & opt (some string) None
1587+
& info ~docs ~doc ["revision"]
1588+
)
1589+
in
15831590
let include_hidden =
15841591
let doc = "Include hidden identifiers in the table" in
15851592
Arg.(value & flag & info ~docs ~doc [ "include-hidden" ])
@@ -1596,7 +1603,7 @@ module Occurrences = struct
15961603
in
15971604
Term.(
15981605
const handle_error
1599-
$ (const count $ input $ dst $ warnings_options $ include_hidden))
1606+
$ (const count $ input $ dst $ revision $ warnings_options $ include_hidden))
16001607

16011608
let info ~docs =
16021609
let doc =

0 commit comments

Comments
 (0)