• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ocaml / odoc / 3054

19 Feb 2026 11:33AM UTC coverage: 71.709% (-1.2%) from 72.946%
3054

Pull #1399

github

web-flow
Merge 8fa44a817 into c3f0f46ee
Pull Request #1399: Upstream OxCaml

20 of 281 new or added lines in 21 files covered. (7.12%)

162 existing lines in 11 files now uncovered.

10400 of 14503 relevant lines covered (71.71%)

7007.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.24
/src/model/reference.ml
1
type path = [ `Root of string | `Dot of path * string ]
2

3
let expected_err :
4
    (Format.formatter -> 'a -> unit) -> 'a -> Location_.span -> Error.t =
5
 fun pp_a a -> Error.make "Expected %a." pp_a a
151✔
6

7
let expected_err_str : string -> Location_.span -> Error.t =
8
  expected_err Format.pp_print_string
1,315✔
9

10
let unknown_reference_qualifier : string -> Location_.span -> Error.t =
11
  Error.make "Unknown reference qualifier '%s'."
1,315✔
12

13
let deprecated_reference_kind : string -> string -> Location_.span -> Error.t =
14
  Error.make "'%s' is deprecated, use '%s' instead."
1,315✔
15

16
let reference_kinds_do_not_match : string -> string -> Location_.span -> Error.t
17
    =
18
  Error.make "Old-style reference kind ('%s:') does not match new ('%s-')."
1,315✔
19

20
let should_not_be_empty : what:string -> Location_.span -> Error.t =
21
 fun ~what ->
22
  Error.make "%s should not be empty." (Astring.String.Ascii.capitalize what)
34✔
23

24
let not_allowed :
25
    ?suggestion:string ->
26
    what:string ->
27
    in_what:string ->
28
    Location_.span ->
29
    Error.t =
30
 fun ?suggestion ~what ~in_what ->
31
  Error.make ?suggestion "%s is not allowed in %s."
2✔
32
    (Astring.String.Ascii.capitalize what)
2✔
33
    in_what
34

35
(** Format a list in a human readable way: [A, B, or C]. *)
36
let pp_hum_comma_separated pp_a ppf lst =
37
  let rec loop hd = function
149✔
38
    | [] -> Format.fprintf ppf "or %a" pp_a hd
149✔
39
    | hd' :: tl' ->
483✔
40
        Format.fprintf ppf "%a, " pp_a hd;
41
        loop hd' tl'
483✔
42
  in
43
  match lst with [] -> () | [ a ] -> pp_a ppf a | hd :: tl -> loop hd tl
×
44

45
let deprecated_reference_kind location kind replacement =
46
  deprecated_reference_kind kind replacement location |> Error.raise_warning
8✔
47

48
(* http://caml.inria.fr/pub/docs/manual-ocaml/ocamldoc.html#sec359. *)
49
let match_ocamldoc_reference_kind (_location as loc) s :
50
    [> Paths.Reference.tag_any ] option =
51
  let d = deprecated_reference_kind in
563✔
52
  match s with
53
  | "module" -> Some `TModule
80✔
54
  | "modtype" ->
1✔
55
      d loc "modtype" "module-type";
56
      Some `TModuleType
1✔
57
  | "class" -> Some `TClass
47✔
58
  | "classtype" ->
1✔
59
      d loc "classtype" "class-type";
60
      Some `TClassType
1✔
61
  | "val" -> Some `TValue
27✔
62
  | "type" -> Some `TType
40✔
63
  | "exception" -> Some `TException
17✔
64
  | "attribute" -> None
×
65
  | "method" -> Some `TMethod
47✔
66
  | "section" -> Some `TLabel
34✔
67
  | "const" ->
1✔
68
      d loc "const" "constructor";
69
      Some `TConstructor
1✔
70
  | "recfield" ->
1✔
71
      d loc "recfield" "field";
72
      Some `TField
1✔
73
  | "childpage" -> Some `TChildPage
3✔
74
  | "childmodule" -> Some `TChildModule
5✔
75
  | _ -> None
259✔
76

77
let match_extra_odoc_reference_kind (_location as loc) s :
78
    [> Paths.Reference.tag_any ] option =
79
  let d = deprecated_reference_kind in
259✔
80
  match s with
81
  | "class-type" -> Some `TClassType
19✔
82
  | "constructor" -> Some `TConstructor
56✔
83
  | "exn" ->
1✔
84
      d loc "exn" "exception";
85
      Some `TException
1✔
86
  | "extension" -> Some `TExtension
19✔
87
  | "extension-decl" -> Some `TExtensionDecl
4✔
88
  | "field" -> Some `TField
55✔
89
  | "instance-variable" -> Some `TInstanceVariable
15✔
90
  | "label" ->
1✔
91
      d loc "label" "section";
92
      Some `TLabel
1✔
93
  | "module-type" -> Some `TModuleType
33✔
94
  | "page" -> Some `TPage
43✔
95
  | "asset" -> Some `TAsset
3✔
96
  | "value" ->
2✔
97
      d loc "value" "val";
98
      Some `TValue
2✔
99
  | _ -> None
8✔
100

101
type reference_kind = Paths.Reference.tag_any
102

103
(* Ideally, [tokenize] would call this on every reference kind annotation during
104
   tokenization, when generating the token list. However, that constrains the
105
   phantom tag type to be the same for all tokens in the list (because lists are
106
   homogeneous). So, the parser stores kinds as strings in the token list
107
   instead, and this function is called on each string at the latest possible
108
   time to prevent typing issues.
109

110
   A secondary reason to delay parsing, and store strings in the token list, is
111
   that we need the strings for user-friendly error reporting. *)
112
let match_reference_kind location s : reference_kind =
113
  match s with
1,155✔
114
  | `None -> `TUnknown
592✔
115
  | `Prefixed s | `Old_prefix s -> (
39✔
116
      let result =
117
        match match_ocamldoc_reference_kind location s with
118
        | Some _ as kind -> kind
304✔
119
        | None -> match_extra_odoc_reference_kind location s
259✔
120
      in
121
      match result with
122
      | Some kind -> kind
555✔
123
      | None -> unknown_reference_qualifier s location |> Error.raise_exception)
8✔
124

125
type token = {
126
  kind : [ `None | `Prefixed of string ];
127
  identifier : string;
128
  location : Location_.span;
129
}
130

131
type path_prefix = Path_prefix of string * Location_.span
132

133
(* The string is scanned right-to-left, because we are interested in right-most
134
   hyphens. The tokens are also returned in right-to-left order, because the
135
   traversals that consume them prefer to look at the deepest identifier
136
   first. *)
137
let tokenize location s : token list * path_prefix option =
138
  let rec scan_identifier started_at open_parenthesis_count index tokens =
709✔
139
    match s.[index] with
5,348✔
140
    | exception Invalid_argument _ ->
408✔
141
        let identifier, location = identifier_ended started_at index in
142
        ({ kind = `None; identifier; location } :: tokens, None)
389✔
143
    | '-' when open_parenthesis_count = 0 ->
537✔
144
        let identifier, location = identifier_ended started_at index in
536✔
145
        scan_kind identifier location index (index - 1) tokens
532✔
146
    | '.' when open_parenthesis_count = 0 ->
190✔
147
        let identifier, location = identifier_ended started_at index in
189✔
148
        scan_identifier index 0 (index - 1)
188✔
149
          ({ kind = `None; identifier; location } :: tokens)
150
    | '/' when open_parenthesis_count = 0 ->
84✔
151
        let identifier, location = identifier_ended started_at index in
84✔
152
        scan_path index ({ kind = `None; identifier; location } :: tokens)
76✔
153
    | ')' ->
9✔
154
        scan_identifier started_at
155
          (open_parenthesis_count + 1)
156
          (index - 1) tokens
157
    | '(' when open_parenthesis_count > 0 ->
9✔
158
        scan_identifier started_at
9✔
159
          (open_parenthesis_count - 1)
160
          (index - 1) tokens
161
    | '"' -> (
18✔
162
        try
163
          scan_identifier started_at 0
16✔
164
            (String.rindex_from s (index - 1) '"' - 1)
17✔
165
            tokens
166
        with _ ->
2✔
167
          Error.raise_exception (Error.make "Unmatched quotation!" location))
2✔
168
    | _ -> scan_identifier started_at open_parenthesis_count (index - 1) tokens
4,095✔
169
  and identifier_ended started_at index =
170
    let offset = index + 1 in
1,217✔
171
    let length = started_at - offset in
172
    let identifier = String.sub s offset length in
173
    let identifier =
1,217✔
174
      Astring.String.cuts ~sep:"\"" identifier
175
      |> List.mapi (fun i s ->
1,217✔
176
             if i mod 2 = 0 then
1,249✔
177
               Astring.String.cuts s ~sep:" " |> String.concat ""
1,233✔
178
             else s)
16✔
179
      |> String.concat ""
1,217✔
180
    in
181
    let location = Location_.in_string s ~offset ~length location in
1,217✔
182

183
    if identifier = "" then
1,217✔
184
      should_not_be_empty ~what:"Identifier in reference" location
185
      |> Error.raise_exception;
×
186

187
    (identifier, location)
1,185✔
188
  and scan_kind identifier identifier_location started_at index tokens =
189
    match s.[index] with
4,233✔
190
    | exception Invalid_argument _ ->
202✔
191
        let kind, location = kind_ended identifier_location started_at index in
192
        ({ kind; identifier; location } :: tokens, None)
202✔
193
    | '.' ->
321✔
194
        let kind, location = kind_ended identifier_location started_at index in
195
        scan_identifier index 0 (index - 1)
321✔
196
          ({ kind; identifier; location } :: tokens)
197
    | '/' ->
9✔
198
        let kind, location = kind_ended identifier_location started_at index in
199
        scan_path index ({ kind; identifier; location } :: tokens)
9✔
200
    | _ ->
3,701✔
201
        scan_kind identifier identifier_location started_at (index - 1) tokens
202
  and kind_ended identifier_location started_at index =
203
    let offset = index + 1 in
532✔
204
    let length = started_at - offset in
205
    let kind = `Prefixed (String.sub s offset length) in
532✔
206
    let location = Location_.in_string s ~offset ~length location in
207
    let location = Location_.span [ location; identifier_location ] in
532✔
208
    (kind, location)
532✔
209
  and scan_path started_at tokens =
210
    let location =
85✔
211
      Location_.in_string s ~offset:0 ~length:(started_at + 1) location
212
    in
213
    (tokens, Some (Path_prefix (String.sub s 0 (started_at + 1), location)))
85✔
214
  in
215

216
  scan_identifier (String.length s) 0 (String.length s - 1) []
709✔
217
  |> fun (toks, p) -> (List.rev toks, p)
676✔
218

219
let expected ?(expect_paths = false) allowed location =
79✔
220
  let unqualified = [ "an unqualified reference" ] in
149✔
221
  let unqualified =
222
    if expect_paths then "a path" :: unqualified else unqualified
70✔
223
  in
224
  let allowed = List.map (Printf.sprintf "'%s-'") allowed @ unqualified in
149✔
225
  expected_err (pp_hum_comma_separated Format.pp_print_string) allowed location
149✔
226

227
let parse_path whole_path_location p =
228
  let segs = Astring.String.cuts ~sep:"/" p in
91✔
229
  let check segs start =
91✔
230
    let _finish =
91✔
231
      List.fold_left
232
        (fun offset seg ->
233
          match seg with
162✔
234
          | "" ->
2✔
235
              let location =
236
                Location_.in_string p ~offset ~length:0 whole_path_location
237
              in
238
              should_not_be_empty ~what:"Identifier in path reference" location
2✔
239
              |> Error.raise_exception
2✔
240
          | seg -> offset + String.length seg + 1)
160✔
241
        start segs
242
    in
243
    ()
89✔
244
  in
245
  match segs with
246
  | "." :: segs ->
14✔
247
      check segs 2;
248
      (`TRelativePath, segs)
14✔
249
  | "" :: "" :: segs ->
27✔
250
      check segs 2;
251
      (`TCurrentPackage, segs)
26✔
252
  | "" :: segs ->
30✔
253
      check segs 1;
254
      (`TAbsolutePath, segs)
30✔
255
  | segs ->
20✔
256
      check segs 0;
257
      (`TRelativePath, segs)
19✔
258

259
let parse_path_prefix (Path_prefix (p, path_location)) identifier
260
    prefix_location =
261
  parse_path (Location_.span [ path_location; prefix_location ]) (p ^ identifier)
84✔
262

263
(* Parse references that do not contain a [/]. Raises errors and warnings. *)
264
let parse whole_reference_location s :
265
    Paths.Reference.t Error.with_errors_and_warnings =
266
  let open Paths.Reference in
709✔
267
  let open Names in
268
  let parse_from_last_component { kind; identifier; location } old_kind tokens
269
      path_prefix =
270
    let rec signature { kind; identifier; location } tokens : Signature.t =
676✔
271
      let kind = match_reference_kind location kind in
119✔
272
      match tokens with
119✔
273
      | [] -> (
96✔
274
          match path_prefix with
275
          | None -> (
96✔
276
              match kind with
277
              | (`TUnknown | `TModule | `TModuleType) as kind ->
5✔
278
                  `Root (identifier, kind)
279
              | _ ->
39✔
280
                  expected ~expect_paths:true
281
                    [ "module"; "module-type" ]
282
                    location
283
                  |> Error.raise_exception)
39✔
284
          | Some p -> (
×
285
              match kind with
286
              | `TUnknown | `TModule ->
×
287
                  `Module_path (parse_path_prefix p identifier location)
×
288
              | _ ->
×
289
                  expected ~expect_paths:true [ "module" ] location
290
                  |> Error.raise_exception))
×
291
      | next_token :: tokens -> (
23✔
292
          match kind with
293
          | `TUnknown ->
3✔
294
              `Dot ((parent next_token tokens :> LabelParent.t), identifier)
2✔
295
          | `TModule ->
4✔
296
              `Module
297
                (signature next_token tokens, ModuleName.make_std identifier)
3✔
298
          | `TModuleType ->
4✔
299
              `ModuleType
300
                (signature next_token tokens, ModuleTypeName.make_std identifier)
3✔
301
          | _ ->
12✔
302
              expected ~expect_paths:true [ "module"; "module-type" ] location
303
              |> Error.raise_exception)
12✔
304
    and parent { kind; identifier; location } tokens : FragmentTypeParent.t =
305
      let kind = match_reference_kind location kind in
101✔
306
      match tokens with
101✔
307
      | [] -> (
52✔
308
          match path_prefix with
309
          | None -> (
52✔
310
              match kind with
311
              | (`TUnknown | `TModule | `TModuleType | `TType) as kind ->
2✔
312
                  `Root (identifier, kind)
313
              | _ ->
27✔
314
                  expected [ "module"; "module-type"; "type" ] location
315
                  |> Error.raise_exception)
27✔
316
          | Some p -> (
×
317
              match kind with
318
              | `TUnknown | `TModule ->
×
319
                  `Module_path (parse_path_prefix p identifier location)
×
320
              | _ ->
×
321
                  expected ~expect_paths:true [ "module" ] location
322
                  |> Error.raise_exception))
×
323
      | next_token :: tokens -> (
49✔
324
          match kind with
325
          | `TUnknown ->
9✔
326
              `Dot ((parent next_token tokens :> LabelParent.t), identifier)
6✔
327
          | `TModule ->
4✔
328
              `Module
329
                (signature next_token tokens, ModuleName.make_std identifier)
3✔
330
          | `TModuleType ->
4✔
331
              `ModuleType
332
                (signature next_token tokens, ModuleTypeName.make_std identifier)
3✔
333
          | `TType ->
6✔
334
              `Type (signature next_token tokens, TypeName.make_std identifier)
4✔
335
          | _ ->
26✔
336
              expected [ "module"; "module-type"; "type" ] location
337
              |> Error.raise_exception)
26✔
338
    in
339

340
    let class_signature { kind; identifier; location } tokens : ClassSignature.t
341
        =
342
      let kind = match_reference_kind location kind in
40✔
343
      match tokens with
40✔
344
      | [] -> (
19✔
345
          match kind with
346
          | (`TUnknown | `TClass | `TClassType) as kind ->
1✔
347
              `Root (identifier, kind)
348
          | _ ->
14✔
349
              expected [ "class"; "class-type" ] location
350
              |> Error.raise_exception)
14✔
351
      | next_token :: tokens -> (
21✔
352
          match kind with
353
          | `TUnknown ->
3✔
354
              `Dot ((parent next_token tokens :> LabelParent.t), identifier)
2✔
355
          | `TClass ->
3✔
356
              `Class (signature next_token tokens, TypeName.make_std identifier)
2✔
357
          | `TClassType ->
3✔
358
              `ClassType
359
                (signature next_token tokens, TypeName.make_std identifier)
2✔
360
          | _ ->
12✔
361
              expected [ "class"; "class-type" ] location
362
              |> Error.raise_exception)
12✔
363
    in
364

365
    let label_parent_path kind path_prefix identifier location =
366
      match kind with
20✔
367
      | `TUnknown ->
19✔
368
          `Any_path (parse_path_prefix path_prefix identifier location)
19✔
369
      | `TModule ->
×
370
          `Module_path (parse_path_prefix path_prefix identifier location)
×
371
      | `TPage -> `Page_path (parse_path_prefix path_prefix identifier location)
1✔
372
      | _ ->
×
373
          expected ~expect_paths:true [ "module"; "page" ] location
374
          |> Error.raise_exception
×
375
    in
376

377
    let any_path kind path_prefix identifier location =
378
      match kind with
65✔
379
      | `TUnknown ->
57✔
380
          `Any_path (parse_path_prefix path_prefix identifier location)
55✔
381
      | `TModule ->
1✔
382
          `Module_path (parse_path_prefix path_prefix identifier location)
1✔
383
      | `TPage -> `Page_path (parse_path_prefix path_prefix identifier location)
3✔
384
      | `TAsset ->
3✔
385
          `Asset_path (parse_path_prefix path_prefix identifier location)
3✔
386
      | _ ->
1✔
387
          expected ~expect_paths:true [ "module"; "page" ] location
388
          |> Error.raise_exception
1✔
389
    in
390

391
    let rec label_parent { kind; identifier; location } tokens : LabelParent.t =
392
      let kind = match_reference_kind location kind in
180✔
393
      match tokens with
179✔
394
      | [] -> (
129✔
395
          match path_prefix with
396
          | None -> (
109✔
397
              match kind with
398
              | ( `TUnknown | `TModule | `TModuleType | `TType | `TClass
2✔
399
                | `TClassType | `TPage ) as kind ->
1✔
400
                  `Root (identifier, kind)
401
              | _ ->
8✔
402
                  expected ~expect_paths:true
403
                    [
404
                      "module";
405
                      "module-type";
406
                      "type";
407
                      "class";
408
                      "class-type";
409
                      "page";
410
                    ]
411
                    location
412
                  |> Error.raise_exception)
8✔
413
          | Some p -> label_parent_path kind p identifier location)
20✔
414
      | next_token :: tokens -> (
50✔
415
          match kind with
416
          | `TUnknown -> `Dot (label_parent next_token tokens, identifier)
25✔
417
          | `TModule ->
3✔
418
              `Module
419
                (signature next_token tokens, ModuleName.make_std identifier)
2✔
420
          | `TModuleType ->
3✔
421
              `ModuleType
422
                (signature next_token tokens, ModuleTypeName.make_std identifier)
2✔
423
          | `TType ->
3✔
424
              `Type (signature next_token tokens, TypeName.make_std identifier)
2✔
425
          | `TClass ->
5✔
426
              `Class (signature next_token tokens, TypeName.make_std identifier)
3✔
427
          | `TClassType ->
1✔
428
              `ClassType
429
                (signature next_token tokens, TypeName.make_std identifier)
1✔
430
          | _ ->
10✔
431
              expected ~expect_paths:true
432
                [ "module"; "module-type"; "type"; "class"; "class-type" ]
433
                location
434
              |> Error.raise_exception)
10✔
435
    in
436

437
    let start_from_last_component { kind; identifier; location } old_kind tokens
438
        =
439
      let new_kind = match_reference_kind location kind in
676✔
440
      let kind =
673✔
441
        match old_kind with
442
        | None -> new_kind
634✔
443
        | Some (old_kind_string, old_kind_location) -> (
39✔
444
            let old_kind =
445
              match_reference_kind old_kind_location
446
                (`Old_prefix old_kind_string)
447
            in
448
            match new_kind with
35✔
449
            | `TUnknown -> old_kind
32✔
450
            | _ ->
3✔
451
                (if old_kind <> new_kind then
452
                   let new_kind_string =
1✔
453
                     match kind with `None -> "" | `Prefixed s -> s
×
454
                   in
455
                   reference_kinds_do_not_match old_kind_string new_kind_string
456
                     whole_reference_location
457
                   |> Error.raise_warning);
1✔
458
                new_kind)
3✔
459
      in
460

461
      match tokens with
462
      | [] -> (
310✔
463
          match path_prefix with
464
          | None -> `Root (identifier, kind)
245✔
465
          | Some p -> any_path kind p identifier location)
65✔
466
      | next_token :: tokens -> (
359✔
467
          match kind with
468
          | `TUnknown -> `Dot (label_parent next_token tokens, identifier)
112✔
469
          | `TModule ->
30✔
470
              `Module
471
                (signature next_token tokens, ModuleName.make_std identifier)
6✔
472
          | `TModuleType ->
5✔
473
              `ModuleType
474
                (signature next_token tokens, ModuleTypeName.make_std identifier)
3✔
475
          | `TType ->
16✔
476
              `Type (signature next_token tokens, TypeName.make_std identifier)
11✔
477
          | `TConstructor ->
42✔
478
              `Constructor
479
                (parent next_token tokens, ConstructorName.make_std identifier)
18✔
480
          | `TField ->
44✔
481
              `Field (parent next_token tokens, FieldName.make_std identifier)
13✔
NEW
482
          | `TUnboxedField ->
×
483
              `UnboxedField
NEW
484
                (parent next_token tokens, UnboxedFieldName.make_std identifier)
×
485
          | `TExtension ->
6✔
486
              `Extension
487
                (signature next_token tokens, ExtensionName.make_std identifier)
4✔
488
          | `TExtensionDecl ->
2✔
489
              `ExtensionDecl
490
                (signature next_token tokens, ExtensionName.make_std identifier)
2✔
491
          | `TException ->
4✔
492
              `Exception
493
                (signature next_token tokens, ExceptionName.make_std identifier)
2✔
494
          | `TValue ->
4✔
495
              `Value (signature next_token tokens, ValueName.make_std identifier)
2✔
496
          | `TClass ->
5✔
497
              `Class (signature next_token tokens, TypeName.make_std identifier)
3✔
498
          | `TClassType ->
4✔
499
              `ClassType
500
                (signature next_token tokens, TypeName.make_std identifier)
2✔
501
          | `TMethod ->
36✔
502
              `Method
503
                ( class_signature next_token tokens,
9✔
504
                  MethodName.make_std identifier )
36✔
505
          | `TInstanceVariable ->
4✔
506
              `InstanceVariable
507
                ( class_signature next_token tokens,
2✔
508
                  InstanceVariableName.make_std identifier )
4✔
509
          | `TLabel ->
19✔
510
              `Label
511
                (label_parent next_token tokens, LabelName.make_std identifier)
19✔
512
          | `TChildPage | `TChildModule ->
×
513
              let suggestion =
514
                Printf.sprintf "'child-%s' should be first." identifier
515
              in
516
              not_allowed ~what:"Child label"
×
517
                ~in_what:"the last component of a reference path" ~suggestion
518
                location
519
              |> Error.raise_exception
×
520
          | `TPage ->
2✔
521
              let suggestion =
522
                Printf.sprintf "Reference pages as '<parent_path>/%s'."
523
                  identifier
524
              in
525
              not_allowed ~what:"Page label"
2✔
526
                ~in_what:"on the right side of a dot" ~suggestion location
527
              |> Error.raise_exception
2✔
528
          | `TAsset ->
×
529
              let suggestion =
530
                Printf.sprintf "Reference assets as '<parent_path>/%s'."
531
                  identifier
532
              in
533
              not_allowed ~what:"Asset label"
×
534
                ~in_what:"on the right side of a dot" ~suggestion location
535
              |> Error.raise_exception)
×
536
    in
537
    start_from_last_component { kind; identifier; location } old_kind tokens
538
  in
539
  Error.catch_errors_and_warnings (fun () ->
540
      let old_kind, s, location =
709✔
541
        let rec find_old_reference_kind_separator index =
542
          if index < 0 then raise Not_found
668✔
543
          else
544
            match s.[index] with
9,488✔
545
            | ':' -> index
41✔
546
            | ')' -> (
15✔
547
                match String.rindex_from s index '(' with
548
                | index -> find_old_reference_kind_separator (index - 1)
15✔
549
                | exception (Not_found as exn) -> raise exn)
×
550
            | _ -> find_old_reference_kind_separator (index - 1)
9,432✔
551
        in
552
        match find_old_reference_kind_separator (String.length s - 1) with
709✔
553
        | index ->
41✔
554
            let old_kind = String.trim (String.sub s 0 index) in
41✔
555
            let old_kind_location =
41✔
556
              Location_.set_end_as_offset_from_start index
557
                whole_reference_location
558
            in
559
            let s = String.sub s (index + 1) (String.length s - (index + 1)) in
41✔
560
            let location =
41✔
561
              Location_.nudge_start (index + 1) whole_reference_location
562
            in
563
            (Some (old_kind, old_kind_location), s, location)
41✔
564
        | exception Not_found -> (None, s, whole_reference_location)
668✔
565
      in
566
      match tokenize location s with
567
      | last_token :: tokens, path_prefix ->
676✔
568
          parse_from_last_component last_token old_kind tokens path_prefix
569
      | [], _ ->
×
570
          should_not_be_empty ~what:"Reference target" whole_reference_location
571
          |> Error.raise_exception)
×
572

573
(* Parse references that do not contain a [/]. Raises errors and warnings. *)
574
let parse_asset whole_reference_location s :
575
    Paths.Reference.Asset.t Error.with_errors_and_warnings =
576
  let path = parse_path whole_reference_location s in
7✔
577
  Error.catch_errors_and_warnings (fun () -> `Asset_path path)
7✔
578

579
let read_path_longident location s =
580
  let rec loop : string -> int -> path option =
160✔
581
   fun s pos ->
582
    try
335✔
583
      let idx = String.rindex_from s pos '.' in
584
      let name = String.sub s (idx + 1) (pos - idx) in
176✔
585
      if String.length name = 0 then None
1✔
586
      else
587
        match loop s (idx - 1) with
175✔
588
        | None -> None
1✔
589
        | Some parent -> Some (`Dot (parent, name))
174✔
590
    with Not_found ->
159✔
591
      let name = String.sub s 0 (pos + 1) in
592
      if String.length name = 0 then None else Some (`Root name)
1✔
593
  in
594
  Error.catch_warnings (fun () ->
595
      match loop s (String.length s - 1) with
160✔
596
      | Some r -> Ok (r :> path)
158✔
597
      | None -> Error (expected_err_str "a valid path" location))
2✔
598

599
let read_mod_longident location lid =
600
  Error.catch_warnings (fun () ->
30✔
601
      match Error.raise_warnings (parse location lid) with
30✔
602
      | Error _ as e -> e
×
603
      | Ok p -> (
30✔
604
          match p with
605
          | (`Root (_, (`TUnknown | `TModule)) | `Dot (_, _) | `Module (_, _))
×
606
            as r ->
607
              Ok r
608
          | _ -> Error (expected_err_str "a reference to a module" location)))
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc