diff mbox series

[39/42] qapi/schema: add doc_visible property to QAPISchemaDefinition

Message ID 20250205231208.1480762-40-jsnow@redhat.com (mailing list archive)
State New
Headers show
Series docs: add sphinx-domain rST generator to qapidoc | expand

Commit Message

John Snow Feb. 5, 2025, 11:12 p.m. UTC
This patch adds a boolean flag to mark definitions as "visible" in the
end-user HTML docs. The intent is that definitions that are not marked
as visible will not be rendered.

What gets marked visible?

The short version: all commands and events are inherently visible. All
other definitions are visible if and only if they are the target of a
cross-reference in the generated output.

The long version:

- All commands:
  - All arg_type members, excluding arg_type itself
    (because it's inlined)
  - All ret_type members, *including* ret_type itself
    (because we cross-reference the return type)

- All events:
  - All arg_type members, excluding arg_type itself
    (because it's inlined)

- For any object marked visible by the above;
  - All members (which includes inherited members)
  - All branch objects, excluding the branch object itself
    (because the branches are inlined)

- For any array marked visible by the above;
  - The array itself, and
  - The contained element_type

- For any alternate marked visible by the above;
  - The alternate itself, and
  - All of its branch types.
    (because we don't currently inline anything for alternates.)

All other definitions are not doc_visible; those exclusions are:

- Any definition not recursively referenced by any command or event;
  i.e. definitions used internally by QEMU but not actually used by the
  QMP protocol.

- Any definition used only as an arg_type for events or
  commands; because the doc generator inlines arguments, there is no
  need to generate documentation for the arguments/members by
  themselves.

- Any definition used only as a base_type for objects. The new
  doc generator will inline inheritance, so there is no need to generate
  standalone documentation for factored/common objects.

- Any definition used only as a branch type for a union. The new doc
  generator also inlines branch members as it does for local and
  inherited members, so there's no need to document each branch as a
  standalone entity.

Note that if a type is used both in an "inlined" context and a
"referenced" context, documentation *will* be generated for that
type; e.g. a struct type used both as a base_type *and* as a member
argument.

This does not necessarily match the data revealed by the runtime
introspection feature: in the generated documentation case, we want
anything that we are cross-referencing in generated documentation to be
available to target with cross-reference syntax.

Some built-in types may be marked visible with this approach, but if
they do not have a documentation block, they'll be skipped by the
generator anyway. This includes array types and built-in primitives
which do not get their own documentation objects.

i.e., for documentation to be generated for a given QAPISchemaDefinition
in the new generator, it must have non-empty documentation AND be
doc_visible. This differs from the current qapidoc generator which only
requires non-empty documentation. This means some items marked
doc_visible *still* will not be rendered because they lack documentation
to render.

This information is not yet used by the current generator, which
continues to render documentation exactly as it has. This information
will be used by the new qapidoc (the "transmogrifier") in the next
commit.

Signed-off-by: John Snow <jsnow@redhat.com>
---
 scripts/qapi/schema.py | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)
diff mbox series

Patch

diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index 4c55f7640b6..32c9a8f4cd2 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -131,6 +131,7 @@  def __init__(
         self.doc = doc
         self._ifcond = ifcond or QAPISchemaIfCond()
         self.features = features or []
+        self.doc_visible = False
 
     def __repr__(self) -> str:
         return "<%s:%s at 0x%x>" % (type(self).__name__, self.name,
@@ -146,6 +147,10 @@  def check(self, schema: QAPISchema) -> None:
         for f in self.features:
             f.check_clash(self.info, seen)
 
+    def mark_visible(self, mark_self: bool = True) -> None:
+        if mark_self:
+            self.doc_visible = True
+
     def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
         super().connect_doc(doc)
         doc = doc or self.doc
@@ -483,6 +488,10 @@  def check(self, schema: QAPISchema) -> None:
             self.info.defn_meta if self.info else None)
         assert not isinstance(self.element_type, QAPISchemaArrayType)
 
+    def mark_visible(self, mark_self: bool = True) -> None:
+        super().mark_visible(mark_self)
+        self.element_type.mark_visible()
+
     def set_module(self, schema: QAPISchema) -> None:
         self._set_module(schema, self.element_type.info)
 
@@ -607,6 +616,17 @@  def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
         for m in self.local_members:
             m.connect_doc(doc)
 
+    def mark_visible(self, mark_self: bool = True) -> None:
+        # Mark this object and its members as visible in the user-facing docs.
+        if self.doc_visible:
+            return
+
+        super().mark_visible(mark_self)
+        for m in self.members:
+            m.type.mark_visible()
+        for var in self.branches or []:
+            var.type.mark_visible(False)
+
     def is_implicit(self) -> bool:
         # See QAPISchema._make_implicit_object_type(), as well as
         # _def_predefineds()
@@ -698,6 +718,11 @@  def check(self, schema: QAPISchema) -> None:
                         % (v.describe(self.info), types_seen[qt]))
                 types_seen[qt] = v.name
 
+    def mark_visible(self, mark_self: bool = True) -> None:
+        super().mark_visible(mark_self)
+        for var in self.alternatives:
+            var.type.mark_visible()
+
     def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
         super().connect_doc(doc)
         doc = doc or self.doc
@@ -1056,6 +1081,13 @@  def check(self, schema: QAPISchema) -> None:
                         "command's 'returns' cannot take %s"
                         % self.ret_type.describe())
 
+    def mark_visible(self, mark_self: bool = True) -> None:
+        super().mark_visible(mark_self)
+        if self.arg_type:
+            self.arg_type.mark_visible(False)
+        if self.ret_type:
+            self.ret_type.mark_visible()
+
     def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
         super().connect_doc(doc)
         doc = doc or self.doc
@@ -1112,6 +1144,11 @@  def check(self, schema: QAPISchema) -> None:
                     self.info,
                     "conditional event arguments require 'boxed': true")
 
+    def mark_visible(self, mark_self: bool = True) -> None:
+        super().mark_visible(mark_self)
+        if self.arg_type:
+            self.arg_type.mark_visible(False)
+
     def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
         super().connect_doc(doc)
         doc = doc or self.doc
@@ -1488,6 +1525,9 @@  def check(self) -> None:
             ent.set_module(self)
         for doc in self.docs:
             doc.check()
+        for ent in self._entity_list:
+            if isinstance(ent, (QAPISchemaCommand, QAPISchemaEvent)):
+                ent.mark_visible()
 
     def visit(self, visitor: QAPISchemaVisitor) -> None:
         visitor.visit_begin(self)