diff --git a/src/document/comment.ml b/src/document/comment.ml index bea8557207..2d2160dbe7 100644 --- a/src/document/comment.ml +++ b/src/document/comment.ml @@ -255,7 +255,7 @@ and nestable_block_element_list elements = |> List.map Odoc_model.Location_.value |> List.map nestable_block_element -let tag : Comment.tag -> Description.one option = +let tag : Comment.tag -> Description.one = fun t -> let item ?value ~tag definition = let sp = inline (Text " ") in @@ -266,7 +266,7 @@ let tag : Comment.tag -> Description.one option = | Some t -> [ sp; inline ~attr:[ "value" ] t ] in let key = tag_name :: tag_value in - Some { Description.attr = [ tag ]; key; definition } + { Description.attr = [ tag ]; key; definition } in let text_def s = [ block (Block.Inline [ inline @@ Text s ]) ] in match t with @@ -293,15 +293,11 @@ let tag : Comment.tag -> Description.one option = let value = Inline.Text version in item ~tag:"before" ~value (nestable_block_element_list content) | `Version s -> item ~tag:"version" (text_def s) - | `Canonical _ | `Inline | `Open | `Closed -> None let attached_block_element : Comment.attached_block_element -> Block.t = function | #Comment.nestable_block_element as e -> [ nestable_block_element e ] - | `Tag t -> ( - match tag t with - | None -> [] - | Some t -> [ block ~attr:[ "at-tags" ] @@ Description [ t ] ]) + | `Tag t -> [ block ~attr:[ "at-tags" ] @@ Description [ tag t ] ] (* TODO collaesce tags *) diff --git a/src/document/generator.ml b/src/document/generator.ml index 66dc8b2d88..550f008e7d 100644 --- a/src/document/generator.ml +++ b/src/document/generator.ml @@ -1516,18 +1516,7 @@ module Make (Syntax : SYNTAX) = struct | Alias p -> Paths.Path.(is_hidden (p :> t)) | ModuleType mty -> umty_hidden mty in - let status = - let is_open_tag element = - element.Odoc_model.Location_.value = `Tag `Open - in - let is_closed_tag element = - element.Odoc_model.Location_.value = `Tag `Closed - in - if t.inline || decl_hidden then `Inline - else if List.exists is_open_tag t.doc then `Open - else if List.exists is_closed_tag t.doc then `Closed - else `Default - in + let status = if decl_hidden then `Inline else t.status in let include_decl = match t.decl with diff --git a/src/loader/cmi.ml b/src/loader/cmi.ml index 3a50089d61..3832c735ea 100644 --- a/src/loader/cmi.ml +++ b/src/loader/cmi.ml @@ -332,13 +332,6 @@ let mark_class_declaration cld = List.iter mark_type_parameter cld.cty_params; mark_class_type cld.cty_params cld.cty_type -let canonical doc : [`Dot of Path.Module.t * string] option = - let doc = List.map Odoc_model.Location_.value doc in - match List.find (function `Tag (`Canonical _) -> true | _ -> false) doc with - | exception Not_found -> None - | `Tag (`Canonical (`Dot (p, n))) -> Some (`Dot (p, n) ) - | _ -> None - let rec read_type_expr env typ = let open TypeExpr in let typ = Btype.repr typ in @@ -512,7 +505,7 @@ let read_value_description env parent id vd = let open Signature in let id = Env.find_value_identifier env id in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container vd.val_attributes in + let doc = Doc_attr.attached_no_tag container vd.val_attributes in mark_value_description vd; let type_ = read_type_expr env vd.val_type in match vd.val_kind with @@ -534,7 +527,7 @@ let read_label_declaration env parent ld = let name = Ident.name ld.ld_id in let id = `Field(parent, Odoc_model.Names.FieldName.make_std name) in let doc = - Doc_attr.attached + Doc_attr.attached_no_tag (parent :> Identifier.LabelParent.t) ld.ld_attributes in let mutable_ = (ld.ld_mutable = Mutable) in @@ -560,7 +553,7 @@ let read_constructor_declaration env parent cd = let name = Ident.name cd.cd_id in let id = `Constructor(parent, Odoc_model.Names.ConstructorName.make_std name) in let container = (parent : Identifier.DataType.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container cd.cd_attributes in + let doc = Doc_attr.attached_no_tag container cd.cd_attributes in let args = read_constructor_declaration_arguments env (parent :> Identifier.Parent.t) cd.cd_args @@ -621,8 +614,10 @@ let read_type_declaration env parent id decl = let open TypeDecl in let id = Env.find_type_identifier env id in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container decl.type_attributes in - let canonical = (canonical doc :> Path.Type.t option) in + let doc, canonical = + Doc_attr.attached Odoc_model.Semantics.Expect_canonical container decl.type_attributes + in + let canonical = (canonical :> Path.Type.t option) in let params = mark_type_declaration decl in let manifest = opt_map (read_type_expr env) decl.type_manifest in let constraints = read_type_constraints env params in @@ -651,7 +646,7 @@ let read_extension_constructor env parent id ext = let name = Ident.name id in let id = `Extension(parent, Odoc_model.Names.ExtensionName.make_std name) in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container ext.ext_attributes in + let doc = Doc_attr.attached_no_tag container ext.ext_attributes in let args = read_constructor_declaration_arguments env (parent : Identifier.Signature.t :> Identifier.Parent.t) ext.ext_args @@ -684,7 +679,7 @@ let read_exception env parent id ext = let name = Ident.name id in let id = `Exception(parent, Odoc_model.Names.ExceptionName.make_std name) in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container ext.ext_attributes in + let doc = Doc_attr.attached_no_tag container ext.ext_attributes in mark_exception ext; let args = read_constructor_declaration_arguments env @@ -782,7 +777,7 @@ let read_class_type_declaration env parent id cltd = let open ClassType in let id = Env.find_class_type_identifier env id in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container cltd.clty_attributes in + let doc = Doc_attr.attached_no_tag container cltd.clty_attributes in mark_class_type_declaration cltd; let params = List.map2 @@ -817,7 +812,7 @@ let read_class_declaration env parent id cld = let open Class in let id = Env.find_class_identifier env id in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container cld.cty_attributes in + let doc = Doc_attr.attached_no_tag container cld.cty_attributes in mark_class_declaration cld; let params = List.map2 @@ -856,8 +851,8 @@ and read_module_type_declaration env parent id (mtd : Odoc_model.Compat.modtype_ let open ModuleType in let id = Env.find_module_type env id in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container mtd.mtd_attributes in - let canonical = (canonical doc :> Path.ModuleType.t option) in + let doc, canonical = Doc_attr.attached Odoc_model.Semantics.Expect_canonical container mtd.mtd_attributes in + let canonical = (canonical :> Path.ModuleType.t option) in let expr = opt_map (read_module_type env (id :> Identifier.Signature.t)) mtd.mtd_type in {id; doc; canonical; expr } @@ -865,8 +860,8 @@ and read_module_declaration env parent ident (md : Odoc_model.Compat.module_decl let open Module in let id = (Env.find_module_identifier env ident :> Identifier.Module.t) in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container md.md_attributes in - let canonical = (canonical doc :> Path.Module.t option) in + let doc, canonical = Doc_attr.attached Odoc_model.Semantics.Expect_canonical container md.md_attributes in + let canonical = (canonical :> Path.Module.t option) in let type_ = match md.md_type with | Mty_alias p -> Alias (Env.Path.read_module env p, None) diff --git a/src/loader/cmi.mli b/src/loader/cmi.mli index 6d9f79efc2..54aa0df1cb 100644 --- a/src/loader/cmi.mli +++ b/src/loader/cmi.mli @@ -25,8 +25,6 @@ val read_interface : Odoc_model.Compat.signature -> Paths.Identifier.RootModule.t * Odoc_model.Lang.Signature.t -val canonical : Odoc_model.Comment.docs -> [ `Dot of Paths.Path.Module.t * string ] option - #if OCAML_MAJOR = 4 && OCAML_MINOR = 02 val read_label : Asttypes.label -> Odoc_model.Lang.TypeExpr.label option #else diff --git a/src/loader/cmt.ml b/src/loader/cmt.ml index b4a37e8823..da36f91a0a 100644 --- a/src/loader/cmt.ml +++ b/src/loader/cmt.ml @@ -71,7 +71,7 @@ let rec read_pattern env parent doc pat = let read_value_binding env parent vb = let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container vb.vb_attributes in + let doc = Doc_attr.attached_no_tag container vb.vb_attributes in read_pattern env parent doc vb.vb_pat let read_value_bindings env parent vbs = @@ -93,7 +93,7 @@ let read_type_extension env parent tyext = let open Extension in let type_path = Env.Path.read_type env tyext.tyext_path in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container tyext.tyext_attributes in + let doc = Doc_attr.attached_no_tag container tyext.tyext_attributes in let type_params = List.map (fun (ctyp, _) -> ctyp.ctyp_type) tyext.tyext_params in @@ -123,7 +123,7 @@ let rec read_class_type_field env parent ctf = let open Odoc_model.Names in let container = (parent : Identifier.ClassSignature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container ctf.ctf_attributes in + let doc = Doc_attr.attached_no_tag container ctf.ctf_attributes in match ctf.ctf_desc with | Tctf_val(name, mutable_, virtual_, typ) -> let open InstanceVariable in @@ -204,7 +204,7 @@ let rec read_class_field env parent cf = let open ClassSignature in let open Odoc_model.Names in let container = (parent : Identifier.ClassSignature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container (cf.cf_attributes) in + let doc = Doc_attr.attached_no_tag container (cf.cf_attributes) in match cf.cf_desc with | Tcf_val({txt = name; _}, mutable_, _, kind, _) -> let open InstanceVariable in @@ -306,7 +306,7 @@ let read_class_declaration env parent cld = let open Class in let id = Env.find_class_identifier env cld.ci_id_class in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container cld.ci_attributes in + let doc = Doc_attr.attached_no_tag container cld.ci_attributes in Cmi.mark_class_declaration cld.ci_decl; let virtual_ = (cld.ci_virt = Virtual) in let clparams = @@ -338,7 +338,9 @@ let rec read_module_expr env parent label_parent mexpr = match mexpr.mod_desc with | Tmod_ident _ -> Cmi.read_module_type env parent (Odoc_model.Compat.module_type mexpr.mod_type) - | Tmod_structure str -> Signature (read_structure env parent str) + | Tmod_structure str -> + let sg, () = read_structure Odoc_model.Semantics.Expect_none env parent str in + Signature sg #if OCAML_MAJOR = 4 && OCAML_MINOR >= 10 | Tmod_functor(parameter, res) -> let f_parameter, env = @@ -397,14 +399,8 @@ and read_module_binding env parent mb = #endif let id = (id :> Identifier.Module.t) in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container mb.mb_attributes in - let canonical = - let doc = List.map Odoc_model.Location_.value doc in - match List.find (function `Tag (`Canonical _) -> true | _ -> false) doc with - | exception Not_found -> None - | `Tag (`Canonical p) -> Some (p :> Path.Module.t) - | _ -> None - in + let doc, canonical = Doc_attr.attached Odoc_model.Semantics.Expect_canonical container mb.mb_attributes in + let canonical = (canonical :> Path.Module.t option) in let type_ = match unwrap_module_expr_desc mb.mb_expr.mod_desc with | Tmod_ident(p, _) -> Alias (Env.Path.read_module env p, None) @@ -510,7 +506,7 @@ and read_structure_item env parent item = and read_include env parent incl = let open Include in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container incl.incl_attributes in + let doc, status = Doc_attr.attached Odoc_model.Semantics.Expect_status container incl.incl_attributes in let decl_modty = match unwrap_module_expr_desc incl.incl_mod.mod_desc with | Tmod_ident(p, _) -> @@ -530,7 +526,7 @@ and read_include env parent incl = | Some m when not (contains_signature m) -> let decl = ModuleType m in let expansion = { content; shadowed; } in - [Include {parent; doc; decl; expansion; inline=false }] + [Include {parent; doc; decl; expansion; status }] | Some (ModuleType.U.Signature { items; _ }) -> items | _ -> @@ -542,21 +538,34 @@ and read_open env parent o = Open.{expansion} #endif -and read_structure env parent str = +and read_structure : + 'tags. 'tags Odoc_model.Semantics.handle_internal_tags -> _ -> _ -> _ -> + _ * 'tags = + fun internal_tags env parent str -> let env = Env.add_structure_tree_items parent str env in + let items, doc, tags = + let classify item = + match item.str_desc with + | Tstr_open _ -> Some `Open + | Tstr_attribute attr -> Some (`Attribute attr) + | _ -> None + in + Doc_attr.extract_top_comment internal_tags ~classify parent str.str_items + in let items = List.fold_left (fun items item -> List.rev_append (read_structure_item env parent item) items) - [] str.str_items + [] items |> List.rev in - let items, doc = Doc_attr.extract_top_comment items in - { items; compiled = false; doc } + ({ Signature.items; compiled = false; doc }, tags) let read_implementation root name impl = let id = `Root (root, Odoc_model.Names.ModuleName.make_std name) in - let sg = read_structure Env.empty id impl in - (id, sg) + let sg, canonical = + read_structure Odoc_model.Semantics.Expect_canonical Env.empty id impl + in + (id, sg, (canonical :> Odoc_model.Paths.Path.Module.t option)) let _ = Cmti.read_module_expr := read_module_expr diff --git a/src/loader/cmt.mli b/src/loader/cmt.mli index 4a4fed3cdc..fe72cc7e89 100644 --- a/src/loader/cmt.mli +++ b/src/loader/cmt.mli @@ -18,4 +18,8 @@ val read_implementation : Odoc_model.Paths.Identifier.ContainerPage.t -> string -> Typedtree.structure -> - Odoc_model.Paths.Identifier.RootModule.t * Odoc_model.Lang.Signature.t + Odoc_model.Paths.Identifier.RootModule.t + * Odoc_model.Lang.Signature.t + * Odoc_model.Paths.Path.Module.t option +(** Returns [id, sg, canonical_path]. [canonical_path] is the path set from the + [@canonical] tag. *) diff --git a/src/loader/cmti.ml b/src/loader/cmti.ml index a4b4cb9a02..a469ebf125 100644 --- a/src/loader/cmti.ml +++ b/src/loader/cmti.ml @@ -33,7 +33,6 @@ let opt_map f = function | Some x -> Some (f x) let read_label = Cmi.read_label -let canonical = Cmi.canonical let rec read_core_type env container ctyp = let open TypeExpr in @@ -117,7 +116,7 @@ let rec read_core_type env container ctyp = #if OCAML_MAJOR = 4 && OCAML_MINOR >= 06 let name = name.txt in #endif - let doc = Doc_attr.attached container attributes in + let doc = Doc_attr.attached_no_tag container attributes in Constructor {name; constant; arguments; doc} | Tinherit typ -> Type (read_core_type env container typ) end @@ -148,7 +147,7 @@ let read_value_description env parent vd = let open Signature in let id = Env.find_value_identifier env vd.val_id in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container vd.val_attributes in + let doc = Doc_attr.attached_no_tag container vd.val_attributes in let type_ = read_core_type env container vd.val_desc in match vd.val_prim with | [] -> Value {Value.id; doc; type_} @@ -189,7 +188,7 @@ let read_label_declaration env parent label_parent ld = let open Odoc_model.Names in let name = Ident.name ld.ld_id in let id = `Field(parent, FieldName.make_std name) in - let doc = Doc_attr.attached label_parent ld.ld_attributes in + let doc = Doc_attr.attached_no_tag label_parent ld.ld_attributes in let mutable_ = (ld.ld_mutable = Mutable) in let type_ = read_core_type env label_parent ld.ld_type in {id; doc; mutable_; type_} @@ -213,7 +212,7 @@ let read_constructor_declaration env parent cd = let id = `Constructor(parent, ConstructorName.make_std name) in let container = (parent : Identifier.DataType.t :> Identifier.Parent.t) in let label_container = (container :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached label_container cd.cd_attributes in + let doc = Doc_attr.attached_no_tag label_container cd.cd_attributes in let args = read_constructor_declaration_arguments env container label_container cd.cd_args @@ -253,8 +252,8 @@ let read_type_declaration env parent decl = let open TypeDecl in let id = Env.find_type_identifier env decl.typ_id in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container decl.typ_attributes in - let canonical = (canonical doc :> Path.Type.t option) in + let doc, canonical = Doc_attr.attached Odoc_model.Semantics.Expect_canonical container decl.typ_attributes in + let canonical = (canonical :> Path.Type.t option) in let equation = read_type_equation env container decl in let representation = read_type_kind env (id :> Identifier.DataType.t) decl.typ_kind in {id; doc; canonical; equation; representation} @@ -287,7 +286,7 @@ let read_extension_constructor env parent ext = let id = `Extension(parent, ExtensionName.make_std name) in let container = (parent : Identifier.Signature.t :> Identifier.Parent.t) in let label_container = (container :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached label_container ext.ext_attributes in + let doc = Doc_attr.attached_no_tag label_container ext.ext_attributes in match ext.ext_kind with | Text_rebind _ -> assert false | Text_decl(args, res) -> @@ -302,7 +301,7 @@ let read_type_extension env parent tyext = let open Extension in let type_path = Env.Path.read_type env tyext.tyext_path in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container tyext.tyext_attributes in + let doc = Doc_attr.attached_no_tag container tyext.tyext_attributes in let type_params = List.map read_type_parameter tyext.tyext_params in let private_ = (tyext.tyext_private = Private) in let constructors = @@ -317,7 +316,7 @@ let read_exception env parent (ext : extension_constructor) = let id = `Exception(parent, ExceptionName.make_std name) in let container = (parent : Identifier.Signature.t :> Identifier.Parent.t) in let label_container = (container :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached label_container ext.ext_attributes in + let doc = Doc_attr.attached_no_tag label_container ext.ext_attributes in match ext.ext_kind with | Text_rebind _ -> assert false | Text_decl(args, res) -> @@ -333,7 +332,7 @@ let rec read_class_type_field env parent ctf = let open Odoc_model.Names in let container = (parent : Identifier.ClassSignature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container ctf.ctf_attributes in + let doc = Doc_attr.attached_no_tag container ctf.ctf_attributes in match ctf.ctf_desc with | Tctf_val(name, mutable_, virtual_, typ) -> let open InstanceVariable in @@ -396,7 +395,7 @@ let read_class_type_declaration env parent cltd = let open ClassType in let id = Env.find_class_type_identifier env cltd.ci_id_class_type in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container cltd.ci_attributes in + let doc = Doc_attr.attached_no_tag container cltd.ci_attributes in let virtual_ = (cltd.ci_virt = Virtual) in let params = List.map read_type_parameter cltd.ci_params in let expr = read_class_signature env (id :> Identifier.ClassSignature.t) container cltd.ci_expr in @@ -434,7 +433,7 @@ let read_class_description env parent cld = let open Class in let id = Env.find_class_identifier env cld.ci_id_class in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container cld.ci_attributes in + let doc = Doc_attr.attached_no_tag container cld.ci_attributes in let virtual_ = (cld.ci_virt = Virtual) in let params = List.map read_type_parameter cld.ci_params in let type_ = read_class_type env (id :> Identifier.ClassSignature.t) container cld.ci_expr in @@ -476,7 +475,9 @@ and read_module_type env parent label_parent mty = let open ModuleType in match mty.mty_desc with | Tmty_ident(p, _) -> Path { p_path = Env.Path.read_module_type env p; p_expansion = None } - | Tmty_signature sg -> Signature (read_signature env parent sg) + | Tmty_signature sg -> + let sg, () = read_signature Odoc_model.Semantics.Expect_none env parent sg in + Signature sg #if OCAML_MAJOR = 4 && OCAML_MINOR >= 10 | Tmty_functor(parameter, res) -> let f_parameter, env = @@ -539,8 +540,8 @@ and read_module_type_declaration env parent mtd = let open ModuleType in let id = Env.find_module_type env mtd.mtd_id in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container mtd.mtd_attributes in - let canonical = (canonical doc :> Path.ModuleType.t option) in + let doc, canonical = Doc_attr.attached Odoc_model.Semantics.Expect_canonical container mtd.mtd_attributes in + let canonical = (canonical :> Path.ModuleType.t option) in let expr = opt_map (read_module_type env (id :> Identifier.Signature.t) container) mtd.mtd_type in {id; doc; canonical; expr;} @@ -557,8 +558,8 @@ and read_module_declaration env parent md = let id = (id :> Identifier.Module.t) in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container md.md_attributes in - let canonical = (canonical doc :> Path.Module.t option) in + let doc, canonical = Doc_attr.attached Odoc_model.Semantics.Expect_canonical container md.md_attributes in + let canonical = (canonical :> Path.Module.t option) in let type_ = match md.md_type.mty_desc with | Tmty_alias(p, _) -> Alias (Env.Path.read_module env p, None) @@ -660,7 +661,7 @@ and read_module_substitution env parent ms = let open ModuleSubstitution in let id = Env.find_module_identifier env ms.ms_id in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container ms.ms_attributes in + let doc, () = Doc_attr.attached Odoc_model.Semantics.Expect_none container ms.ms_attributes in let manifest = Env.Path.read_module env ms.ms_manifest in { id; doc; manifest } #endif @@ -668,7 +669,7 @@ and read_module_substitution env parent ms = and read_include env parent incl = let open Include in let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in - let doc = Doc_attr.attached container incl.incl_attributes in + let doc, status = Doc_attr.attached Odoc_model.Semantics.Expect_status container incl.incl_attributes in let content, shadowed = Cmi.read_signature_noenv env parent (Odoc_model.Compat.signature incl.incl_type) in let expr = read_module_type env parent container incl.incl_mod in let rec contains_signature = function @@ -691,7 +692,7 @@ and read_include env parent incl = | Some uexpr when not (contains_signature uexpr) -> let decl = Include.ModuleType uexpr in let expansion = { content; shadowed; } in - [Include {parent; doc; decl; expansion; inline=false }] + [Include {parent; doc; decl; expansion; status }] | Some ModuleType.U.Signature { items; _ } when is_inlinable items -> items | _ -> @@ -703,19 +704,32 @@ and read_open env parent o = { expansion } #endif -and read_signature env parent sg = +and read_signature : + 'tags. 'tags Odoc_model.Semantics.handle_internal_tags -> _ -> _ -> _ -> + _ * 'tags = + fun internal_tags env parent sg -> let env = Env.add_signature_tree_items parent sg env in + let items, doc, tags = + let classify item = + match item.sig_desc with + | Tsig_attribute attr -> Some (`Attribute attr) + | Tsig_open _ -> Some `Open + | _ -> None + in + Doc_attr.extract_top_comment internal_tags ~classify parent sg.sig_items + in let items = List.fold_left (fun items item -> List.rev_append (read_signature_item env parent item) items) - [] sg.sig_items + [] items |> List.rev in - let items, doc = Doc_attr.extract_top_comment items in - { items; compiled = false; doc } + ({ Signature.items; compiled = false; doc }, tags) let read_interface root name intf = let id = `Root (root, Odoc_model.Names.ModuleName.make_std name) in - let sg = read_signature Env.empty id intf in - (id, sg) + let sg, canonical = + read_signature Odoc_model.Semantics.Expect_canonical Env.empty id intf + in + (id, sg, (canonical :> Odoc_model.Paths.Path.Module.t option)) diff --git a/src/loader/cmti.mli b/src/loader/cmti.mli index ffe099e711..515dbccdf1 100644 --- a/src/loader/cmti.mli +++ b/src/loader/cmti.mli @@ -28,7 +28,11 @@ val read_interface : Odoc_model.Paths.Identifier.ContainerPage.t -> string -> Typedtree.signature -> - Paths.Identifier.RootModule.t * Odoc_model.Lang.Signature.t + Paths.Identifier.RootModule.t + * Odoc_model.Lang.Signature.t + * Paths.Path.Module.t option +(** Returns [id, sg, canonical_path]. [canonical_path] is the path set from the + [@canonical] tag. *) val read_module_type : Ident_env.t -> diff --git a/src/loader/doc_attr.ml b/src/loader/doc_attr.ml index d09509fce7..e2b30aedfa 100644 --- a/src/loader/doc_attr.ml +++ b/src/loader/doc_attr.ml @@ -14,13 +14,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *) -open Result open Odoc_model module Paths = Odoc_model.Paths - let empty_body = [] let empty : Odoc_model.Comment.docs = empty_body @@ -54,10 +52,17 @@ let load_payload : Parsetree.payload -> string * Location.t = function end | _ -> None -let attached parent attrs = - let ocaml_deprecated = ref None in - let rec loop first nb_deprecated acc - : _ -> (Odoc_model.Comment.docs, Odoc_model.Error.t) result = +let pad_loc loc = + { loc.Location.loc_start with pos_cnum = loc.loc_start.pos_cnum + 3 } + +let ast_to_comment ~internal_tags parent ast_docs = + Error.accumulate_warnings (fun warnings -> + Odoc_model.Semantics.ast_to_comment warnings ~internal_tags + ~sections_allowed:`All ~parent_of_sections:parent ast_docs) + |> Error.raise_warnings + +let attached internal_tags parent attrs = + let rec loop acc = function #if OCAML_MAJOR = 4 && OCAML_MINOR >= 08 | {Parsetree.attr_name = { Location.txt = @@ -66,55 +71,49 @@ let attached parent attrs = | ({Location.txt = ("doc" | "ocaml.doc"); loc = _loc}, attr_payload) :: rest -> begin #endif - match load_payload attr_payload with - | (str, loc) -> begin - let start_pos = loc.Location.loc_start in - let start_pos = - {start_pos with pos_cnum = start_pos.pos_cnum + 3} in - let parsed = - Odoc_model.Semantics.parse_comment - ~sections_allowed:`All - ~containing_definition:parent - ~location:start_pos - ~text:str - |> Odoc_model.Error.raise_warnings - in - loop false 0 (acc @ parsed) rest - end - end - | _ :: rest -> loop first nb_deprecated acc rest - | [] -> begin - match nb_deprecated, !ocaml_deprecated with - | 0, Some _tag -> Ok acc - | _, _ -> Ok acc + let str, loc = load_payload attr_payload in + let ast_docs = + Odoc_parser.parse_comment ~location:(pad_loc loc) ~text:str + |> Error.raise_parser_warnings + in + loop (List.rev_append ast_docs acc) rest end + | _ :: rest -> loop acc rest + | [] -> List.rev acc in - loop true 0 empty_body attrs - |> Odoc_model.Error.to_exception - -let read_string parent loc str : Odoc_model.Comment.docs_or_stop = - let start_pos = loc.Location.loc_start in - let doc : Odoc_model.Comment.docs = - Odoc_model.Semantics.parse_comment - ~sections_allowed:`All - ~containing_definition:parent - ~location:start_pos - ~text:str - |> Odoc_model.Error.raise_warnings + let ast_docs = loop [] attrs in + ast_to_comment ~internal_tags parent ast_docs + +let attached_no_tag parent attrs = + let x, () = attached Semantics.Expect_none parent attrs in + x + +let read_string internal_tags parent location str = + Odoc_model.Semantics.parse_comment + ~internal_tags + ~sections_allowed:`All + ~containing_definition:parent + ~location + ~text:str + |> Odoc_model.Error.raise_warnings + +let read_string_comment internal_tags parent loc str = + read_string internal_tags parent (pad_loc loc) str + +let page parent loc str = + let doc, () = + read_string Odoc_model.Semantics.Expect_none parent loc.Location.loc_start + str in `Docs doc -let page = read_string - -let standalone parent(attr : Parsetree.attribute): Odoc_model.Comment.docs_or_stop option = +let standalone parent (attr : Parsetree.attribute) : + Odoc_model.Comment.docs_or_stop option = match parse_attribute attr with | Some ("/*", _loc) -> Some `Stop | Some (str, loc) -> - let loc' = - { loc with - loc_start = { loc.loc_start with pos_cnum = loc.loc_start.pos_cnum + 3 } } - in - Some (read_string parent loc' str) + let doc, () = read_string_comment Semantics.Expect_none parent loc str in + Some (`Docs doc) | _ -> None let standalone_multiple parent attrs = @@ -128,14 +127,32 @@ let standalone_multiple parent attrs = in List.rev coms -let rec extract_top_comment items = - match items with - | Lang.Signature.Comment (`Docs doc) :: tl -> (tl, doc) - | (Open _ as skipped) :: tl -> - (* Skip opens *) - let items, doc = extract_top_comment tl in - (skipped :: items, doc) - | _ -> (items, empty) +let extract_top_comment internal_tags ~classify parent items = + let rec extract ~classify = function + | hd :: tl as items -> ( + match classify hd with + | Some (`Attribute attr) -> ( + match parse_attribute attr with + | Some (text, loc) -> + let ast_docs = + Odoc_parser.parse_comment ~location:(pad_loc loc) ~text + |> Error.raise_parser_warnings + in + (tl, ast_docs) + | None -> (items, [])) + | Some `Open -> + let items, ast_docs = extract ~classify tl in + (hd :: items, ast_docs) + | None -> (items, [])) + | [] -> ([], []) + in + let items, ast_docs = extract ~classify items in + let docs, tags = + ast_to_comment ~internal_tags + (parent : Paths.Identifier.Signature.t :> Paths.Identifier.LabelParent.t) + ast_docs + in + (items, docs, tags) let extract_top_comment_class items = match items with diff --git a/src/loader/doc_attr.mli b/src/loader/doc_attr.mli index 88ae02372f..48b2927c2c 100644 --- a/src/loader/doc_attr.mli +++ b/src/loader/doc_attr.mli @@ -22,9 +22,16 @@ val empty : Odoc_model.Comment.docs val parse_attribute : Parsetree.attribute -> (string * Location.t) option val attached : + 'tags Semantics.handle_internal_tags -> + Paths.Identifier.LabelParent.t -> + Parsetree.attributes -> + Odoc_model.Comment.docs * 'tags + +val attached_no_tag : Paths.Identifier.LabelParent.t -> Parsetree.attributes -> Odoc_model.Comment.docs +(** Shortcut for [attached Semantics.Expect_none]. *) val page : Paths.Identifier.LabelParent.t -> @@ -49,7 +56,11 @@ val standalone_multiple : Odoc_model.Comment.docs_or_stop list val extract_top_comment : - Lang.Signature.item list -> Lang.Signature.item list * Comment.docs + 'tags Semantics.handle_internal_tags -> + classify:('item -> [ `Attribute of Parsetree.attribute | `Open ] option) -> + Paths.Identifier.Signature.t -> + 'item list -> + 'item list * Comment.docs * 'tags (** Extract the first comment of a signature. Returns the remaining items. *) val extract_top_comment_class : diff --git a/src/loader/odoc_loader.ml b/src/loader/odoc_loader.ml index e5de557885..a8af589ccc 100644 --- a/src/loader/odoc_loader.ml +++ b/src/loader/odoc_loader.ml @@ -77,11 +77,8 @@ let make_compilation_unit ~make_root ~imports ~interface ?sourcefile ~name ~id } let compilation_unit_of_sig ~make_root ~imports ~interface ?sourcefile ~name ~id - sg = + ?canonical sg = let content = Odoc_model.Lang.Compilation_unit.Module sg in - let canonical = - (Cmi.canonical sg.doc :> Odoc_model.Paths.Path.Module.t option) - in make_compilation_unit ~make_root ~imports ~interface ?sourcefile ~name ~id ?canonical content @@ -98,9 +95,9 @@ let read_cmti ~make_root ~parent ~filename () = cmt_info.cmt_source_digest, cmt_info.cmt_builddir ) in - let id, sg = Cmti.read_interface parent name intf in + let id, sg, canonical = Cmti.read_interface parent name intf in compilation_unit_of_sig ~make_root ~imports:cmt_info.cmt_imports - ~interface ~sourcefile ~name ~id sg) + ~interface ~sourcefile ~name ~id ?canonical sg) | _ -> raise Not_an_interface let read_cmt ~make_root ~parent ~filename () = @@ -141,9 +138,9 @@ let read_cmt ~make_root ~parent ~filename () = make_compilation_unit ~make_root ~imports ~interface ~sourcefile ~name ~id content | Implementation impl -> - let id, sg = Cmt.read_implementation parent name impl in + let id, sg, canonical = Cmt.read_implementation parent name impl in compilation_unit_of_sig ~make_root ~imports ~interface ~sourcefile - ~name ~id sg + ~name ~id ?canonical sg | _ -> raise Not_an_implementation) let read_cmi ~make_root ~parent ~filename () = diff --git a/src/model/comment.ml b/src/model/comment.ml index 811c2aa16f..1598555a08 100644 --- a/src/model/comment.ml +++ b/src/model/comment.ml @@ -47,8 +47,6 @@ type nestable_block_element = [ `Unordered | `Ordered ] * nestable_block_element with_location list list ] -type canonical_path = [ `Root of string | `Dot of Path.Module.t * string ] - type tag = [ `Author of string | `Deprecated of nestable_block_element with_location list @@ -61,11 +59,7 @@ type tag = * nestable_block_element with_location list | `Since of string | `Before of string * nestable_block_element with_location list - | `Version of string - | `Canonical of canonical_path - | `Inline - | `Open - | `Closed ] + | `Version of string ] type heading_level = [ `Title diff --git a/src/model/error.ml b/src/model/error.ml index 5a92c97b59..f01d070262 100644 --- a/src/model/error.ml +++ b/src/model/error.ml @@ -76,8 +76,13 @@ let with_ref r f = let raised_warnings = ref [] +let raise_warnings' warnings = + raised_warnings := List.rev_append warnings !raised_warnings + +let raise_warning t = raised_warnings := t :: !raised_warnings + let raise_warnings with_warnings = - raised_warnings := List.rev_append with_warnings.warnings !raised_warnings; + raise_warnings' with_warnings.warnings; with_warnings.value let catch_warnings f = @@ -110,3 +115,7 @@ let handle_errors_and_warnings ~warn_error = function let t_of_parser_t : Odoc_parser.Error.t -> t = fun x -> (`With_full_location x :> t) + +let raise_parser_warnings { Odoc_parser.Error.value; warnings } = + raise_warnings' (List.map t_of_parser_t warnings); + value diff --git a/src/model/error.mli b/src/model/error.mli index e3bea4d640..076b87bac9 100644 --- a/src/model/error.mli +++ b/src/model/error.mli @@ -33,6 +33,9 @@ val accumulate_warnings : (warning_accumulator -> 'a) -> 'a with_warnings val warning : warning_accumulator -> t -> unit +val raise_warning : t -> unit +(** Raise a warning that need to be caught with [catch_warnings]. *) + val raise_warnings : 'a with_warnings -> 'a (** Accumulate warnings into a global variable. See [catch_warnings]. *) @@ -56,3 +59,5 @@ val handle_errors_and_warnings : [catch_errors_and_warnings]. Error case is converted into a [`Msg]. *) val t_of_parser_t : Odoc_parser.Error.t -> t + +val raise_parser_warnings : 'a Odoc_parser.Error.with_warnings -> 'a diff --git a/src/model/lang.ml b/src/model/lang.ml index 9f5ed95000..3ecdd23d5e 100644 --- a/src/model/lang.ml +++ b/src/model/lang.ml @@ -169,8 +169,8 @@ and Include : sig type t = { parent : Identifier.Signature.t; doc : Comment.docs; + status : [ `Inline | `Closed | `Open | `Default ]; decl : decl; - inline : bool; expansion : expansion; } end = diff --git a/src/model/semantics.ml b/src/model/semantics.ml index da14740d6e..f2deb8ccda 100644 --- a/src/model/semantics.ml +++ b/src/model/semantics.ml @@ -1,6 +1,66 @@ module Location = Location_ +module Ast = Odoc_parser.Ast open Result +type internal_tags_removed = + [ `Tag of Ast.external_tag + | `Heading of Ast.heading + | Ast.nestable_block_element ] +(** {!Ast.block_element} without internal tags. *) + +type _ handle_internal_tags = + | Expect_status + : [ `Default | `Inline | `Open | `Closed ] handle_internal_tags + | Expect_canonical + : [ `Dot of Paths.Path.Module.t * string ] option handle_internal_tags + | Expect_none : unit handle_internal_tags + +let describe_internal_tag = function + | `Canonical _ -> "@canonical" + | `Inline -> "@inline" + | `Open -> "@open" + | `Closed -> "@closed" + +let warn_unexpected_tag { Location.value; location } = + Error.raise_warning + @@ Error.make "Unexpected tag '%s' at this location." + (describe_internal_tag value) + location + +let warn_root_canonical location = + Error.raise_warning + @@ Error.make "Canonical paths must contain a dot, eg. X.Y." location + +let rec find_tag f = function + | [] -> None + | hd :: tl -> ( + match f hd.Location.value with + | Some x -> Some (x, hd.location) + | None -> + warn_unexpected_tag hd; + find_tag f tl) + +let handle_internal_tags (type a) tags : a handle_internal_tags -> a = function + | Expect_status -> ( + match + find_tag + (function (`Inline | `Open | `Closed) as t -> Some t | _ -> None) + tags + with + | Some (status, _) -> status + | None -> `Default) + | Expect_canonical -> ( + match find_tag (function `Canonical p -> Some p | _ -> None) tags with + | Some (`Root _, location) -> + warn_root_canonical location; + None + | Some ((`Dot _ as p), _) -> Some p + | None -> None) + | Expect_none -> + (* Will raise warnings. *) + ignore (find_tag (fun _ -> None) tags); + () + (* Errors *) let invalid_raw_markup_target : string -> Location.span -> Error.t = Error.make ~suggestion:"try '{%html:...%}'." @@ -195,24 +255,14 @@ and nestable_block_elements status elements = let tag : location:Location.span -> status -> - Odoc_parser.Ast.tag -> + Ast.external_tag -> ( Comment.block_element with_location, - Odoc_parser.Ast.block_element with_location ) + internal_tags_removed with_location ) Result.result = fun ~location status tag -> let ok t = Result.Ok (Location.at location (`Tag t)) in match tag with - | (`Author _ | `Since _ | `Version _ | `Inline | `Open | `Closed) as tag -> - ok tag - | `Canonical { value = s; location = r_location } -> ( - let path = Reference.read_path_longident r_location s in - match path with - | Result.Ok path -> ok (`Canonical path) - | Result.Error e -> - Error.warning status.warnings e; - let placeholder = [ `Word "@canonical"; `Space " "; `Code_span s ] in - let placeholder = List.map (Location.at location) placeholder in - Error (Location.at location (`Paragraph placeholder))) + | (`Author _ | `Since _ | `Version _) as tag -> ok tag | `Deprecated content -> ok (`Deprecated (nestable_block_elements status content)) | `Param (name, content) -> @@ -350,15 +400,11 @@ let validate_first_page_heading status ast_element = Error.warning status.warnings (page_heading_required filename)) | _not_a_page -> () -let top_level_block_elements : - status -> - Odoc_parser.Ast.block_element with_location list -> - Comment.block_element with_location list = - fun status ast_elements -> +let top_level_block_elements status ast_elements = let rec traverse : top_heading_level:int option -> Comment.block_element with_location list -> - Odoc_parser.Ast.block_element with_location list -> + internal_tags_removed with_location list -> Comment.block_element with_location list = fun ~top_heading_level comment_elements_acc ast_elements -> match ast_elements with @@ -401,15 +447,43 @@ let top_level_block_elements : in traverse ~top_heading_level [] ast_elements -let ast_to_comment warnings ~sections_allowed ~parent_of_sections ast = +let strip_internal_tags status ast : + internal_tags_removed with_location list * _ = + let rec loop tags ast' = function + | ({ Location.value = `Tag (#Ast.internal_tag as tag); _ } as wloc) :: tl + -> ( + let next tag = loop ({ wloc with value = tag } :: tags) ast' tl in + match tag with + | (`Inline | `Open | `Closed) as tag -> next tag + | `Canonical { Location.value = s; location = r_location } -> ( + match Reference.read_path_longident r_location s with + | Result.Ok path -> next (`Canonical path) + | Result.Error e -> + Error.warning status.warnings e; + loop tags ast' tl)) + | ({ + value = + `Tag #Ast.external_tag | `Heading _ | #Ast.nestable_block_element; + _; + } as hd) + :: tl -> + loop tags (hd :: ast') tl + | [] -> (List.rev ast', List.rev tags) + in + loop [] [] ast + +let ast_to_comment warnings ~internal_tags ~sections_allowed ~parent_of_sections + ast = let status = { warnings; sections_allowed; parent_of_sections } in - top_level_block_elements status ast + let ast, tags = strip_internal_tags status ast in + (top_level_block_elements status ast, handle_internal_tags tags internal_tags) -let parse_comment ~sections_allowed ~containing_definition ~location ~text = +let parse_comment ~internal_tags ~sections_allowed ~containing_definition + ~location ~text = let ast = Odoc_parser.parse_comment ~location ~text in let comment = Error.accumulate_warnings (fun warnings -> - ast_to_comment warnings ~sections_allowed + ast_to_comment warnings ~internal_tags ~sections_allowed ~parent_of_sections:containing_definition ast.Odoc_parser.Error.value) in { diff --git a/src/model/semantics.mli b/src/model/semantics.mli index 3a1137cfd4..ba76f17c39 100644 --- a/src/model/semantics.mli +++ b/src/model/semantics.mli @@ -1,16 +1,26 @@ +(** How to handle internal tags. *) +type _ handle_internal_tags = + | Expect_status + : [ `Default | `Inline | `Open | `Closed ] handle_internal_tags + | Expect_canonical + : [ `Dot of Paths.Path.Module.t * string ] option handle_internal_tags + | Expect_none : unit handle_internal_tags + val ast_to_comment : Error.warning_accumulator -> + internal_tags:'tags handle_internal_tags -> sections_allowed:Odoc_parser.Ast.sections_allowed -> parent_of_sections:Paths.Identifier.LabelParent.t -> Odoc_parser.Ast.docs -> - Comment.docs + Comment.docs * 'tags val parse_comment : + internal_tags:'tags handle_internal_tags -> sections_allowed:Odoc_parser.Ast.sections_allowed -> containing_definition:Paths.Identifier.LabelParent.t -> location:Lexing.position -> text:string -> - Comment.docs Error.with_warnings + (Comment.docs * 'tags) Error.with_warnings val parse_reference : string -> (Paths.Reference.t, [> `Msg of string ]) Result.result diff --git a/src/model_desc/comment_desc.ml b/src/model_desc/comment_desc.ml index 3b03a08cab..aab5f62528 100644 --- a/src/model_desc/comment_desc.ml +++ b/src/model_desc/comment_desc.ml @@ -35,11 +35,7 @@ and general_tag = | `See of [ `Url | `File | `Document ] * string * general_docs | `Since of string | `Before of string * general_docs - | `Version of string - | `Canonical of Paths.Path.t - | `Inline - | `Open - | `Closed ] + | `Version of string ] and general_docs = general_block_element with_location list @@ -121,11 +117,7 @@ and tag : general_tag t = C ("`See", (x1, x2, x3), Triple (url_kind, string, docs)) | `Since x -> C ("`Since", x, string) | `Before (x1, x2) -> C ("`Before", (x1, x2), Pair (string, docs)) - | `Version x -> C ("`Version", x, string) - | `Canonical x1 -> C ("`Canonical", x1, path) - | `Inline -> C0 "`Inline" - | `Open -> C0 "`Open" - | `Closed -> C0 "`Closed") + | `Version x -> C ("`Version", x, string)) and docs : general_docs t = List (Indirect (ignore_loc, block_element)) diff --git a/src/model_desc/lang_desc.ml b/src/model_desc/lang_desc.ml index bf1723ab00..584a0ccf7d 100644 --- a/src/model_desc/lang_desc.ml +++ b/src/model_desc/lang_desc.ml @@ -8,6 +8,14 @@ module Digest = struct let t : Digest.t t = To_string (fun _ -> "") end +let inline_status = + Variant + (function + | `Default -> C0 "`Default" + | `Open -> C0 "`Open" + | `Closed -> C0 "`Closed" + | `Inline -> C0 "`Inline") + (** {3 Module} *) let rec module_decl = @@ -251,7 +259,7 @@ and include_t = F ("parent", (fun t -> t.parent), identifier); F ("doc", (fun t -> t.doc), docs); F ("decl", (fun t -> t.decl), include_decl); - F ("inline", (fun t -> t.inline), bool); + F ("status", (fun t -> t.status), inline_status); F ("expansion", (fun t -> t.expansion), include_expansion); ] diff --git a/src/parser/ast.ml b/src/parser/ast.ml index c2f1efe09a..dd08f47be0 100644 --- a/src/parser/ast.ml +++ b/src/parser/ast.ml @@ -24,7 +24,10 @@ type nestable_block_element = * [ `Light | `Heavy ] * nestable_block_element with_location list list ] -type tag = +type internal_tag = + [ `Canonical of string with_location | `Inline | `Open | `Closed ] + +type external_tag = [ `Author of string | `Deprecated of nestable_block_element with_location list | `Param of string * nestable_block_element with_location list @@ -36,16 +39,14 @@ type tag = * nestable_block_element with_location list | `Since of string | `Before of string * nestable_block_element with_location list - | `Version of string - | `Canonical of string with_location - | `Inline - | `Open - | `Closed ] + | `Version of string ] + +type tag = [ internal_tag | external_tag ] + +type heading = int * string option * inline_element with_location list type block_element = - [ nestable_block_element - | `Heading of int * string option * inline_element with_location list - | `Tag of tag ] + [ nestable_block_element | `Heading of heading | `Tag of tag ] type docs = block_element with_location list diff --git a/src/xref2/component.ml b/src/xref2/component.ml index 4893d1d5b1..3691cb525e 100644 --- a/src/xref2/component.ml +++ b/src/xref2/component.ml @@ -327,6 +327,7 @@ and Include : sig type t = { parent : Odoc_model.Paths.Identifier.Signature.t; doc : CComment.docs; + status : [ `Default | `Inline | `Closed | `Open ]; shadowed : Odoc_model.Lang.Include.shadowed; expansion_ : Signature.t; decl : decl; @@ -2117,6 +2118,7 @@ module Of_Lang = struct doc = docs ident_map i.doc; shadowed = i.expansion.shadowed; expansion_ = apply_sig_map ident_map i.expansion.content; + status = i.status; decl; } diff --git a/src/xref2/component.mli b/src/xref2/component.mli index 042803853e..2ebb0dc638 100644 --- a/src/xref2/component.mli +++ b/src/xref2/component.mli @@ -305,6 +305,7 @@ and Include : sig type t = { parent : Odoc_model.Paths.Identifier.Signature.t; doc : CComment.docs; + status : [ `Default | `Inline | `Closed | `Open ]; shadowed : Odoc_model.Lang.Include.shadowed; expansion_ : Signature.t; decl : decl; diff --git a/src/xref2/lang_of.ml b/src/xref2/lang_of.ml index 09ce01a655..4b9437fea3 100644 --- a/src/xref2/lang_of.ml +++ b/src/xref2/lang_of.ml @@ -598,7 +598,7 @@ and include_ parent map i = { map with shadowed = combine_shadowed map.shadowed i.shadowed } i.expansion_; }; - inline = false; + status = i.status; } and open_ parent map o = diff --git a/src/xref2/link.ml b/src/xref2/link.ml index c50ecf1f6f..560ebce073 100644 --- a/src/xref2/link.ml +++ b/src/xref2/link.ml @@ -422,15 +422,11 @@ and include_ : Env.t -> Include.t -> Include.t = (* Format.eprintf "include_: %a\n%!" Component.Fmt.module_decl (Component.Of_Lang.(module_decl empty i.decl)); *) let doc = comment_docs env i.parent i.doc in - let should_be_inlined = - let is_inline_tag element = element.Location_.value = `Tag `Inline in - List.exists is_inline_tag doc - in let expansion = let content = signature env i.parent i.expansion.content in { i.expansion with content } in - { i with decl; expansion; inline = should_be_inlined; doc } + { i with decl; expansion; doc } and functor_parameter_parameter : Env.t -> FunctorParameter.parameter -> FunctorParameter.parameter = diff --git a/test/model/dune b/test/model/dune index 82a5bc98eb..eaecf8649c 100644 --- a/test/model/dune +++ b/test/model/dune @@ -1,8 +1,10 @@ -(library - (name odoc_model_test) - (inline_tests) - (enabled_if - (>= %{ocaml_version} 4.04.1)) - (preprocess - (pps ppx_expect)) - (libraries sexplib0 odoc_model type_desc_to_yojson)) +; Use the 'compile' helper program defined in xref2 tests + +(env + (_ + (binaries + (../odoc_print/odoc_print.exe as odoc_print) + (../xref2/compile.exe as compile)))) + +(cram + (deps %{bin:odoc} %{bin:odoc_print} %{bin:compile})) diff --git a/test/model/internal_tags.t/bad.mli b/test/model/internal_tags.t/bad.mli new file mode 100644 index 0000000000..c447a1badc --- /dev/null +++ b/test/model/internal_tags.t/bad.mli @@ -0,0 +1,22 @@ +(** Status tags in the top-comment. + + @inline *) + +(** Canonical on an [include]. + + @canonical X.Y *) +include sig end + +(** Canonical on a value. + + @canonical X.x *) +val x : int + +(** Canonical in a floating comment. + + @canonical X.Y *) + +(** Status tags on a value. + + @inline *) +val x : int diff --git a/test/model/internal_tags.t/good.mli b/test/model/internal_tags.t/good.mli new file mode 100644 index 0000000000..cb62b6d600 --- /dev/null +++ b/test/model/internal_tags.t/good.mli @@ -0,0 +1,22 @@ +(** Canonical tag in the top-comment + + @canonical A.B *) + +module type T = sig type t end + +include T +(** Status tags on an [include]. Only the first one will be taken into account. + + @open + @closed + @inline *) + +type u +(** Canonical on a type. + + @canonical A.u *) + +module M : sig end +(** Canonical on a module. + + @canonical A.B *) diff --git a/test/model/internal_tags.t/run.t b/test/model/internal_tags.t/run.t new file mode 100644 index 0000000000..18b041bb37 --- /dev/null +++ b/test/model/internal_tags.t/run.t @@ -0,0 +1,19 @@ +Test handling of internal tags. +We expect no warning for "good.mli". The code already ensures that either tags +are handled of a warning is emitted. + + $ compile good.mli + +We expect warnings to be emitted for each bad tags: + + $ compile bad.mli + File "bad.mli", line 3, characters 4-11: + Unexpected tag '@inline' at this location. + File "bad.mli", line 7, characters 4-19: + Unexpected tag '@canonical' at this location. + File "bad.mli", line 12, characters 4-19: + Unexpected tag '@canonical' at this location. + File "bad.mli", line 17, characters 4-19: + Unexpected tag '@canonical' at this location. + File "bad.mli", line 21, characters 4-11: + Unexpected tag '@inline' at this location. diff --git a/test/model/semantics/dune b/test/model/semantics/dune new file mode 100644 index 0000000000..49f806d0d1 --- /dev/null +++ b/test/model/semantics/dune @@ -0,0 +1,8 @@ +(library + (name odoc_model_semantics_test) + (inline_tests) + (enabled_if + (>= %{ocaml_version} 4.04.1)) + (preprocess + (pps ppx_expect)) + (libraries sexplib0 odoc_model type_desc_to_yojson)) diff --git a/test/model/test.ml b/test/model/semantics/test.ml similarity index 98% rename from test/model/test.ml rename to test/model/semantics/test.ml index 8dafae3823..1aff3f03d2 100644 --- a/test/model/test.ml +++ b/test/model/semantics/test.ml @@ -7,10 +7,10 @@ let warning_desc = Type_desc.To_string Error.to_string let parser_output_desc = let open Odoc_model.Error in - let open Odoc_model_desc.Type_desc in + let open Type_desc in Record [ - F ("value", (fun t -> t.value), Comment_desc.docs); + F ("value", (fun t -> fst t.value), Comment_desc.docs); F ("warnings", (fun t -> t.warnings), List warning_desc); ] @@ -27,8 +27,8 @@ let test ?(sections_allowed = `No_titles) } in let parser_output = - Semantics.parse_comment ~sections_allowed ~containing_definition:dummy_page - ~location ~text:str + Semantics.parse_comment ~internal_tags:Odoc_model.Semantics.Expect_none + ~sections_allowed ~containing_definition:dummy_page ~location ~text:str in let print_json_desc desc t = let yojson = Type_desc_to_yojson.to_yojson desc t in @@ -1834,7 +1834,8 @@ let%expect_test _ = let basic = test "@author Foo Bar"; [%expect - {| { "value": [ { "`Tag": { "`Author": "Foo Bar" } } ], "warnings": [] } |}] + {| + { "value": [ { "`Tag": { "`Author": "Foo Bar" } } ], "warnings": [] } |}] let empty = test "@author"; @@ -1861,22 +1862,26 @@ let%expect_test _ = let extra_whitespace = test "@author Foo Bar"; [%expect - {| { "value": [ { "`Tag": { "`Author": "Foo Bar" } } ], "warnings": [] } |}] + {| + { "value": [ { "`Tag": { "`Author": "Foo Bar" } } ], "warnings": [] } |}] let newline = test "@author Foo Bar"; [%expect - {| { "value": [ { "`Tag": { "`Author": "Foo Bar" } } ], "warnings": [] } |}] + {| + { "value": [ { "`Tag": { "`Author": "Foo Bar" } } ], "warnings": [] } |}] let cr_lf = test "@author Foo Bar"; [%expect - {| { "value": [ { "`Tag": { "`Author": "Foo Bar" } } ], "warnings": [] } |}] + {| + { "value": [ { "`Tag": { "`Author": "Foo Bar" } } ], "warnings": [] } |}] let blank_line = test "@author Foo Bar"; [%expect - {| { "value": [ { "`Tag": { "`Author": "Foo Bar" } } ], "warnings": [] } |}] + {| + { "value": [ { "`Tag": { "`Author": "Foo Bar" } } ], "warnings": [] } |}] let followed_by_junk = test "@author Foo\nbar"; @@ -2027,12 +2032,14 @@ let%expect_test _ = let in_author = test "@author Foo @author Bar"; [%expect - {| { "value": [ { "`Tag": { "`Author": "Foo @author Bar" } } ], "warnings": [] } |}] + {| + { "value": [ { "`Tag": { "`Author": "Foo @author Bar" } } ], "warnings": [] } |}] let in_author_at_start = test "@author @author Foo"; [%expect - {| { "value": [ { "`Tag": { "`Author": "@author Foo" } } ], "warnings": [] } |}] + {| + { "value": [ { "`Tag": { "`Author": "@author Foo" } } ], "warnings": [] } |}] let preceded_by_paragraph = test "foo\n@author Bar"; @@ -2049,7 +2056,8 @@ let%expect_test _ = let no_markup = test "@author Foo [Bar]"; [%expect - {| { "value": [ { "`Tag": { "`Author": "Foo [Bar]" } } ], "warnings": [] } |}] + {| + { "value": [ { "`Tag": { "`Author": "Foo [Bar]" } } ], "warnings": [] } |}] let in_paragraph = test "foo @author Bar"; @@ -2294,12 +2302,14 @@ let%expect_test _ = let in_code_block = test "{[@author Foo]}"; [%expect - {| { "value": [ { "`Code_block": "@author Foo" } ], "warnings": [] } |}] + {| + { "value": [ { "`Code_block": "@author Foo" } ], "warnings": [] } |}] let in_verbatim = test "{v @author Foo v}"; [%expect - {| { "value": [ { "`Verbatim": "@author Foo" } ], "warnings": [] } |}] + {| + { "value": [ { "`Verbatim": "@author Foo" } ], "warnings": [] } |}] let after_code_block = test "{[foo]} @author Bar"; @@ -2365,7 +2375,8 @@ let%expect_test _ = let preceded_by_whitespace = test "@author Foo Bar"; [%expect - {| { "value": [ { "`Tag": { "`Author": "Foo Bar" } } ], "warnings": [] } |}] + {| + { "value": [ { "`Tag": { "`Author": "Foo Bar" } } ], "warnings": [] } |}] let second_preceded_by_whitespace = test "@author Foo\n @author Bar"; @@ -6970,71 +6981,35 @@ let%expect_test _ = let canonical_something = test "@canonical Foo"; - [%expect - {| - { - "value": [ { "`Tag": { "`Canonical": { "`Root": "Foo" } } } ], - "warnings": [] - } |}] + [%expect {| + { "value": [], "warnings": [] } |}] let canonical_module = test "@canonical module-Foo"; - [%expect - {| - { - "value": [ { "`Tag": { "`Canonical": { "`Root": "module-Foo" } } } ], - "warnings": [] - } |}] + [%expect {| + { "value": [], "warnings": [] } |}] let canonical_path = test "@canonical Foo.Bar"; - [%expect - {| - { - "value": [ - { "`Tag": { "`Canonical": { "`Dot": [ { "`Root": "Foo" }, "Bar" ] } } } - ], - "warnings": [] - } |}] + [%expect {| + { "value": [], "warnings": [] } |}] let canonical_val = test "@canonical val-foo"; - [%expect - {| - { - "value": [ { "`Tag": { "`Canonical": { "`Root": "val-foo" } } } ], - "warnings": [] - } |}] + [%expect {| + { "value": [], "warnings": [] } |}] let canonical_bad_parent = test "@canonical bar.page-foo"; - [%expect - {| - { - "value": [ - { - "`Tag": { - "`Canonical": { "`Dot": [ { "`Root": "bar" }, "page-foo" ] } - } - } - ], - "warnings": [] - } |}] + [%expect {| + { "value": [], "warnings": [] } |}] let canonical_empty_component = test "@canonical .Foo"; [%expect {| { - "value": [ - { - "`Paragraph": [ - { "`Word": "@canonical" }, - "`Space", - { "`Code_span": ".Foo" } - ] - } - ], + "value": [], "warnings": [ "File \"f.ml\", line 1, characters 11-15:\nExpected a valid path." ] @@ -7045,15 +7020,7 @@ let%expect_test _ = [%expect {| { - "value": [ - { - "`Paragraph": [ - { "`Word": "@canonical" }, - "`Space", - { "`Code_span": "Foo." } - ] - } - ], + "value": [], "warnings": [ "File \"f.ml\", line 1, characters 11-15:\nExpected a valid path." ] diff --git a/test/print/print.ml b/test/print/print.ml index a98b951796..77f5f7c1ab 100644 --- a/test/print/print.ml +++ b/test/print/print.ml @@ -537,14 +537,6 @@ module Comment_to_sexp = struct List ([ Atom "@before"; Atom s ] @ List.map (at nestable_block_element) es) | `Version s -> List [ Atom "@version"; Atom s ] - | `Canonical p -> - List - [ - Atom "@canonical"; Path_to_sexp.path (p :> Odoc_model.Paths.Path.t); - ] - | `Inline -> Atom "@inline" - | `Open -> Atom "@open" - | `Closed -> Atom "@closed" let block_element : Comment.block_element -> sexp = function | #Comment.nestable_block_element as e -> nestable_block_element e diff --git a/test/xref2/canonical_unit.t/run.t b/test/xref2/canonical_unit.t/run.t index c0a4ce5400..011daf2d9f 100644 --- a/test/xref2/canonical_unit.t/run.t +++ b/test/xref2/canonical_unit.t/run.t @@ -4,6 +4,8 @@ top-comment. The module Test__X is expected to be referenced through Test.X. $ compile test__x.mli test.ml + File "test.ml", line 15, characters 6-24: + Unexpected tag '@canonical' at this location. Test__x has a 'canonical' field: diff --git a/test/xref2/lib/common.cppo.ml b/test/xref2/lib/common.cppo.ml index 114c724b4a..b7f8f25886 100644 --- a/test/xref2/lib/common.cppo.ml +++ b/test/xref2/lib/common.cppo.ml @@ -71,7 +71,7 @@ let model_of_string_impl str = let signature_of_mli_string str = Odoc_xref2.Ident.reset (); - let _, sg = model_of_string str in + let _, sg, _ = model_of_string str in sg let string_of_file f = @@ -628,6 +628,6 @@ let resolve unit = let resolve_from_string s = - let id, sg = model_of_string s in + let id, sg, _ = model_of_string s in let unit = my_compilation_unit id sg in resolve unit diff --git a/test/xref2/module_preamble.t/run.t b/test/xref2/module_preamble.t/run.t index 4fe9e41400..a0d32f7b9a 100644 --- a/test/xref2/module_preamble.t/run.t +++ b/test/xref2/module_preamble.t/run.t @@ -13,6 +13,8 @@ and that "hidden" modules (eg. `A__b`, rendered to `html/A__b`) are not rendered $ odoc compile --pkg test -o a__b.odoc -I . a__b.cmti $ odoc compile --pkg test -o a.odoc -I . a.cmti + File "a.mli", line 4, characters 4-17: + Canonical paths must contain a dot, eg. X.Y. $ odoc link -I . a__b.odoc $ odoc link -I . a.odoc @@ -54,6 +56,8 @@ and that "hidden" modules (eg. `A__b`, rendered to `html/A__b`) are not rendered +

Module B. This paragraph is the synopsis.

+
diff --git a/test/xref2/ocaml_stdlib.t/main.mli b/test/xref2/ocaml_stdlib.t/main.mli new file mode 100644 index 0000000000..8bd4951e25 --- /dev/null +++ b/test/xref2/ocaml_stdlib.t/main.mli @@ -0,0 +1,4 @@ +type pervasives + +(** @canonical X *) +module X = Main__x diff --git a/test/xref2/ocaml_stdlib.t/run.t b/test/xref2/ocaml_stdlib.t/run.t new file mode 100644 index 0000000000..1dca1d6d78 --- /dev/null +++ b/test/xref2/ocaml_stdlib.t/run.t @@ -0,0 +1,22 @@ +Imitate the way the stdlib is built and how its documentation should be built. + + $ ocamlc -c -no-alias-deps -bin-annot -w -49 -o main.cmti main.mli + $ ocamlc -c -bin-annot -I . -o main__x.cmti x.mli + +'Main' doesn't depend on 'Main__x': + + $ odoc compile-deps main.cmti | grep Main__x + [1] + + $ odoc compile --pkg ocaml -o main.odoc main.cmti -I . + File "main.mli", line 3, characters 4-17: + Canonical paths must contain a dot, eg. X.Y. + $ odoc compile --pkg ocaml -o main__x.odoc main__x.cmti -I . + + $ odoc html --indent -o html main__x.odoc -I . + $ odoc html --indent -o html main.odoc -I . + +The page for Main should include the synopsis from X: + + $ cat html/ocaml/Main/index.html | grep "Synopsis" +

Synopsis

diff --git a/test/xref2/ocaml_stdlib.t/x.mli b/test/xref2/ocaml_stdlib.t/x.mli new file mode 100644 index 0000000000..a115783eaa --- /dev/null +++ b/test/xref2/ocaml_stdlib.t/x.mli @@ -0,0 +1,4 @@ +(** Synopsis *) + +(* Reference to [Main] to ensure compilation order *) +type t = Main.pervasives