Several kdoc fixes
cover Several kdoc fixes
Hi Jon,
This series contains patches from:
https://lore.kernel.org/linux-doc/[email protected]/T/#t
I rebased them to make the changes cleaner, fixing mostly on fixes.
I dropped stuff related to NestedMatch arguments parsing. I'll be sending you on a new patch series, likely tomorrow.
The changes here basically addresses several issues discoverd by Randy and by me and makes NestedMatch more similar to KernRe.
It also moves the transforms ruleset to a separate file, to make easier to maintain kernel-doc code.
Mauro Carvalho Chehab (16):
docs: kdoc_re: add support for groups()
docs: kdoc_re: don't go past the end of a line
docs: kdoc_parser: move var transformers to the beginning
docs: kdoc_parser: don't mangle with function defines
docs: kdoc_parser: fix variable regexes to work with size_t
docs: kdoc_parser: fix the default_value logic for variables
docs: kdoc_parser: don't exclude defaults from prototype
docs: kdoc_parser: fix parser to support multi-word types
docs: kdoc_parser: add support for LIST_HEAD
docs: kdoc_re: better show KernRe() at documentation
docs: kdoc_parser: move transform lists to a separate file
docs: kdoc_re: handle strings and escape chars on NextMatch
docs: kdoc_re: don't recompile NestedMatch regex every time
docs: kdoc_re: Change NestedMath args replacement to \0
docs: kdoc_re: make NestedMatch use KernRe
docs: kdoc_parser: move nested match transforms to xforms_lists.py
Randy Dunlap (2):
docs: kdoc_parser: handle struct member macro
VIRTIO_DECLARE_FEATURES(name)
docs: xforms_lists: ignore context analysis and lock attributes
Documentation/tools/kdoc_parser.rst | 8 ++ tools/lib/python/kdoc/kdoc_files.py | 3 +- tools/lib/python/kdoc/kdoc_parser.py | 172 +++----------------------- tools/lib/python/kdoc/kdoc_re.py | 115 +++++++++++++---- tools/lib/python/kdoc/xforms_lists.py | 170 +++++++++++++++++++++++++ 5 files changed, 286 insertions(+), 182 deletions(-) create mode 100644 tools/lib/python/kdoc/xforms_lists.py
Signature · 1 line
2.52.0
PATCH 1/18 docs: kdoc_re: add support for groups()
Add an equivalent to re groups() method.
This is useful on debug messages.
--- tools/lib/python/kdoc/kdoc_re.py | 7 +++++++ 1 file changed, 7 insertions(+)
tools/lib/python/kdoc/kdoc_re.py +7 -0
@@ -106,6 +106,13 @@ class KernRe: return self.last_match.group(num) + def groups(self): + """ + Returns the group results of the last match + """ + + return self.last_match.groups() + class NestedMatch: """
Signature · 1 line
2.52.0
PATCH 2/18 docs: kdoc_re: don't go past the end of a line
In reply to Mauro Carvalho ChehabThe logic which checks if the line ends with ";" is currently
broken: it may try to read past the buffer.
Fix it by checking before trying to access line[pos].
--- tools/lib/python/kdoc/kdoc_re.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/lib/python/kdoc/kdoc_re.py +1 -1
@@ -269,7 +269,7 @@ class NestedMatch: out += new_sub # Drop end ';' if any - if line[pos] == ';': + if pos < len(line) and line[pos] == ';': pos += 1 cur_pos = pos
Signature · 1 line
2.52.0
PATCH 3/18 docs: kdoc_parser: move var transformers to the beginning
In reply to Mauro Carvalho ChehabJust like functions and structs had their transform variables placed at the beginning, move variable transforms to there as well.
No functional changes.
--- tools/lib/python/kdoc/kdoc_parser.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-)
tools/lib/python/kdoc/kdoc_parser.py +13 -10
@@ -192,6 +192,18 @@ function_xforms = [ (KernRe(r"__attribute__\s*\(\((?:[\w\s]+(?:\([^)]*\))?\s*,?)+\)\)\s+"), ""), ] +# +# Transforms for variable prototypes +# +var_xforms = [ + (KernRe(r"__read_mostly"), ""), + (KernRe(r"__ro_after_init"), ""), + (KernRe(r"(?://.*)$"), ""), + (KernRe(r"(?:/\*.*\*/)"), ""), + (KernRe(r";$"), ""), + (KernRe(r"=.*"), ""), +] + # # Ancillary functions #
@@ -972,15 +984,6 @@ class KernelDoc: ] OPTIONAL_VAR_ATTR = "^(?:" + "|".join(VAR_ATTRIBS) + ")?" - sub_prefixes = [ - (KernRe(r"__read_mostly"), ""), - (KernRe(r"__ro_after_init"), ""), - (KernRe(r"(?://.*)$"), ""), - (KernRe(r"(?:/\*.*\*/)"), ""), - (KernRe(r";$"), ""), - (KernRe(r"=.*"), ""), - ] - # # Store the full prototype before modifying it #
@@ -1004,7 +1007,7 @@ class KernelDoc: # Drop comments and macros to have a pure C prototype # if not declaration_name: - for r, sub in sub_prefixes: + for r, sub in var_xforms: proto = r.sub(sub, proto) proto = proto.rstrip()
Signature · 1 line
2.52.0
PATCH 4/18 docs: kdoc_parser: don't mangle with function defines
In reply to Mauro Carvalho ChehabMangling with #defines is not nice, as we may end removing the macro names, preventing several macros from being properly documented.
Also, on defines, we have something like:
#define foo(a1, a2, a3, ...) \ /* some real implementation */
The prototype part (first line on this example) won't contain any macros, so no need to apply any regexes on it.
With that, move the apply_transforms() logic to ensure that it will be called only on functions.
--- tools/lib/python/kdoc/kdoc_parser.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
tools/lib/python/kdoc/kdoc_parser.py +7 -5
@@ -163,7 +163,7 @@ struct_nested_prefixes = [ # # Transforms for function prototypes # -function_xforms = [ +function_xforms = [ (KernRe(r"^static +"), ""), (KernRe(r"^extern +"), ""), (KernRe(r"^asmlinkage +"), ""),
@@ -1066,10 +1066,7 @@ class KernelDoc: found = func_macro = False return_type = '' decl_type = 'function' - # - # Apply the initial transformations. - # - prototype = apply_transforms(function_xforms, prototype) + # # If we have a macro, remove the "#define" at the front. #
@@ -1088,6 +1085,11 @@ class KernelDoc: declaration_name = r.group(1) func_macro = True found = True + else: + # + # Apply the initial transformations. + # + prototype = apply_transforms(function_xforms, prototype) # Yes, this truly is vile. We are looking for: # 1. Return type (may be nothing if we're looking at a macro)
Signature · 1 line
2.52.0
PATCH 5/18 docs: kdoc_parser: fix variable regexes to work with size_t
In reply to Mauro Carvalho ChehabThe regular expressions meant to pick variable types are too
naive: they forgot that the type word may contain underlines.
It also means that we need to change the regex which detects var attributes to handle "const".
--- tools/lib/python/kdoc/kdoc_parser.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
tools/lib/python/kdoc/kdoc_parser.py +4 -3
@@ -981,8 +981,9 @@ class KernelDoc: """ VAR_ATTRIBS = [ "extern", + "const", ] - OPTIONAL_VAR_ATTR = "^(?:" + "|".join(VAR_ATTRIBS) + ")?" + OPTIONAL_VAR_ATTR = r"^(?:\b(?:" +"|".join(VAR_ATTRIBS) +r")\b\s*)*" # # Store the full prototype before modifying it
@@ -1018,14 +1019,14 @@ class KernelDoc: default_val = None - r= KernRe(OPTIONAL_VAR_ATTR + r"\w.*\s+(?:\*+)?([\w_]+)\s*[\d\]\[]*\s*(=.*)?") + r= KernRe(OPTIONAL_VAR_ATTR + r"[\w_]*\s+(?:\*+)?([\w_]+)\s*[\d\]\[]*\s*(=.*)?") if r.match(proto): if not declaration_name: declaration_name = r.group(1) default_val = r.group(2) else: - r= KernRe(OPTIONAL_VAR_ATTR + r"(?:\w.*)?\s+(?:\*+)?(?:[\w_]+)\s*[\d\]\[]*\s*(=.*)?") + r= KernRe(OPTIONAL_VAR_ATTR + r"(?:[\w_]*)?\s+(?:\*+)?(?:[\w_]+)\s*[\d\]\[]*\s*(=.*)?") if r.match(proto): default_val = r.group(1)
Signature · 1 line
2.52.0
PATCH 6/18 docs: kdoc_parser: fix the default_value logic for variables
In reply to Mauro Carvalho ChehabThe indentation is wrong for the second regex, which causes problems on variables with defaults.
--- tools/lib/python/kdoc/kdoc_parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/lib/python/kdoc/kdoc_parser.py +2 -2
@@ -1027,9 +1027,9 @@ class KernelDoc: default_val = r.group(2) else: r= KernRe(OPTIONAL_VAR_ATTR + r"(?:[\w_]*)?\s+(?:\*+)?(?:[\w_]+)\s*[\d\]\[]*\s*(=.*)?") - if r.match(proto): - default_val = r.group(1) + if r.match(proto): + default_val = r.group(1) if not declaration_name: self.emit_msg(ln,f"{proto}: can't parse variable") return
Signature · 1 line
2.52.0
PATCH 7/18 docs: kdoc_parser: don't exclude defaults from prototype
In reply to Mauro Carvalho ChehabIf we do that, the defaults won't be parsed.
--- tools/lib/python/kdoc/kdoc_parser.py | 1 - 1 file changed, 1 deletion(-)
tools/lib/python/kdoc/kdoc_parser.py +0 -1
@@ -201,7 +201,6 @@ var_xforms = [ (KernRe(r"(?://.*)$"), ""), (KernRe(r"(?:/\*.*\*/)"), ""), (KernRe(r";$"), ""), - (KernRe(r"=.*"), ""), ] #
Signature · 1 line
2.52.0
PATCH 8/18 docs: kdoc_parser: fix parser to support multi-word types
In reply to Mauro Carvalho ChehabThe regular expression currently expects a single word for the type, but it may be something like "struct foo".
Add support for it.
--- tools/lib/python/kdoc/kdoc_parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/lib/python/kdoc/kdoc_parser.py +2 -2
@@ -1018,14 +1018,14 @@ class KernelDoc: default_val = None - r= KernRe(OPTIONAL_VAR_ATTR + r"[\w_]*\s+(?:\*+)?([\w_]+)\s*[\d\]\[]*\s*(=.*)?") + r= KernRe(OPTIONAL_VAR_ATTR + r"\s*[\w_\s]*\s+(?:\*+)?([\w_]+)\s*[\d\]\[]*\s*(=.*)?") if r.match(proto): if not declaration_name: declaration_name = r.group(1) default_val = r.group(2) else: - r= KernRe(OPTIONAL_VAR_ATTR + r"(?:[\w_]*)?\s+(?:\*+)?(?:[\w_]+)\s*[\d\]\[]*\s*(=.*)?") + r= KernRe(OPTIONAL_VAR_ATTR + r"(?:[\w_\s]*)?\s+(?:\*+)?(?:[\w_]+)\s*[\d\]\[]*\s*(=.*)?") if r.match(proto): default_val = r.group(1)
Signature · 1 line
2.52.0
Jonathan Corbet
maintainerRe: [PATCH 08/18] docs: kdoc_parser: fix parser to support multi-word types
Quoted 18 lines · Mauro Carvalho Chehab
The regular expression currently expects a single word for the type, but it may be something like "struct foo".
Add support for it.
Signed-off-by Mauro Carvalho Chehab <[email protected]>Acked-by Randy Dunlap <[email protected]>Tested-by Randy Dunlap <[email protected]>Reviewed-by Aleksandr Loktionov <[email protected]>--- tools/lib/python/kdoc/kdoc_parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)tools/lib/python/kdoc/kdoc_parser.py +0
-0
tools/lib/python/kdoc/kdoc_parser.py class KernelDoc: · line 1021
Quoted 5 lines
tools/lib/python/kdoc/kdoc_parser.py +1
-1@@ -1018,14 +1018,14 @@ class KernelDoc: default_val = None - r= KernRe(OPTIONAL_VAR_ATTR + r"[\w_]*\s+(?:\*+)?([\w_]+)\s*[\d\]\[]*\s*(=.*)?") + r= KernRe(OPTIONAL_VAR_ATTR + r"\s*[\w_\s]*\s+(?:\*+)?([\w_]+)\s*[\d\]\[]*\s*(=.*)?")
Just for future reference...I *really* think that the code is improved by breaking up and commenting gnarly regexes like this. They are really unreadable in this form. (And yes, I know the code has been full of these forever, but we can always try to make it better :)
Anyway, just grumbling.
Thanks,
jon
Re: [PATCH 08/18] docs: kdoc_parser: fix parser to support multi-word types
Quoted 23 lines · On Tue, 03 Mar 2026 10:34:48 -0700 Jonathan Corbet <[email protected]> wrote:
Quoted 21 lines · Mauro Carvalho Chehab
The regular expression currently expects a single word for the type, but it may be something like "struct foo".
Add support for it.
Signed-off-by Mauro Carvalho Chehab <[email protected]>Acked-by Randy Dunlap <[email protected]>Tested-by Randy Dunlap <[email protected]>Reviewed-by Aleksandr Loktionov <[email protected]>--- tools/lib/python/kdoc/kdoc_parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)tools/lib/python/kdoc/kdoc_parser.py +0
-0@@ -1018,14 +1018,14 @@ class KernelDoc: default_val = None
Quoted 7 lines
tools/lib/python/kdoc/kdoc_parser.py class KernelDoc: · line 1021
Quoted 2 lines
tools/lib/python/kdoc/kdoc_parser.py +1
-1- r= KernRe(OPTIONAL_VAR_ATTR + r"[\w_]*\s+(?:\*+)?([\w_]+)\s*[\d\]\[]*\s*(=.*)?") + r= KernRe(OPTIONAL_VAR_ATTR + r"\s*[\w_\s]*\s+(?:\*+)?([\w_]+)\s*[\d\]\[]*\s*(=.*)?")Just for future reference...I *really* think that the code is improved by breaking up and commenting gnarly regexes like this. They are really unreadable in this form. (And yes, I know the code has been full of these forever, but we can always try to make it better :)
Heh, you're right: this could be better.
Quoted 1 line
Anyway, just grumbling.
Heh, if we start using a code like the tokenizer I'm experimenting here:
https://lore.kernel.org/linux-doc/20260303155310.5235b367@localhost/
we could probably get rid of regexes in the future, using instead a loop that would be picking "ID" tokens, e.g. basically we would have something similar to this completely untested code snippet:
self.tokenizer = CTokenizer()
...
ids = []
get_default = False
while kind, value in self.tokenizer(proto):
if kind == "ID":
ids.append(value)
if kind == "OP" and value == "=":
get_default = True
break
if get_default:
while kind, value in self.tokenizer(proto):
if kind in ["CHAR", "STRING", "NUMBER"]:
default_val = value break
declaration_name = ids[-1]
Thanks,
Mauro
Jonathan Corbet
maintainerRe: [PATCH 08/18] docs: kdoc_parser: fix parser to support multi-word types
Quoted 8 lines · Mauro Carvalho Chehab
Heh, if we start using a code like the tokenizer I'm experimenting here:
https://lore.kernel.org/linux-doc/20260303155310.5235b367@localhost/we could probably get rid of regexes in the future, using instead a loop that would be picking "ID" tokens, e.g. basically we would have something similar to this completely untested code snippet:
...which has some appeal, but I will confess to being leery of another massive kernel-doc thrash; it would be nice if things settled for a bit.
One can always dream :)
jon
Re: [PATCH 08/18] docs: kdoc_parser: fix parser to support multi-word types
Quoted 5 lines · On Tue, 03 Mar 2026 13:24:55 -0700 Jonathan Corbet <[email protected]> wrote:
Quoted 3 lines · Mauro Carvalho Chehab
Heh, if we start using a code like the tokenizer I'm experimenting here:
Quoted 8 lines
Quoted 5 lines
https://lore.kernel.org/linux-doc/20260303155310.5235b367@localhost/we could probably get rid of regexes in the future, using instead a loop that would be picking "ID" tokens, e.g. basically we would have something similar to this completely untested code snippet:
...which has some appeal, but I will confess to being leery of another massive kernel-doc thrash; it would be nice if things settled for a bit.
Yeah, I feel your pain. The idea is not to simply rewrite the entire kernel-doc. Just to use it at the places that have known hard to solve bugs.
Quoted 1 line
One can always dream :)
The thing is that there are some issues at kernel-doc that can only be solved with a better parser, and a plain regex logic won't fix, even with really complex expressions.
I'm not talking about variable handling like on this specific patch. For it, the current pure regex approach works fine, at least for the cases we already mapped.
However, kernel-doc, even after this series, do a crap job on several places:
1. Macros used to build structs and function prototypes.
During the conversion I wrote a half-baked NestedMatch class to be able of properly handling struct_group*(), which is the best example of the involved complexity. It works, but it requires parsing the code twice.
Also, It probably will fail with nested struct_group;
2. Nested structs.
Current logic just transform them on an un-nested struct-like pseudo-code to re-use the structs regex-based parser;
3. Nested struct identifiers handling.
Spec says that if one has:
struct {
struct {
int foo;
} a;
} b;kernel-doc should document "foo" as "a.foo", but this is not always the case, due to bugs at the parser. So, on some places, you need to use "foo"; on others, "a.foo".
4. Public/private handling.
Code almost works, but when it finds a unmatched private inside a nested struct, it will can hide close brackets. This prevents fixing (2).
5. Comments strip.
Code kinda works if you don't touch it, but when trying to solve the previous issues, I ended discovering some hidden problems related to the way it does.
(That's basically when I ended opting to try a different approach:
too much changes to try to live with a plain regex approach, plus all stuff needed for NestedMatch to do a better job)
6. Proper whitespace and alignment at the output.
The current way we parse things mean that little changes end mangling with whitespaces, line breaks and/or indentation.
Perhaps we could use some token-based formatter for man pages to properly handle open/close brackets.
For rst output, we're relying at the C domain to handle it for us. Still, perhaps a tokenizer-based approach can just add a single whitespace everywhere, which would help us to check before/after differences on kernel-doc changes.
I attempted fixing this at the /38 patch series and afterwards (good news that that we have 18 less patches after you merged this one), but my current pending patch pile has stlll +40 patches to address issues and add unit tests.
Among them, I have changes:
- adding support for "\1", "\2", "\3"... group matches at NestedMatch sub. It works. The code itself is small, but very complex;
- writing a different logic to address comment stripping;
- write a logic to pick struct IDs on nested cases that will be using an approach similar to NestedMatch.
- some of those new logic are recursive, which makes them more complex to be understood and tested.
Such approach works, but, as Jani pointed, this ends adding lots of complexity, and the main reason is that we're acquainted to use regexes - or perhaps too afraid to handle it on a different way. Also, they ended introducing extra bugs.
I had to confess that I also a little reticent on trying to use a tokenizer, as I was afraid that this would require extra libraries to have something similar to what flex/bison would be doing. Then, I realized that perhaps the already internal libraries might just have what we needed. So, after some research, looking at:
https://docs.python.org/3/library/re.html#writing-a-tokenizer
and doing some (so far simple) tests, I'm starting to think about modifying my pending patches to use a code similar to it.
Note that, at this point, I didn't try yet to use the tokenizer, so for now this is still mostly a brainstorm.
I intend to try to use the tokenizer to handle comments e.g. touching the logic at trim_private_members() and see how it behaves. This is self-contained, checking the results would likely be easy, and I don't expect big surprises.
Depending on such tests, I may try to modify NestedMatch and my patches using it to use the same approach.
So, if all ends well, the changes will so far be confined to the code used by dump_struct().
Let's see.
Thanks,
Mauro
PATCH 9/18 docs: kdoc_parser: add support for LIST_HEAD
In reply to Mauro Carvalho ChehabConvert LIST_HEAD into struct list_head when handling its prototype.
--- tools/lib/python/kdoc/kdoc_parser.py | 1 + 1 file changed, 1 insertion(+)
tools/lib/python/kdoc/kdoc_parser.py +1 -0
@@ -198,6 +198,7 @@ function_xforms = [ var_xforms = [ (KernRe(r"__read_mostly"), ""), (KernRe(r"__ro_after_init"), ""), + (KernRe(r"LIST_HEAD\(([\w_]+)\)"), r"struct list_head \1"), (KernRe(r"(?://.*)$"), ""), (KernRe(r"(?:/\*.*\*/)"), ""), (KernRe(r";$"), ""),
Signature · 1 line
2.52.0
PATCH 10/18 docs: kdoc_parser: handle struct member macro VIRTIO_DECLARE_FEATURES(name)
In reply to Mauro Carvalho ChehabFrom: Randy Dunlap <[email protected]>
Parse the macro VIRTIO_DECLARE_FEATURES(name) and expand it to its definition. These prevents one build warning:
WARNING: include/linux/virtio.h:188 struct member 'VIRTIO_DECLARE_FEATURES(features' not described in 'virtio_device'
--- tools/lib/python/kdoc/kdoc_parser.py | 1 + 1 file changed, 1 insertion(+)
tools/lib/python/kdoc/kdoc_parser.py +1 -0
@@ -150,6 +150,7 @@ struct_xforms = [ struct_args_pattern + r'\)', re.S), r'\1 \2[]'), (KernRe(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + struct_args_pattern + r'\)', re.S), r'dma_addr_t \1'), (KernRe(r'DEFINE_DMA_UNMAP_LEN\s*\(' + struct_args_pattern + r'\)', re.S), r'__u32 \1'), + (KernRe(r'VIRTIO_DECLARE_FEATURES\(([\w_]+)\)'), r'union { u64 \1; u64 \1_array[VIRTIO_FEATURES_U64S]; }'), ] # # Regexes here are guaranteed to have the end delimiter matching
Signature · 1 line
2.52.0
PATCH 11/18 docs: kdoc_re: better show KernRe() at documentation
In reply to Mauro Carvalho Chehabthe __repr__() function is used by autodoc to document macro initialization.
Add a better representation for them.
--- tools/lib/python/kdoc/kdoc_re.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
tools/lib/python/kdoc/kdoc_re.py +22 -1
@@ -52,7 +52,28 @@ class KernRe: return self.regex.pattern def __repr__(self): - return f're.compile("{self.regex.pattern}")' + """ + Returns a displayable version of the class init. + """ + + flag_map = { + re.IGNORECASE: "re.I", + re.MULTILINE: "re.M", + re.DOTALL: "re.S", + re.VERBOSE: "re.X", + } + + flags = [] + for flag, name in flag_map.items(): + if self.regex.flags & flag: + flags.append(name) + + flags_name = " | ".join(flags) + + if flags_name: + return f'KernRe("{self.regex.pattern}", {flags_name})' + else: + return f'KernRe("{self.regex.pattern}")' def __add__(self, other): """
Signature · 1 line
2.52.0
PATCH 12/18 docs: kdoc_parser: move transform lists to a separate file
In reply to Mauro Carvalho ChehabOver the time, most of the changes at kernel-doc are related to maintaining a list of transforms to convert macros into pure C code.
Place such transforms on a separate module, to cleanup the parser module.
There is an advantage on that: QEMU also uses our own kernel-doc, but the xforms list there is different. By placing it on a separate module, we can minimize the differences and make it easier to keep QEMU in sync with Kernel upstream.
No functional changes.
--- Documentation/tools/kdoc_parser.rst | 8 ++ tools/lib/python/kdoc/kdoc_files.py | 3 +- tools/lib/python/kdoc/kdoc_parser.py | 145 +----------------------- tools/lib/python/kdoc/xforms_lists.py | 153 ++++++++++++++++++++++++++ 4 files changed, 168 insertions(+), 141 deletions(-) create mode 100644 tools/lib/python/kdoc/xforms_lists.py
Documentation/tools/kdoc_parser.rst +8 -0
@@ -4,6 +4,14 @@ Kernel-doc parser stage ======================= +C replacement rules used by the parser +====================================== + +.. automodule:: lib.python.kdoc.xforms_lists + :members: + :show-inheritance: + :undoc-members: + File handler classes ====================
tools/lib/python/kdoc/kdoc_files.py +2 -1
@@ -15,6 +15,7 @@ import os import re from kdoc.kdoc_parser import KernelDoc +from kdoc.xforms_lists import CTransforms from kdoc.kdoc_output import OutputFormat
@@ -117,7 +118,7 @@ class KernelFiles(): if fname in self.files: return - doc = KernelDoc(self.config, fname) + doc = KernelDoc(self.config, fname, CTransforms()) export_table, entries = doc.parse_kdoc() self.export_table[fname] = export_table
tools/lib/python/kdoc/kdoc_parser.py +5 -140
189 lines not on this page · raw message
tools/lib/python/kdoc/xforms_lists.py new file +153 -0
153 lines not on this page · raw message
Signature · 1 line
2.52.0
PATCH 13/18 docs: xforms_lists: ignore context analysis and lock attributes
In reply to Mauro Carvalho ChehabFrom: Randy Dunlap <[email protected]>
Drop context analysis and lock (tracking) attributes to avoid kernel-doc warnings.
There are now lots of warnings like these:
Documentation/core-api/kref:328: ../include/linux/kref.h:72: WARNING: Invalid C declaration: Expected end of definition. [error at 96]
int kref_put_mutex (struct kref *kref, void (*release)(struct kref *kref), struct mutex *mutex) __cond_acquires(true# mutex) ------------------------------------------------------------------------------------------------^
Documentation/core-api/kref:328: ../include/linux/kref.h:94: WARNING: Invalid C declaration: Expected end of definition. [error at 92]
int kref_put_lock (struct kref *kref, void (*release)(struct kref *kref), spinlock_t *lock) __cond_acquires(true# lock) --------------------------------------------------------------------------------------------^
The regex is suggested by Mauro; mine was too greedy. Thanks. Updated context analysis and lock macros list provided by PeterZ. Thanks.
[mchehab: modified to be applied after xforms_lists split]
--- tools/lib/python/kdoc/kdoc_parser.py | 10 ++++++++++ tools/lib/python/kdoc/xforms_lists.py | 5 +++++ 2 files changed, 15 insertions(+)
tools/lib/python/kdoc/kdoc_parser.py +10 -0
@@ -75,6 +75,16 @@ doc_begin_func = KernRe(str(doc_com) + # initial " * ' # is allowed. # struct_nested_prefixes = [ + (re.compile(r"__cond_acquires\s*\("), ""), + (re.compile(r"__cond_releases\s*\("), ""), + (re.compile(r"__acquires\s*\("), ""), + (re.compile(r"__releases\s*\("), ""), + (re.compile(r"__must_hold\s*\("), ""), + (re.compile(r"__must_not_hold\s*\("), ""), + (re.compile(r"__must_hold_shared\s*\("), ""), + (re.compile(r"__cond_acquires_shared\s*\("), ""), + (re.compile(r"__acquires_shared\s*\("), ""), + (re.compile(r"__releases_shared\s*\("), ""), (re.compile(r'\bSTRUCT_GROUP\('), r'\1'), ]
tools/lib/python/kdoc/xforms_lists.py +5 -0
@@ -22,6 +22,8 @@ class CTransforms: (KernRe(r'\s*__aligned\s*\([^;]*\)', re.S), ' '), (KernRe(r'\s*__counted_by\s*\([^;]*\)', re.S), ' '), (KernRe(r'\s*__counted_by_(le|be)\s*\([^;]*\)', re.S), ' '), + (KernRe(r'\s*__guarded_by\s*\([^\)]*\)', re.S), ' '), + (KernRe(r'\s*__pt_guarded_by\s*\([^\)]*\)', re.S), ' '), (KernRe(r'\s*__packed\s*', re.S), ' '), (KernRe(r'\s*CRYPTO_MINALIGN_ATTR', re.S), ' '), (KernRe(r'\s*__private', re.S), ' '),
@@ -120,6 +122,7 @@ class CTransforms: (KernRe(r"__(?:re)?alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\) +"), ""), (KernRe(r"__diagnose_as\s*\(\s*\S+\s*(?:,\s*\d+\s*)*\) +"), ""), (KernRe(r"DECL_BUCKET_PARAMS\s*\(\s*(\S+)\s*,\s*(\S+)\s*\)"), r"\1, \2"), + (KernRe(r"__no_context_analysis\s*"), ""), (KernRe(r"__attribute_const__ +"), ""), (KernRe(r"__attribute__\s*\(\((?:[\w\s]+(?:\([^)]*\))?\s*,?)+\)\)\s+"), ""), ]
@@ -128,6 +131,8 @@ class CTransforms: var_xforms = [ (KernRe(r"__read_mostly"), ""), (KernRe(r"__ro_after_init"), ""), + (KernRe(r'\s*__guarded_by\s*\([^\)]*\)', re.S), ""), + (KernRe(r'\s*__pt_guarded_by\s*\([^\)]*\)', re.S), ""), (KernRe(r"LIST_HEAD\(([\w_]+)\)"), r"struct list_head \1"), (KernRe(r"(?://.*)$"), ""), (KernRe(r"(?:/\*.*\*/)"), ""),
Signature · 1 line
2.52.0
PATCH 14/18 docs: kdoc_re: handle strings and escape chars on NextMatch
In reply to Mauro Carvalho ChehabThe logic inside NestedMatch currently doesn't consider that function arguments may have chars and strings, which may eventually contain delimiters.
Add logic to handle strings and escape characters on them.
--- tools/lib/python/kdoc/kdoc_re.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
tools/lib/python/kdoc/kdoc_re.py +18 -0
@@ -216,6 +216,8 @@ class NestedMatch: for match_re in regex.finditer(line): start = match_re.start() offset = match_re.end() + string_char = None + escape = False d = line[offset - 1] if d not in self.DELIMITER_PAIRS:
@@ -229,6 +231,22 @@ class NestedMatch: d = line[pos] + if escape: + escape = False + continue + + if string_char: + if d == '\\': + escape = True + elif d == string_char: + string_char = None + + continue + + if d in ('"', "'"): + string_char = d + continue + if d in self.DELIMITER_PAIRS: end = self.DELIMITER_PAIRS[d]
Signature · 1 line
2.52.0
PATCH 15/18 docs: kdoc_re: don't recompile NestedMatch regex every time
In reply to Mauro Carvalho ChehabStore delimiters and its regex-compiled version as const vars.
--- tools/lib/python/kdoc/kdoc_re.py | 35 ++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 13 deletions(-)
tools/lib/python/kdoc/kdoc_re.py +22 -13
@@ -99,6 +99,13 @@ class KernRe: self.last_match = self.regex.search(string) return self.last_match + def finditer(self, string): + """ + Alias to re.finditer. + """ + + return self.regex.finditer(string) + def findall(self, string): """ Alias to re.findall.
@@ -134,6 +141,16 @@ class KernRe: return self.last_match.groups() +#: Nested delimited pairs (brackets and parenthesis) +DELIMITER_PAIRS = { + '{': '}', + '(': ')', + '[': ']', +} + +#: compiled delimiters +RE_DELIM = KernRe(r'[\{\}\[\]\(\)]') + class NestedMatch: """
@@ -183,14 +200,6 @@ class NestedMatch: # # FOO(arg1, arg2, arg3) - DELIMITER_PAIRS = { - '{': '}', - '(': ')', - '[': ']', - } - - RE_DELIM = re.compile(r'[\{\}\[\]\(\)]') - def _search(self, regex, line): """ Finds paired blocks for a regex that ends with a delimiter.
@@ -220,13 +229,13 @@ class NestedMatch: escape = False d = line[offset - 1] - if d not in self.DELIMITER_PAIRS: + if d not in DELIMITER_PAIRS: continue - end = self.DELIMITER_PAIRS[d] + end = DELIMITER_PAIRS[d] stack.append(end) - for match in self.RE_DELIM.finditer(line[offset:]): + for match in RE_DELIM.finditer(line[offset:]): pos = match.start() + offset d = line[pos]
@@ -247,8 +256,8 @@ class NestedMatch: string_char = d continue - if d in self.DELIMITER_PAIRS: - end = self.DELIMITER_PAIRS[d] + if d in DELIMITER_PAIRS: + end = DELIMITER_PAIRS[d] stack.append(end) continue
Signature · 1 line
2.52.0
PATCH 16/18 docs: kdoc_re: Change NestedMath args replacement to \0
In reply to Mauro Carvalho ChehabFuture patches will allow parsing each argument instead of the hole set. Prepare for it by changing the replace all args from \1 to \0.
No functional changes.
--- tools/lib/python/kdoc/kdoc_parser.py | 2 +- tools/lib/python/kdoc/kdoc_re.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-)
tools/lib/python/kdoc/kdoc_parser.py +1 -1
@@ -85,7 +85,7 @@ struct_nested_prefixes = [ (re.compile(r"__cond_acquires_shared\s*\("), ""), (re.compile(r"__acquires_shared\s*\("), ""), (re.compile(r"__releases_shared\s*\("), ""), - (re.compile(r'\bSTRUCT_GROUP\('), r'\1'), + (re.compile(r'\bSTRUCT_GROUP\('), r'\0'), ] #
tools/lib/python/kdoc/kdoc_re.py +4 -4
@@ -188,7 +188,7 @@ class NestedMatch: # except that the content inside the match group is delimiter-aligned. # # The content inside parentheses is converted into a single replace - # group (e.g. r`\1'). + # group (e.g. r`\0'). # # It would be nice to change such definition to support multiple # match groups, allowing a regex equivalent to:
@@ -291,7 +291,7 @@ class NestedMatch: if the sub argument contains:: - r'\1' + r'\0' it will work just like re: it places there the matched paired data with the delimiter stripped.
@@ -310,9 +310,9 @@ class NestedMatch: # Value, ignoring start/end delimiters value = line[end:pos - 1] - # replaces \1 at the sub string, if \1 is used there + # replaces \0 at the sub string, if \0 is used there new_sub = sub - new_sub = new_sub.replace(r'\1', value) + new_sub = new_sub.replace(r'\0', value) out += new_sub
Signature · 1 line
2.52.0
PATCH 17/18 docs: kdoc_re: make NestedMatch use KernRe
In reply to Mauro Carvalho ChehabInstead of using re_compile, let's create the class with the regex and use KernRe to keep it cached.
--- tools/lib/python/kdoc/kdoc_parser.py | 25 ++++++++++++------------- tools/lib/python/kdoc/kdoc_re.py | 24 +++++++++++++++++------- 2 files changed, 29 insertions(+), 20 deletions(-)
tools/lib/python/kdoc/kdoc_parser.py +12 -13
@@ -75,17 +75,17 @@ doc_begin_func = KernRe(str(doc_com) + # initial " * ' # is allowed. # struct_nested_prefixes = [ - (re.compile(r"__cond_acquires\s*\("), ""), - (re.compile(r"__cond_releases\s*\("), ""), - (re.compile(r"__acquires\s*\("), ""), - (re.compile(r"__releases\s*\("), ""), - (re.compile(r"__must_hold\s*\("), ""), - (re.compile(r"__must_not_hold\s*\("), ""), - (re.compile(r"__must_hold_shared\s*\("), ""), - (re.compile(r"__cond_acquires_shared\s*\("), ""), - (re.compile(r"__acquires_shared\s*\("), ""), - (re.compile(r"__releases_shared\s*\("), ""), - (re.compile(r'\bSTRUCT_GROUP\('), r'\0'), + (NestedMatch(r"__cond_acquires\s*\("), ""), + (NestedMatch(r"__cond_releases\s*\("), ""), + (NestedMatch(r"__acquires\s*\("), ""), + (NestedMatch(r"__releases\s*\("), ""), + (NestedMatch(r"__must_hold\s*\("), ""), + (NestedMatch(r"__must_not_hold\s*\("), ""), + (NestedMatch(r"__must_hold_shared\s*\("), ""), + (NestedMatch(r"__cond_acquires_shared\s*\("), ""), + (NestedMatch(r"__acquires_shared\s*\("), ""), + (NestedMatch(r"__releases_shared\s*\("), ""), + (NestedMatch(r'\bSTRUCT_GROUP\('), r'\0'), ] #
@@ -761,9 +761,8 @@ class KernelDoc: members = trim_private_members(members) members = self.xforms.apply("struct", members) - nested = NestedMatch() for search, sub in struct_nested_prefixes: - members = nested.sub(search, sub, members) + members = search.sub(search, sub, members) # # Deal with embedded struct and union members, and drop enums entirely. #
tools/lib/python/kdoc/kdoc_re.py +17 -7
@@ -200,7 +200,10 @@ class NestedMatch: # # FOO(arg1, arg2, arg3) - def _search(self, regex, line): + def __init__(self, regex): + self.regex = KernRe(regex) + + def _search(self, line): """ Finds paired blocks for a regex that ends with a delimiter.
@@ -222,7 +225,7 @@ class NestedMatch: stack = [] - for match_re in regex.finditer(line): + for match_re in self.regex.finditer(line): start = match_re.start() offset = match_re.end() string_char = None
@@ -270,7 +273,7 @@ class NestedMatch: yield start, offset, pos + 1 break - def search(self, regex, line): + def search(self, line): """ This is similar to re.search:
@@ -278,12 +281,12 @@ class NestedMatch: returning occurrences only if all delimiters are paired. """ - for t in self._search(regex, line): + for t in self._search(line): yield line[t[0]:t[2]] - def sub(self, regex, sub, line, count=0): - r""" + def sub(self, sub, line, count=0): + """ This is similar to re.sub: It matches a regex that it is followed by a delimiter,
@@ -304,7 +307,7 @@ class NestedMatch: cur_pos = 0 n = 0 - for start, end, pos in self._search(regex, line): + for start, end, pos in self._search(line): out += line[cur_pos:start] # Value, ignoring start/end delimiters
@@ -331,3 +334,10 @@ class NestedMatch: out += line[cur_pos:l] return out + + def __repr__(self): + """ + Returns a displayable version of the class init. + """ + + return f'NestedMatch("{self.regex.regex.pattern}")'
Signature · 1 line
2.52.0
PATCH 18/18 docs: kdoc_parser: move nested match transforms to xforms_lists.py
In reply to Mauro Carvalho ChehabAs NestedMatch now has a sub method and a declaration close to what KernRe does, we can move the rules to xforms_lists and simplify kdoc_parser a little bit.
No functional changes.
--- tools/lib/python/kdoc/kdoc_parser.py | 21 --------------------- tools/lib/python/kdoc/xforms_lists.py | 14 +++++++++++++- 2 files changed, 13 insertions(+), 22 deletions(-)
tools/lib/python/kdoc/kdoc_parser.py +0 -21
@@ -69,25 +69,6 @@ doc_begin_func = KernRe(str(doc_com) + # initial " * ' r'(?:[-:].*)?$', # description (not captured) cache = False) -# -# Regexes here are guaranteed to have the end delimiter matching -# the start delimiter. Yet, right now, only one replace group -# is allowed. -# -struct_nested_prefixes = [ - (NestedMatch(r"__cond_acquires\s*\("), ""), - (NestedMatch(r"__cond_releases\s*\("), ""), - (NestedMatch(r"__acquires\s*\("), ""), - (NestedMatch(r"__releases\s*\("), ""), - (NestedMatch(r"__must_hold\s*\("), ""), - (NestedMatch(r"__must_not_hold\s*\("), ""), - (NestedMatch(r"__must_hold_shared\s*\("), ""), - (NestedMatch(r"__cond_acquires_shared\s*\("), ""), - (NestedMatch(r"__acquires_shared\s*\("), ""), - (NestedMatch(r"__releases_shared\s*\("), ""), - (NestedMatch(r'\bSTRUCT_GROUP\('), r'\0'), -] - # # Ancillary functions #
@@ -761,8 +742,6 @@ class KernelDoc: members = trim_private_members(members) members = self.xforms.apply("struct", members) - for search, sub in struct_nested_prefixes: - members = search.sub(search, sub, members) # # Deal with embedded struct and union members, and drop enums entirely. #
tools/lib/python/kdoc/xforms_lists.py +13 -1
@@ -4,7 +4,7 @@ import re -from kdoc.kdoc_re import KernRe +from kdoc.kdoc_re import KernRe, NestedMatch struct_args_pattern = r'([^,)]+)'
@@ -94,6 +94,18 @@ class CTransforms: (KernRe(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + struct_args_pattern + r'\)', re.S), r'dma_addr_t \1'), (KernRe(r'DEFINE_DMA_UNMAP_LEN\s*\(' + struct_args_pattern + r'\)', re.S), r'__u32 \1'), (KernRe(r'VIRTIO_DECLARE_FEATURES\(([\w_]+)\)'), r'union { u64 \1; u64 \1_array[VIRTIO_FEATURES_U64S]; }'), + + (NestedMatch(r"__cond_acquires\s*\("), ""), + (NestedMatch(r"__cond_releases\s*\("), ""), + (NestedMatch(r"__acquires\s*\("), ""), + (NestedMatch(r"__releases\s*\("), ""), + (NestedMatch(r"__must_hold\s*\("), ""), + (NestedMatch(r"__must_not_hold\s*\("), ""), + (NestedMatch(r"__must_hold_shared\s*\("), ""), + (NestedMatch(r"__cond_acquires_shared\s*\("), ""), + (NestedMatch(r"__acquires_shared\s*\("), ""), + (NestedMatch(r"__releases_shared\s*\("), ""), + (NestedMatch(r'\bSTRUCT_GROUP\('), r'\0'), ] #: Transforms for function prototypes.
Signature · 1 line
2.52.0
Jonathan Corbet
maintainerQuoted 7 lines · Mauro Carvalho Chehab
Hi Jon,
This series contains patches from:
https://lore.kernel.org/linux-doc/[email protected]/T/#tI rebased them to make the changes cleaner, fixing mostly on fixes.
Quoted 8 lines
I dropped stuff related to NestedMatch arguments parsing. I'll be sending you on a new patch series, likely tomorrow.
The changes here basically addresses several issues discoverd by Randy and by me and makes NestedMatch more similar to KernRe.
It also moves the transforms ruleset to a separate file, to make easier to maintain kernel-doc code.
OK, I have applied this set - it all seems to work as advertised as far as I can tell.
Thanks,
jon