xref: /linux/tools/lib/python/kdoc/xforms_lists.py (revision c6c23449b3029757864c6895420296acbe096534)
1#!/usr/bin/env python3
2# SPDX-License-Identifier: GPL-2.0
3# Copyright(c) 2026: Mauro Carvalho Chehab <mchehab@kernel.org>.
4
5import re
6
7from kdoc.kdoc_re import KernRe, NestedMatch
8
9struct_args_pattern = r'([^,)]+)'
10
11class CTransforms:
12    """
13    Data class containing a long set of transformations to turn
14    structure member prefixes, and macro invocations and variables
15    into something we can parse and generate kdoc for.
16    """
17
18    #: Transforms for structs and unions.
19    struct_xforms = [
20        # Strip attributes
21        (KernRe(r"__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)", flags=re.I | re.S, cache=False), ' '),
22        (KernRe(r'\s*__aligned\s*\([^;]*\)', re.S), ' '),
23        (KernRe(r'\s*__counted_by\s*\([^;]*\)', re.S), ' '),
24        (KernRe(r'\s*__counted_by_(le|be)\s*\([^;]*\)', re.S), ' '),
25        (KernRe(r'\s*__guarded_by\s*\([^\)]*\)', re.S), ' '),
26        (KernRe(r'\s*__pt_guarded_by\s*\([^\)]*\)', re.S), ' '),
27        (KernRe(r'\s*__packed\s*', re.S), ' '),
28        (KernRe(r'\s*CRYPTO_MINALIGN_ATTR', re.S), ' '),
29        (KernRe(r'\s*__private', re.S), ' '),
30        (KernRe(r'\s*__rcu', re.S), ' '),
31        (KernRe(r'\s*____cacheline_aligned_in_smp', re.S), ' '),
32        (KernRe(r'\s*____cacheline_aligned', re.S), ' '),
33        (KernRe(r'\s*__cacheline_group_(begin|end)\([^\)]+\);'), ''),
34        #
35        # Unwrap struct_group macros based on this definition:
36        # __struct_group(TAG, NAME, ATTRS, MEMBERS...)
37        # which has variants like: struct_group(NAME, MEMBERS...)
38        # Only MEMBERS arguments require documentation.
39        #
40        # Parsing them happens on two steps:
41        #
42        # 1. drop struct group arguments that aren't at MEMBERS,
43        #    storing them as STRUCT_GROUP(MEMBERS)
44        #
45        # 2. remove STRUCT_GROUP() ancillary macro.
46        #
47        # The original logic used to remove STRUCT_GROUP() using an
48        # advanced regex:
49        #
50        #   \bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;
51        #
52        # with two patterns that are incompatible with
53        # Python re module, as it has:
54        #
55        #   - a recursive pattern: (?1)
56        #   - an atomic grouping: (?>...)
57        #
58        # I tried a simpler version: but it didn't work either:
59        #   \bSTRUCT_GROUP\(([^\)]+)\)[^;]*;
60        #
61        # As it doesn't properly match the end parenthesis on some cases.
62        #
63        # So, a better solution was crafted: there's now a NestedMatch
64        # class that ensures that delimiters after a search are properly
65        # matched. So, the implementation to drop STRUCT_GROUP() will be
66        # handled in separate.
67        #
68        (KernRe(r'\bstruct_group\s*\(([^,]*,)', re.S), r'STRUCT_GROUP('),
69        (KernRe(r'\bstruct_group_attr\s*\(([^,]*,){2}', re.S), r'STRUCT_GROUP('),
70        (KernRe(r'\bstruct_group_tagged\s*\(([^,]*),([^,]*),', re.S), r'struct \1 \2; STRUCT_GROUP('),
71        (KernRe(r'\b__struct_group\s*\(([^,]*,){3}', re.S), r'STRUCT_GROUP('),
72        #
73        # Replace macros
74        #
75        # TODO: use NestedMatch for FOO($1, $2, ...) matches
76        #
77        # it is better to also move those to the NestedMatch logic,
78        # to ensure that parentheses will be properly matched.
79        #
80        (KernRe(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S),
81        r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'),
82        (KernRe(r'DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)', re.S),
83        r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'),
84        (KernRe(r'DECLARE_BITMAP\s*\(' + struct_args_pattern + r',\s*' + struct_args_pattern + r'\)',
85                re.S), r'unsigned long \1[BITS_TO_LONGS(\2)]'),
86        (KernRe(r'DECLARE_HASHTABLE\s*\(' + struct_args_pattern + r',\s*' + struct_args_pattern + r'\)',
87                re.S), r'unsigned long \1[1 << ((\2) - 1)]'),
88        (KernRe(r'DECLARE_KFIFO\s*\(' + struct_args_pattern + r',\s*' + struct_args_pattern +
89                r',\s*' + struct_args_pattern + r'\)', re.S), r'\2 *\1'),
90        (KernRe(r'DECLARE_KFIFO_PTR\s*\(' + struct_args_pattern + r',\s*' +
91                struct_args_pattern + r'\)', re.S), r'\2 *\1'),
92        (KernRe(r'(?:__)?DECLARE_FLEX_ARRAY\s*\(' + struct_args_pattern + r',\s*' +
93                struct_args_pattern + r'\)', re.S), r'\1 \2[]'),
94        (KernRe(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + struct_args_pattern + r'\)', re.S), r'dma_addr_t \1'),
95        (KernRe(r'DEFINE_DMA_UNMAP_LEN\s*\(' + struct_args_pattern + r'\)', re.S), r'__u32 \1'),
96        (KernRe(r'VIRTIO_DECLARE_FEATURES\(([\w_]+)\)'), r'union { u64 \1; u64 \1_array[VIRTIO_FEATURES_U64S]; }'),
97
98        (NestedMatch(r"__cond_acquires\s*\("), ""),
99        (NestedMatch(r"__cond_releases\s*\("), ""),
100        (NestedMatch(r"__acquires\s*\("), ""),
101        (NestedMatch(r"__releases\s*\("), ""),
102        (NestedMatch(r"__must_hold\s*\("), ""),
103        (NestedMatch(r"__must_not_hold\s*\("), ""),
104        (NestedMatch(r"__must_hold_shared\s*\("), ""),
105        (NestedMatch(r"__cond_acquires_shared\s*\("), ""),
106        (NestedMatch(r"__acquires_shared\s*\("), ""),
107        (NestedMatch(r"__releases_shared\s*\("), ""),
108        (NestedMatch(r'\bSTRUCT_GROUP\('), r'\0'),
109    ]
110
111    #: Transforms for function prototypes.
112    function_xforms = [
113        (KernRe(r"^static +"), ""),
114        (KernRe(r"^extern +"), ""),
115        (KernRe(r"^asmlinkage +"), ""),
116        (KernRe(r"^inline +"), ""),
117        (KernRe(r"^__inline__ +"), ""),
118        (KernRe(r"^__inline +"), ""),
119        (KernRe(r"^__always_inline +"), ""),
120        (KernRe(r"^noinline +"), ""),
121        (KernRe(r"^__FORTIFY_INLINE +"), ""),
122        (KernRe(r"__init +"), ""),
123        (KernRe(r"__init_or_module +"), ""),
124        (KernRe(r"__exit +"), ""),
125        (KernRe(r"__deprecated +"), ""),
126        (KernRe(r"__flatten +"), ""),
127        (KernRe(r"__meminit +"), ""),
128        (KernRe(r"__must_check +"), ""),
129        (KernRe(r"__weak +"), ""),
130        (KernRe(r"__sched +"), ""),
131        (KernRe(r"_noprof"), ""),
132        (KernRe(r"__always_unused *"), ""),
133        (KernRe(r"__printf\s*\(\s*\d*\s*,\s*\d*\s*\) +"), ""),
134        (KernRe(r"__(?:re)?alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\) +"), ""),
135        (KernRe(r"__diagnose_as\s*\(\s*\S+\s*(?:,\s*\d+\s*)*\) +"), ""),
136        (KernRe(r"DECL_BUCKET_PARAMS\s*\(\s*(\S+)\s*,\s*(\S+)\s*\)"), r"\1, \2"),
137        (KernRe(r"__no_context_analysis\s*"), ""),
138        (KernRe(r"__attribute_const__ +"), ""),
139        (KernRe(r"__attribute__\s*\(\((?:[\w\s]+(?:\([^)]*\))?\s*,?)+\)\)\s+"), ""),
140    ]
141
142    #: Transforms for variable prototypes.
143    var_xforms = [
144        (KernRe(r"__read_mostly"), ""),
145        (KernRe(r"__ro_after_init"), ""),
146        (KernRe(r'\s*__guarded_by\s*\([^\)]*\)', re.S), ""),
147        (KernRe(r'\s*__pt_guarded_by\s*\([^\)]*\)', re.S), ""),
148        (KernRe(r"LIST_HEAD\(([\w_]+)\)"), r"struct list_head \1"),
149        (KernRe(r"(?://.*)$"), ""),
150        (KernRe(r"(?:/\*.*\*/)"), ""),
151        (KernRe(r";$"), ""),
152    ]
153
154    #: Transforms main dictionary used at apply_transforms().
155    xforms = {
156        "struct": struct_xforms,
157        "func": function_xforms,
158        "var": var_xforms,
159    }
160
161    def apply(self, xforms_type, text):
162        """
163        Apply a set of transforms to a block of text.
164        """
165        if xforms_type not in self.xforms:
166            return text
167
168        for search, subst in self.xforms[xforms_type]:
169            text = search.sub(subst, text)
170        return text
171