lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <28b456f726a022011f0ce5810dbcc26827c1403a.1745564565.git.mchehab+huawei@kernel.org>
Date: Fri, 25 Apr 2025 15:13:40 +0800
From: Mauro Carvalho Chehab <mchehab+huawei@...nel.org>
To: Linux Doc Mailing List <linux-doc@...r.kernel.org>,
	Jonathan Corbet <corbet@....net>
Cc: Mauro Carvalho Chehab <mchehab+huawei@...nel.org>,
	Sean Anderson <sean.anderson@...ux.dev>,
	linux-kernel@...r.kernel.org
Subject: [PATCH 3/3] scripts/lib/kdoc/kdoc_parser.py: move kernel entry to a class

The KernelDoc class is too complex. Start optimizing it by
placing the kernel-doc parser entry to a separate class.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@...nel.org>
---
 scripts/lib/kdoc/kdoc_parser.py | 277 +++++++++++++++++---------------
 1 file changed, 151 insertions(+), 126 deletions(-)

diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py
index 461e0acb0fb7..062453eefc7a 100644
--- a/scripts/lib/kdoc/kdoc_parser.py
+++ b/scripts/lib/kdoc/kdoc_parser.py
@@ -12,7 +12,6 @@ Read a C language source or header FILE and extract embedded
 documentation comments
 """
 
-import argparse
 import re
 from pprint import pformat
 
@@ -104,6 +103,97 @@ class state:
         "_ERROR",
     ]
 
+SECTION_DEFAULT = "Description"  # default section
+
+class KernelEntry:
+
+    def __init__(self, config, ln):
+        self.config = config
+
+        self.contents = ""
+        self.function = ""
+        self.sectcheck = ""
+        self.struct_actual = ""
+        self.prototype = ""
+
+        self.warnings = []
+
+        self.parameterlist = []
+        self.parameterdescs = {}
+        self.parametertypes = {}
+        self.parameterdesc_start_lines = {}
+
+        self.section_start_lines = {}
+        self.sectionlist = []
+        self.sections = {}
+
+        self.anon_struct_union = False
+
+        self.leading_space = None
+
+        # State flags
+        self.brcount = 0
+
+        self.in_doc_sect = False
+        self.declaration_start_line = ln + 1
+
+    # TODO: rename to emit_message after removal of kernel-doc.pl
+    def emit_msg(self, log_msg, warning=True):
+        """Emit a message"""
+
+        if not warning:
+            self.config.log.info(log_msg)
+            return
+
+        # Delegate warning output to output logic, as this way it
+        # will report warnings/info only for symbols that are output
+
+        self.warnings.append(log_msg)
+        return
+
+    def dump_section(self, start_new=True):
+        """
+        Dumps section contents to arrays/hashes intended for that purpose.
+        """
+
+        name = self.section
+        contents = self.contents
+
+        if type_param.match(name):
+            name = type_param.group(1)
+
+            self.parameterdescs[name] = contents
+            self.parameterdesc_start_lines[name] = self.new_start_line
+
+            self.sectcheck += name + " "
+            self.new_start_line = 0
+
+        elif name == "@...":
+            name = "..."
+            self.parameterdescs[name] = contents
+            self.sectcheck += name + " "
+            self.parameterdesc_start_lines[name] = self.new_start_line
+            self.new_start_line = 0
+
+        else:
+            if name in self.sections and self.sections[name] != "":
+                # Only warn on user-specified duplicate section names
+                if name != SECTION_DEFAULT:
+                    self.emit_msg(self.new_start_line,
+                                  f"duplicate section name '{name}'\n")
+                self.sections[name] += contents
+            else:
+                self.sections[name] = contents
+                self.sectionlist.append(name)
+                self.section_start_lines[name] = self.new_start_line
+                self.new_start_line = 0
+
+#        self.config.log.debug("Section: %s : %s", name, pformat(vars(self)))
+
+        if start_new:
+            self.section = SECTION_DEFAULT
+            self.contents = ""
+
 
 class KernelDoc:
     """
@@ -113,7 +203,6 @@ class KernelDoc:
 
     # Section names
 
-    section_default = "Description"  # default section
     section_intro = "Introduction"
     section_context = "Context"
     section_return = "Return"
@@ -136,67 +225,27 @@ class KernelDoc:
         # Place all potential outputs into an array
         self.entries = []
 
-    # TODO: rename to emit_message after removal of kernel-doc.pl
-    def emit_warning(self, ln, msg, warning=True):
+    def emit_msg(self, ln, msg, warning=True):
         """Emit a message"""
 
         log_msg = f"{self.fname}:{ln} {msg}"
 
-        if not warning:
+        if self.entry:
+            self.entry.emit_msg(log_msg, warning)
+            return
+
+        if warning:
+            self.config.log.warning(log_msg)
+        else:
             self.config.log.info(log_msg)
-            return
-
-        if self.entry:
-            # Delegate warning output to output logic, as this way it
-            # will report warnings/info only for symbols that are output
-
-            self.entry.warnings.append(log_msg)
-            return
-
-        self.config.log.warning(log_msg)
 
     def dump_section(self, start_new=True):
         """
         Dumps section contents to arrays/hashes intended for that purpose.
         """
 
-        name = self.entry.section
-        contents = self.entry.contents
-
-        if type_param.match(name):
-            name = type_param.group(1)
-
-            self.entry.parameterdescs[name] = contents
-            self.entry.parameterdesc_start_lines[name] = self.entry.new_start_line
-
-            self.entry.sectcheck += name + " "
-            self.entry.new_start_line = 0
-
-        elif name == "@...":
-            name = "..."
-            self.entry.parameterdescs[name] = contents
-            self.entry.sectcheck += name + " "
-            self.entry.parameterdesc_start_lines[name] = self.entry.new_start_line
-            self.entry.new_start_line = 0
-
-        else:
-            if name in self.entry.sections and self.entry.sections[name] != "":
-                # Only warn on user-specified duplicate section names
-                if name != self.section_default:
-                    self.emit_warning(self.entry.new_start_line,
-                                      f"duplicate section name '{name}'\n")
-                self.entry.sections[name] += contents
-            else:
-                self.entry.sections[name] = contents
-                self.entry.sectionlist.append(name)
-                self.entry.section_start_lines[name] = self.entry.new_start_line
-                self.entry.new_start_line = 0
-
-#        self.config.log.debug("Section: %s : %s", name, pformat(vars(self.entry)))
-
-        if start_new:
-            self.entry.section = self.section_default
-            self.entry.contents = ""
+        if self.entry:
+            self.entry.dump_section(start_new)
 
     # TODO: rename it to store_declaration after removal of kernel-doc.pl
     def output_declaration(self, dtype, name, **args):
@@ -241,36 +290,11 @@ class KernelDoc:
         variables used by the state machine.
         """
 
-        self.entry = argparse.Namespace
-
-        self.entry.contents = ""
-        self.entry.function = ""
-        self.entry.sectcheck = ""
-        self.entry.struct_actual = ""
-        self.entry.prototype = ""
-
-        self.entry.warnings = []
-
-        self.entry.parameterlist = []
-        self.entry.parameterdescs = {}
-        self.entry.parametertypes = {}
-        self.entry.parameterdesc_start_lines = {}
-
-        self.entry.section_start_lines = {}
-        self.entry.sectionlist = []
-        self.entry.sections = {}
-
-        self.entry.anon_struct_union = False
-
-        self.entry.leading_space = None
+        self.entry = KernelEntry(self.config, ln)
 
         # State flags
         self.state = state.NORMAL
         self.inline_doc_state = state.INLINE_NA
-        self.entry.brcount = 0
-
-        self.entry.in_doc_sect = False
-        self.entry.declaration_start_line = ln + 1
 
     def push_parameter(self, ln, decl_type, param, dtype,
                        org_arg, declaration_name):
@@ -328,8 +352,8 @@ class KernelDoc:
                 else:
                     dname = f"{decl_type} member"
 
-                self.emit_warning(ln,
-                                  f"{dname} '{param}' not described in '{declaration_name}'")
+                self.emit_msg(ln,
+                              f"{dname} '{param}' not described in '{declaration_name}'")
 
         # Strip spaces from param so that it is one continuous string on
         # parameterlist. This fixes a problem where check_sections()
@@ -393,7 +417,7 @@ class KernelDoc:
                 if r.match(arg):
                     param = r.group(1)
                 else:
-                    self.emit_warning(ln, f"Invalid param: {arg}")
+                    self.emit_msg(ln, f"Invalid param: {arg}")
                     param = arg
 
                 dtype = KernRe(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg)
@@ -409,7 +433,7 @@ class KernelDoc:
                 if r.match(arg):
                     param = r.group(1)
                 else:
-                    self.emit_warning(ln, f"Invalid param: {arg}")
+                    self.emit_msg(ln, f"Invalid param: {arg}")
                     param = arg
 
                 dtype = KernRe(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg)
@@ -442,7 +466,7 @@ class KernelDoc:
                     if KernRe(r'^(\*+)\s*(.*)').match(param):
                         r = KernRe(r'^(\*+)\s*(.*)')
                         if not r.match(param):
-                            self.emit_warning(ln, f"Invalid param: {param}")
+                            self.emit_msg(ln, f"Invalid param: {param}")
                             continue
 
                         param = r.group(1)
@@ -455,7 +479,7 @@ class KernelDoc:
                     elif KernRe(r'(.*?):(\w+)').search(param):
                         r = KernRe(r'(.*?):(\w+)')
                         if not r.match(param):
-                            self.emit_warning(ln, f"Invalid param: {param}")
+                            self.emit_msg(ln, f"Invalid param: {param}")
                             continue
 
                         if dtype != "":  # Skip unnamed bit-fields
@@ -503,8 +527,8 @@ class KernelDoc:
                 else:
                     dname = f"{decl_type} member"
 
-                self.emit_warning(ln,
-                                  f"Excess {dname} '{sects[sx]}' description in '{decl_name}'")
+                self.emit_msg(ln,
+                              f"Excess {dname} '{sects[sx]}' description in '{decl_name}'")
 
     def check_return_section(self, ln, declaration_name, return_type):
         """
@@ -521,8 +545,8 @@ class KernelDoc:
             return
 
         if not self.entry.sections.get("Return", None):
-            self.emit_warning(ln,
-                              f"No description found for return value of '{declaration_name}'")
+            self.emit_msg(ln,
+                          f"No description found for return value of '{declaration_name}'")
 
     def dump_struct(self, ln, proto):
         """
@@ -561,12 +585,12 @@ class KernelDoc:
                 members = r.group(2)
 
         if not members:
-            self.emit_warning(ln, f"{proto} error: Cannot parse struct or union!")
+            self.emit_msg(ln, f"{proto} error: Cannot parse struct or union!")
             return
 
         if self.entry.identifier != declaration_name:
-            self.emit_warning(ln,
-                              f"expecting prototype for {decl_type} {self.entry.identifier}. Prototype was for {decl_type} {declaration_name} instead\n")
+            self.emit_msg(ln,
+                          f"expecting prototype for {decl_type} {self.entry.identifier}. Prototype was for {decl_type} {declaration_name} instead\n")
             return
 
         args_pattern = r'([^,)]+)'
@@ -835,16 +859,16 @@ class KernelDoc:
                 members = r.group(2).rstrip()
 
         if not members:
-            self.emit_warning(ln, f"{proto}: error: Cannot parse enum!")
+            self.emit_msg(ln, f"{proto}: error: Cannot parse enum!")
             return
 
         if self.entry.identifier != declaration_name:
             if self.entry.identifier == "":
-                self.emit_warning(ln,
-                                  f"{proto}: wrong kernel-doc identifier on prototype")
+                self.emit_msg(ln,
+                              f"{proto}: wrong kernel-doc identifier on prototype")
             else:
-                self.emit_warning(ln,
-                                  f"expecting prototype for enum {self.entry.identifier}. Prototype was for enum {declaration_name} instead")
+                self.emit_msg(ln,
+                              f"expecting prototype for enum {self.entry.identifier}. Prototype was for enum {declaration_name} instead")
             return
 
         if not declaration_name:
@@ -861,14 +885,14 @@ class KernelDoc:
             self.entry.parameterlist.append(arg)
             if arg not in self.entry.parameterdescs:
                 self.entry.parameterdescs[arg] = self.undescribed
-                self.emit_warning(ln,
-                                  f"Enum value '{arg}' not described in enum '{declaration_name}'")
+                self.emit_msg(ln,
+                              f"Enum value '{arg}' not described in enum '{declaration_name}'")
             member_set.add(arg)
 
         for k in self.entry.parameterdescs:
             if k not in member_set:
-                self.emit_warning(ln,
-                                  f"Excess enum value '%{k}' description in '{declaration_name}'")
+                self.emit_msg(ln,
+                              f"Excess enum value '%{k}' description in '{declaration_name}'")
 
         self.output_declaration('enum', declaration_name,
                                 enum=declaration_name,
@@ -1023,13 +1047,13 @@ class KernelDoc:
                     found = True
                     break
         if not found:
-            self.emit_warning(ln,
-                              f"cannot understand function prototype: '{prototype}'")
+            self.emit_msg(ln,
+                          f"cannot understand function prototype: '{prototype}'")
             return
 
         if self.entry.identifier != declaration_name:
-            self.emit_warning(ln,
-                              f"expecting prototype for {self.entry.identifier}(). Prototype was for {declaration_name}() instead")
+            self.emit_msg(ln,
+                          f"expecting prototype for {self.entry.identifier}(). Prototype was for {declaration_name}() instead")
             return
 
         prms = " ".join(self.entry.parameterlist)
@@ -1092,8 +1116,8 @@ class KernelDoc:
             args = r.group(3)
 
             if self.entry.identifier != declaration_name:
-                self.emit_warning(ln,
-                                  f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n")
+                self.emit_msg(ln,
+                              f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n")
                 return
 
             decl_type = 'function'
@@ -1124,7 +1148,8 @@ class KernelDoc:
             declaration_name = r.group(1)
 
             if self.entry.identifier != declaration_name:
-                self.emit_warning(ln, f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n")
+                self.emit_msg(ln,
+                              f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n")
                 return
 
             self.output_declaration('typedef', declaration_name,
@@ -1135,7 +1160,7 @@ class KernelDoc:
                                     purpose=self.entry.declaration_purpose)
             return
 
-        self.emit_warning(ln, "error: Cannot parse typedef!")
+        self.emit_msg(ln, "error: Cannot parse typedef!")
 
     @staticmethod
     def process_export(function_set, line):
@@ -1232,7 +1257,7 @@ class KernelDoc:
             self.state = state.BODY
 
             # if there's no @param blocks need to set up default section here
-            self.entry.section = self.section_default
+            self.entry.section = SECTION_DEFAULT
             self.entry.new_start_line = ln + 1
 
             r = KernRe("[-:](.*)")
@@ -1248,28 +1273,28 @@ class KernelDoc:
                 self.entry.declaration_purpose = ""
 
             if not self.entry.is_kernel_comment:
-                self.emit_warning(ln,
-                                  f"This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n{line}")
+                self.emit_msg(ln,
+                              f"This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n{line}")
                 self.state = state.NORMAL
 
             if not self.entry.declaration_purpose and self.config.wshort_desc:
-                self.emit_warning(ln,
-                                  f"missing initial short description on line:\n{line}")
+                self.emit_msg(ln,
+                              f"missing initial short description on line:\n{line}")
 
             if not self.entry.identifier and self.entry.decl_type != "enum":
-                self.emit_warning(ln,
-                                  f"wrong kernel-doc identifier on line:\n{line}")
+                self.emit_msg(ln,
+                              f"wrong kernel-doc identifier on line:\n{line}")
                 self.state = state.NORMAL
 
             if self.config.verbose:
-                self.emit_warning(ln,
-                                  f"Scanning doc for {self.entry.decl_type} {self.entry.identifier}",
+                self.emit_msg(ln,
+                              f"Scanning doc for {self.entry.decl_type} {self.entry.identifier}",
                                   warning=False)
 
             return
 
         # Failed to find an identifier. Emit a warning
-        self.emit_warning(ln, f"Cannot find identifier on line:\n{line}")
+        self.emit_msg(ln, f"Cannot find identifier on line:\n{line}")
 
     def process_body(self, ln, line):
         """
@@ -1280,7 +1305,7 @@ class KernelDoc:
             r = KernRe(r"\s*\*\s?\S")
             if r.match(line):
                 self.dump_section()
-                self.entry.section = self.section_default
+                self.entry.section = SECTION_DEFAULT
                 self.entry.new_start_line = ln
                 self.entry.contents = ""
 
@@ -1325,7 +1350,7 @@ class KernelDoc:
             # Look for doc_com + <text> + doc_end:
             r = KernRe(r'\s*\*\s*[a-zA-Z_0-9:\.]+\*/')
             if r.match(line):
-                self.emit_warning(ln, f"suspicious ending line: {line}")
+                self.emit_msg(ln, f"suspicious ending line: {line}")
 
             self.entry.prototype = ""
             self.entry.new_start_line = ln + 1
@@ -1343,7 +1368,7 @@ class KernelDoc:
                     self.entry.new_start_line = ln
                     self.state = state.BODY
                 else:
-                    if self.entry.section != self.section_default:
+                    if self.entry.section != SECTION_DEFAULT:
                         self.state = state.BODY_WITH_BLANK_LINE
                     else:
                         self.state = state.BODY
@@ -1388,7 +1413,7 @@ class KernelDoc:
             return
 
         # Unknown line, ignore
-        self.emit_warning(ln, f"bad line: {line}")
+        self.emit_msg(ln, f"bad line: {line}")
 
     def process_inline(self, ln, line):
         """STATE_INLINE: docbook comments within a prototype."""
@@ -1421,8 +1446,8 @@ class KernelDoc:
                     self.entry.contents = ""
 
             elif self.inline_doc_state == state.INLINE_NAME:
-                self.emit_warning(ln,
-                                  f"Incorrect use of kernel-doc format: {line}")
+                self.emit_msg(ln,
+                              f"Incorrect use of kernel-doc format: {line}")
 
                 self.inline_doc_state = state.INLINE_ERROR
 
@@ -1494,8 +1519,8 @@ class KernelDoc:
             tracepointargs = r.group(1)
 
         if not tracepointname or not tracepointargs:
-            self.emit_warning(ln,
-                              f"Unrecognized tracepoint format:\n{proto}\n")
+            self.emit_msg(ln,
+                          f"Unrecognized tracepoint format:\n{proto}\n")
         else:
             proto = f"static inline void trace_{tracepointname}({tracepointargs})"
             self.entry.identifier = f"trace_{self.entry.identifier}"
-- 
2.49.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ