Skip to content

Commit bb406ea

Browse files
committed
Resolve fully-qualified references in modules synopsis
This removes the previous warning when a reference was encountered and instead attaches some informations to eventual errors reported while resolving contained references.
1 parent a5fb877 commit bb406ea

File tree

7 files changed

+91
-43
lines changed

7 files changed

+91
-43
lines changed

src/xref2/env.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,9 @@ let initial_env :
744744
| Not_found -> (import :: imports, env)))
745745
t.imports ([], initial_env)
746746

747+
let inherit_resolver env =
748+
match env.resolver with Some r -> set_resolver empty r | None -> empty
749+
747750
let modules_of env =
748751
let f acc = function `Module (id, m) -> (id, m) :: acc | _ -> acc in
749752
StringMap.fold (fun _ e acc -> List.fold_left f acc e) env.elts []

src/xref2/env.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,9 @@ val initial_env :
176176
resolver ->
177177
Odoc_model.Lang.Compilation_unit.Import.t list * t
178178

179+
val inherit_resolver : t -> t
180+
(** Create an empty environment reusing the same resolver. *)
181+
179182
val modules_of :
180183
t ->
181184
(Odoc_model.Paths.Identifier.Path.Module.t

src/xref2/link.ml

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,6 @@ let synopsis_of_module env (m : Component.Module.t) =
3030
| Ok sg -> synopsis_from_comment (Component.extract_signature_doc sg)
3131
| Error _ -> None)
3232

33-
let warn_if_contains_references ~location p =
34-
let is_ref = function
35-
| { Location_.value = `Reference _; _ } -> true
36-
| _ -> false
37-
in
38-
match p with
39-
| Some p when List.exists is_ref p ->
40-
Lookup_failures.with_location location (fun () ->
41-
Lookup_failures.report ~kind:`Warning
42-
"The synopsis from this module contains references that won't be \
43-
resolved when included in this list.")
44-
| _ -> ()
45-
4633
exception Loop
4734

4835
let rec is_forward : Paths.Path.Module.t -> bool = function
@@ -164,11 +151,20 @@ let rec comment_inline_element :
164151
orig)
165152
| y -> y
166153

154+
and paragraph env elts =
155+
List.map (with_location (comment_inline_element env)) elts
156+
157+
and resolve_external_synopsis env ~location synopsis =
158+
let env = Env.inherit_resolver env in
159+
Lookup_failures.with_context
160+
~suggestion:
161+
"Only fully-qualified references can be resolved in a synopsis."
162+
location "resolving a module's synopsis" (fun () -> paragraph env synopsis)
163+
167164
and comment_nestable_block_element env parent
168165
(x : Comment.nestable_block_element) =
169166
match x with
170-
| `Paragraph elts ->
171-
`Paragraph (List.map (with_location (comment_inline_element env)) elts)
167+
| `Paragraph elts -> `Paragraph (paragraph env elts)
172168
| (`Code_block _ | `Verbatim _) as x -> x
173169
| `List (x, ys) ->
174170
`List
@@ -185,8 +181,11 @@ and comment_nestable_block_element env parent
185181
match Ref_tools.resolve_module_reference env ref with
186182
| Some (r, _, m) ->
187183
let module_reference = Location_.at location (`Resolved r)
188-
and module_synopsis = synopsis_of_module env m in
189-
warn_if_contains_references ~location module_synopsis;
184+
and module_synopsis =
185+
Opt.map
186+
(resolve_external_synopsis env ~location)
187+
(synopsis_of_module env m)
188+
in
190189
{ Comment.module_reference; module_synopsis }
191190
| None -> r)
192191
refs

src/xref2/lookup_failures.ml

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,32 @@ let strict_mode = ref false
22

33
type kind = [ `Root | `Internal | `Warning ]
44

5-
type loc = Odoc_model.Location_.span option
5+
type loc = Odoc_model.Location_.span
66

7-
type 'a with_failures = 'a * (kind * string * loc) list
7+
type context = loc * string * string option
8+
(** Location * message * suggestion *)
9+
10+
type 'a with_failures = 'a * (kind * string * loc option * context option) list
811

912
let failure_acc = ref []
1013

1114
let loc_acc = ref None
1215

13-
let add ~kind f = failure_acc := (kind, f, !loc_acc) :: !failure_acc
16+
let context_acc = ref None
1417

15-
let catch_failures f =
16-
let prev = !failure_acc in
17-
failure_acc := [];
18+
let add ~kind f =
19+
failure_acc := (kind, f, !loc_acc, !context_acc) :: !failure_acc
20+
21+
let with_var var x f =
22+
let prev_x = !var in
23+
var := x;
1824
let r = f () in
19-
let failures = !failure_acc in
20-
failure_acc := prev;
25+
let last_x = !var in
26+
var := prev_x;
27+
(r, last_x)
28+
29+
let catch_failures f =
30+
let r, failures = with_var failure_acc [] f in
2131
(r, List.rev failures)
2232

2333
let kasprintf k fmt =
@@ -30,12 +40,10 @@ let report ?(kind = `Internal) fmt = kasprintf (add ~kind) fmt
3040
let report_important ?(kind = `Internal) exn fmt =
3141
if !strict_mode then raise exn else kasprintf (add ~kind) fmt
3242

33-
let with_location loc f =
34-
let prev_loc = !loc_acc in
35-
loc_acc := Some loc;
36-
let r = f () in
37-
loc_acc := prev_loc;
38-
r
43+
let with_location loc f = fst (with_var loc_acc (Some loc) f)
44+
45+
let with_context ?suggestion loc msg f =
46+
fst (with_var context_acc (Some (loc, msg, suggestion)) f)
3947

4048
let handle_failures ~warn_error ~filename (r, failures) =
4149
let open Odoc_model in
@@ -44,10 +52,19 @@ let handle_failures ~warn_error ~filename (r, failures) =
4452
| Some loc -> Error.make "%s" msg loc
4553
| None -> Error.filename_only "%s" msg filename
4654
in
47-
let handle_failure ~warnings = function
48-
| `Internal, msg, loc -> Error.warning warnings (error ~loc msg)
49-
| `Warning, msg, loc -> Error.warning warnings (error ~loc msg)
50-
| `Root, msg, loc -> prerr_endline (Error.to_string (error ~loc msg))
55+
let handle_failure ~warnings (kind, msg, loc, context) =
56+
let e = error ~loc msg in
57+
let e =
58+
match context with
59+
| None -> e
60+
| Some (cloc, cmsg, suggestion) ->
61+
Error.make ?suggestion "The following error occurred while %s:@\n%s"
62+
cmsg (Error.to_string e) cloc
63+
in
64+
match kind with
65+
| `Internal -> Error.warning warnings e
66+
| `Warning -> Error.warning warnings e
67+
| `Root -> prerr_endline (Error.to_string e)
5168
in
5269
Error.accumulate_warnings (fun warnings ->
5370
List.iter (handle_failure ~warnings) failures;

src/xref2/lookup_failures.mli

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ val with_location : Odoc_model.Location_.span -> (unit -> 'a) -> 'a
2323
(** Failures reported indirectly by this function will have a location
2424
attached. *)
2525

26+
val with_context :
27+
?suggestion:string ->
28+
Odoc_model.Location_.span ->
29+
string ->
30+
(unit -> 'a) ->
31+
'a
32+
(** Add context to every failures reported while executing [f]. *)
33+
2634
val handle_failures :
2735
warn_error:bool ->
2836
filename:string ->

test/xref2/module_list.t/main.mli

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,8 @@ module Inline_include : sig
5959
end
6060

6161
module Resolve_synopsis : sig
62-
(** {!t}
63-
64-
This reference should be resolved when included the list. *)
62+
(** This should be resolved when included: {!Main.Resolve_synopsis.t}. These
63+
shouldn't: {!t} {!Resolve_synopsis.t} *)
6564

6665
type t
6766
end

test/xref2/module_list.t/run.t

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,30 @@
22

33
$ compile external.mli starts_with_open.mli main.mli
44
File "external.mli", line 20, characters 4-36:
5-
The synopsis from this module contains references that won't be resolved when included in this list.
5+
The following error occurred while resolving a module's synopsis:
6+
File "main.mli", line 63, characters 17-21:
7+
Failed to resolve reference.
8+
Suggestion: Only fully-qualified references can be resolved in a synopsis.
9+
File "external.mli", line 20, characters 4-36:
10+
The following error occurred while resolving a module's synopsis:
11+
File "main.mli", line 63, characters 22-43:
12+
Failed to resolve reference.
13+
Suggestion: Only fully-qualified references can be resolved in a synopsis.
14+
File "main.mli", line 1, character 4 to line 3, character 47:
15+
The following error occurred while resolving a module's synopsis:
16+
File "main.mli", line 63, characters 17-21:
17+
Failed to resolve reference.
18+
Suggestion: Only fully-qualified references can be resolved in a synopsis.
619
File "main.mli", line 1, character 4 to line 3, character 47:
7-
The synopsis from this module contains references that won't be resolved when included in this list.
20+
The following error occurred while resolving a module's synopsis:
21+
File "main.mli", line 63, characters 22-43:
22+
Failed to resolve reference.
23+
Suggestion: Only fully-qualified references can be resolved in a synopsis.
824
File "main.mli", line 1, character 4 to line 3, character 47:
9-
The synopsis from this module contains references that won't be resolved when included in this list.
25+
The following error occurred while resolving a module's synopsis:
26+
File "external.mli", line 9, characters 6-10:
27+
Failed to resolve reference.
28+
Suggestion: Only fully-qualified references can be resolved in a synopsis.
1029

1130
Everything should resolve:
1231

@@ -42,7 +61,7 @@ Everything should resolve:
4261
{"`Resolved":{"`Identifier":{"`Root":[{"`RootPage":"test"},"Starts_with_open"]}}}
4362
{"Some":[{"`Word":"Synopsis"},"`Space",{"`Word":"of"},"`Space",{"`Code_span":"Starts_with_open"},{"`Word":"."}]}
4463
{"`Resolved":{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Main"]},"Resolve_synopsis"]}}}
45-
{"Some":[{"`Reference":[{"`Root":["t","`TUnknown"]},[]]}]}
64+
{"Some":[{"`Word":"This"},"`Space",{"`Word":"should"},"`Space",{"`Word":"be"},"`Space",{"`Word":"resolved"},"`Space",{"`Word":"when"},"`Space",{"`Word":"included:"},"`Space",{"`Reference":[{"`Resolved":{"`Type":[{"`Module":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Main"]}},"Resolve_synopsis"]},"t"]}},[]]},{"`Word":"."},"`Space",{"`Word":"These"},"`Space",{"`Word":"shouldn't:"},"`Space",{"`Reference":[{"`Root":["t","`TUnknown"]},[]]},"`Space",{"`Reference":[{"`Dot":[{"`Root":["Resolve_synopsis","`TUnknown"]},"t"]},[]]}]}
4665
{"`Resolved":{"`Module":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"External"]}},"Resolve_synopsis"]}}
4766
{"Some":[{"`Reference":[{"`Root":["t","`TUnknown"]},[]]}]}
4867

@@ -51,6 +70,6 @@ References in the synopses above should be resolved.
5170

5271
$ odoc_print external.odocl | jq -c '.. | .["`Modules"]? | select(.) | .[] | .[]'
5372
{"`Resolved":{"`Module":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Main"]}},"Resolve_synopsis"]}}
54-
{"Some":[{"`Reference":[{"`Root":["t","`TUnknown"]},[]]}]}
73+
{"Some":[{"`Word":"This"},"`Space",{"`Word":"should"},"`Space",{"`Word":"be"},"`Space",{"`Word":"resolved"},"`Space",{"`Word":"when"},"`Space",{"`Word":"included:"},"`Space",{"`Reference":[{"`Resolved":{"`Type":[{"`Module":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Main"]}},"Resolve_synopsis"]},"t"]}},[]]},{"`Word":"."},"`Space",{"`Word":"These"},"`Space",{"`Word":"shouldn't:"},"`Space",{"`Reference":[{"`Root":["t","`TUnknown"]},[]]},"`Space",{"`Reference":[{"`Dot":[{"`Root":["Resolve_synopsis","`TUnknown"]},"t"]},[]]}]}
5574

5675
'Type_of' and 'Alias' don't have a summary. `C1` and `C2` neither, we expect at least `C2` to have one.

0 commit comments

Comments
 (0)