{"id":2221085,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2221085/?format=json","web_url":"http://patchwork.ozlabs.org/project/qemu-devel/patch/20260408045531.3006678-7-jsnow@redhat.com/","project":{"id":14,"url":"http://patchwork.ozlabs.org/api/1.1/projects/14/?format=json","name":"QEMU Development","link_name":"qemu-devel","list_id":"qemu-devel.nongnu.org","list_email":"qemu-devel@nongnu.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260408045531.3006678-7-jsnow@redhat.com>","date":"2026-04-08T04:55:27","name":"[v2,06/10] qapi: detect potentially semantically ambiguous intro paragraphs","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"d6eceb4edc3081147e3c4ae516af95ee9734ab21","submitter":{"id":64343,"url":"http://patchwork.ozlabs.org/api/1.1/people/64343/?format=json","name":"John Snow","email":"jsnow@redhat.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/qemu-devel/patch/20260408045531.3006678-7-jsnow@redhat.com/mbox/","series":[{"id":499174,"url":"http://patchwork.ozlabs.org/api/1.1/series/499174/?format=json","web_url":"http://patchwork.ozlabs.org/project/qemu-devel/list/?series=499174","date":"2026-04-08T04:55:23","name":"qapi: enforce section ordering","version":2,"mbox":"http://patchwork.ozlabs.org/series/499174/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2221085/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2221085/checks/","tags":{},"headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=GBAeChwG;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)"],"Received":["from lists.gnu.org (unknown [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4frXC34tn6z1xy1\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 09 Apr 2026 04:48:31 +1000 (AEST)","from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1wAXqT-0004Fp-JN; Wed, 08 Apr 2026 14:41:45 -0400","from eggs.gnu.org ([2001:470:142:3::10])\n by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <jsnow@redhat.com>) id 1wAXqM-0003PL-EL\n for qemu-devel@nongnu.org; Wed, 08 Apr 2026 14:41:38 -0400","from us-smtp-delivery-124.mimecast.com ([170.10.133.124])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <jsnow@redhat.com>) id 1wAKy4-0005Wj-VB\n for qemu-devel@nongnu.org; Wed, 08 Apr 2026 00:56:46 -0400","from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-686-_o4l-70FP0eZEHHQCdHbbg-1; Wed,\n 08 Apr 2026 00:56:41 -0400","from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 8FE191956053; Wed,  8 Apr 2026 04:56:38 +0000 (UTC)","from jsnow-thinkpadp16vgen1.westford.csb (unknown [10.22.88.7])\n by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id CE33419560A6; Wed,  8 Apr 2026 04:56:29 +0000 (UTC)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1775624204;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=DaLNkC78dChf3IQ1YnUFsiyxPTWSj16Ag0PWMwgYCaM=;\n b=GBAeChwG4LOgGrzB718oWES+u0g8qs2QGfTKTFJ6tWdT+5h0zRjsTUovrj9VheomUX59xQ\n Wzmfb+8f5SZjb3LZ0OOJRlu6zDFYT7ElItHc86Ok4owGCTJ/hYpmret+nLWtEDHit/1mWU\n onqtyf3mieARW/uKC1FbTYkBkyXSHIU=","X-MC-Unique":"_o4l-70FP0eZEHHQCdHbbg-1","X-Mimecast-MFC-AGG-ID":"_o4l-70FP0eZEHHQCdHbbg_1775624198","From":"John Snow <jsnow@redhat.com>","To":"qemu-devel@nongnu.org","Cc":"Kashyap Chamarthy <kchamart@redhat.com>,\n Stefan Berger <stefanb@linux.vnet.ibm.com>,\n Mauro Carvalho Chehab <mchehab+huawei@kernel.org>,\n Michael Roth <michael.roth@amd.com>,\n =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= <philmd@linaro.org>,\n qemu-block@nongnu.org, Pierrick Bouvier <pierrick.bouvier@linaro.org>,\n Yanan Wang <wangyanan55@huawei.com>, Hanna Reitz <hreitz@redhat.com>,\n Peter Xu <peterx@redhat.com>, Igor Mammedov <imammedo@redhat.com>,\n \"Michael S. Tsirkin\" <mst@redhat.com>, Kevin Wolf <kwolf@redhat.com>,\n\t=?utf-8?q?Marc-Andr=C3=A9_Lureau?= <marcandre.lureau@redhat.com>,\n Stefano Garzarella <sgarzare@redhat.com>, =?utf-8?q?Daniel_P=2E_Berrang?=\n\t=?utf-8?q?=C3=A9?= <berrange@redhat.com>, Lukas Straub <lukasstraub2@web.de>,\n Jason Wang <jasowang@redhat.com>, Alex Williamson <alex@shazbot.org>,\n Paolo Bonzini <pbonzini@redhat.com>, Fabiano Rosas <farosas@suse.de>,\n Zhao Liu <zhao1.liu@intel.com>,\n Richard Henderson <richard.henderson@linaro.org>, =?utf-8?q?C=C3=A9dric_Le_?=\n\t=?utf-8?q?Goater?= <clg@redhat.com>, Stefan Hajnoczi <stefanha@redhat.com>,\n Peter Maydell <peter.maydell@linaro.org>, Eric Blake <eblake@redhat.com>,\n\t=?utf-8?q?Alex_Benn=C3=A9e?= <alex.bennee@linaro.org>,\n Kostiantyn Kostiuk <kkostiuk@redhat.com>, Jiri Pirko <jiri@resnulli.us>,\n Markus Armbruster <armbru@redhat.com>, John Snow <jsnow@redhat.com>,\n Ani Sinha <anisinha@redhat.com>,\n Marcel Apfelbaum <marcel.apfelbaum@gmail.com>","Subject":"[PATCH v2 06/10] qapi: detect potentially semantically ambiguous\n intro paragraphs","Date":"Wed,  8 Apr 2026 00:55:27 -0400","Message-ID":"<20260408045531.3006678-7-jsnow@redhat.com>","In-Reply-To":"<20260408045531.3006678-1-jsnow@redhat.com>","References":"<20260408045531.3006678-1-jsnow@redhat.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-Scanned-By":"MIMEDefang 3.0 on 10.30.177.12","Received-SPF":"pass client-ip=170.10.133.124; envelope-from=jsnow@redhat.com;\n helo=us-smtp-delivery-124.mimecast.com","X-Spam_score_int":"-25","X-Spam_score":"-2.6","X-Spam_bar":"--","X-Spam_report":"(-2.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54,\n DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001,\n RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001,\n SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no","X-Spam_action":"no action","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"qemu development <qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<https://lists.nongnu.org/archive/html/qemu-devel>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org"},"content":"Cajole the QAPI Doc parser into yelping if a QAPI Doc Block contains two\nor more paragraphs of plaintext and has no instances of Members, Errors,\nReturns, or Features that would naturally delineate an introduction from\nadditional details such as notes, examples, and additional details.\n\nSuch locations do not currently *guarantee* a difference to rendered\nmanual output, but later changes to the documentation generator that may\ninclude additional auto-generated sections, and complexities from the\ninliner, may increase the odds that these locations are suspect and will\nneed to be explicitly delineated.\n\nSigned-off-by: John Snow <jsnow@redhat.com>\n\n---\n\n[Review notes: no changes to *.ir files. --js]\n\nSigned-off-by: John Snow <jsnow@redhat.com>\n---\n scripts/qapi/parser.py                     | 49 ++++++++++++++++++++++\n tests/qapi-schema/doc-missing-details.err  |  0\n tests/qapi-schema/doc-missing-details.json |  3 ++\n tests/qapi-schema/doc-missing-details.out  | 11 +++++\n tests/qapi-schema/meson.build              |  1 +\n 5 files changed, 64 insertions(+)\n create mode 100644 tests/qapi-schema/doc-missing-details.err\n create mode 100644 tests/qapi-schema/doc-missing-details.json\n create mode 100644 tests/qapi-schema/doc-missing-details.out","diff":"diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py\nindex 1d52d80e672..ade26d124df 100644\n--- a/scripts/qapi/parser.py\n+++ b/scripts/qapi/parser.py\n@@ -32,6 +32,8 @@\n from .source import QAPISourceInfo\n \n \n+# pylint: disable=too-many-lines\n+\n if TYPE_CHECKING:\n     # pylint: disable=cyclic-import\n     # TODO: Remove cycle. [schema -> expr -> parser -> schema]\n@@ -962,3 +964,50 @@ def check_args_section(\n \n         check_args_section(self.args, 'member')\n         check_args_section(self.features, 'feature')\n+\n+        # Ignore free-form documentation sections\n+        if self.symbol is None:\n+            return\n+\n+        n_intro_para = 0\n+        has_intro = False\n+        has_other = False\n+\n+        for section in self.all_sections:\n+            # Ignore Since: and TODO: sections\n+            if section.kind in (QAPIDoc.Kind.SINCE, QAPIDoc.Kind.TODO):\n+                continue\n+\n+            # Ignore empty plaintext sections\n+            if section.kind in (QAPIDoc.Kind.INTRO, QAPIDoc.Kind.DETAILS):\n+                if not section.text:\n+                    continue\n+\n+            if section.kind == QAPIDoc.Kind.INTRO:\n+                has_intro = True\n+                n_intro_para = len(section.text.split(\"\\n\\n\"))\n+            else:\n+                if section.kind == QAPIDoc.Kind.MEMBER and not section.text:\n+                    pass\n+                elif section.kind == QAPIDoc.Kind.RETURNS and not section.text:\n+                    pass\n+                else:\n+                    # This section is something other than an Intro section;\n+                    # but we explicitly exclude stub entries for members\n+                    # (undocumented fields with no text) from consideration\n+                    # because they were auto-generated; they are not useful\n+                    # for identifying the case \"There are multiple intro\n+                    # paragraphs and no other explicit source sections.\"\n+                    has_other = True\n+\n+        # If an intro section is only a single paragraph, we are\n+        # confident it is well and truly just an introduction. If we\n+        # have a single, multi-paragraph intro section and *no other*\n+        # explicit sections in source code, it is potentially a semantic\n+        # goof-em-up where the intro and details sections have bled\n+        # together. Warn about this case.\n+        if has_intro and n_intro_para > 1 and not has_other:\n+            print(\n+                f\"Warning: paragraphs for {self.symbol} are ambiguous \"\n+                \"and could be either intro or details paragraphs.\"\n+            )\ndiff --git a/tests/qapi-schema/doc-missing-details.err b/tests/qapi-schema/doc-missing-details.err\nnew file mode 100644\nindex 00000000000..e69de29bb2d\ndiff --git a/tests/qapi-schema/doc-missing-details.json b/tests/qapi-schema/doc-missing-details.json\nnew file mode 100644\nindex 00000000000..02c14ee768d\n--- /dev/null\n+++ b/tests/qapi-schema/doc-missing-details.json\n@@ -0,0 +1,3 @@\n+# TODO / FIXME\n+# This test intentionally triggers the parser warning\n+# suggesting we use the Details: marker.\ndiff --git a/tests/qapi-schema/doc-missing-details.out b/tests/qapi-schema/doc-missing-details.out\nnew file mode 100644\nindex 00000000000..52ca7cb8727\n--- /dev/null\n+++ b/tests/qapi-schema/doc-missing-details.out\n@@ -0,0 +1,11 @@\n+module ./builtin\n+object q_empty\n+enum QType\n+    member none\n+    member qnull\n+    member qnum\n+    member qstring\n+    member qdict\n+    member qlist\n+    member qbool\n+module doc-missing-details.json\ndiff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build\nindex c233d77ab78..01da8534f2e 100644\n--- a/tests/qapi-schema/meson.build\n+++ b/tests/qapi-schema/meson.build\n@@ -85,6 +85,7 @@ schemas = [\n   'doc-long-line.json',\n   'doc-misplaced-details.json',\n   'doc-missing-colon.json',\n+  'doc-missing-details.json',\n   'doc-missing-expr.json',\n   'doc-missing-space.json',\n   'doc-missing.json',\n","prefixes":["v2","06/10"]}