xref: /linux/tools/lib/python/kdoc/xforms_lists.py (revision 79d881beb721d27f679f0dc1cba2d5fe2d7f6d8d)
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
8from kdoc.c_lex import CMatch, CTokenizer
9
10struct_args_pattern = r'([^,)]+)'
11
12class CTransforms:
13    """
14    Data class containing a long set of transformations to turn
15    structure member prefixes, and macro invocations and variables
16    into something we can parse and generate kdoc for.
17    """
18
19    #
20    # NOTE:
21    #      Due to performance reasons, place CMatch rules before KernRe,
22    #      as this avoids running the C parser every time.
23    #
24
25    #: Transforms for structs and unions.
26    struct_xforms = [
27        # Strip attributes
28        (KernRe(r"__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)", flags=re.I | re.S, cache=False), ' '),
29        (KernRe(r'\s*__aligned\s*\([^;]*\)', re.S), ' '),
30        (KernRe(r'\s*__counted_by\s*\([^;]*\)', re.S), ' '),
31        (KernRe(r'\s*__counted_by_(le|be)\s*\([^;]*\)', re.S), ' '),
32        (KernRe(r'\s*__guarded_by\s*\([^\)]*\)', re.S), ' '),
33        (KernRe(r'\s*__pt_guarded_by\s*\([^\)]*\)', re.S), ' '),
34        (KernRe(r'\s*__packed\s*', re.S), ' '),
35        (KernRe(r'\s*CRYPTO_MINALIGN_ATTR', re.S), ' '),
36        (KernRe(r'\s*__private', re.S), ' '),
37        (KernRe(r'\s*__rcu', re.S), ' '),
38        (KernRe(r'\s*____cacheline_aligned_in_smp', re.S), ' '),
39        (KernRe(r'\s*____cacheline_aligned', re.S), ' '),
40        (KernRe(r'\s*__cacheline_group_(begin|end)\([^\)]+\);'), ''),
41        (KernRe(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S),
42        r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'),
43        (KernRe(r'DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)', re.S),
44        r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'),
45        (KernRe(r'DECLARE_BITMAP\s*\(' + struct_args_pattern + r',\s*' + struct_args_pattern + r'\)',
46                re.S), r'unsigned long \1[BITS_TO_LONGS(\2)]'),
47        (KernRe(r'DECLARE_HASHTABLE\s*\(' + struct_args_pattern + r',\s*' + struct_args_pattern + r'\)',
48                re.S), r'unsigned long \1[1 << ((\2) - 1)]'),
49        (KernRe(r'DECLARE_KFIFO\s*\(' + struct_args_pattern + r',\s*' + struct_args_pattern +
50                r',\s*' + struct_args_pattern + r'\)', re.S), r'\2 *\1'),
51        (KernRe(r'DECLARE_KFIFO_PTR\s*\(' + struct_args_pattern + r',\s*' +
52                struct_args_pattern + r'\)', re.S), r'\2 *\1'),
53        (KernRe(r'(?:__)?DECLARE_FLEX_ARRAY\s*\(' + struct_args_pattern + r',\s*' +
54                struct_args_pattern + r'\)', re.S), r'\1 \2[]'),
55        (KernRe(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + struct_args_pattern + r'\)', re.S), r'dma_addr_t \1'),
56        (KernRe(r'DEFINE_DMA_UNMAP_LEN\s*\(' + struct_args_pattern + r'\)', re.S), r'__u32 \1'),
57        (KernRe(r'VIRTIO_DECLARE_FEATURES\(([\w_]+)\)'), r'union { u64 \1; u64 \1_array[VIRTIO_FEATURES_U64S]; }'),
58
59        (CMatch(r"__cond_acquires"), ""),
60        (CMatch(r"__cond_releases"), ""),
61        (CMatch(r"__acquires"), ""),
62        (CMatch(r"__releases"), ""),
63        (CMatch(r"__must_hold"), ""),
64        (CMatch(r"__must_not_hold"), ""),
65        (CMatch(r"__must_hold_shared"), ""),
66        (CMatch(r"__cond_acquires_shared"), ""),
67        (CMatch(r"__acquires_shared"), ""),
68        (CMatch(r"__releases_shared"), ""),
69
70        #
71        # Macro __struct_group() creates an union with an anonymous
72        # and a non-anonymous struct, depending on the parameters. We only
73        # need one of those at kernel-doc, as we won't be documenting the same
74        # members twice.
75        #
76        (CMatch('struct_group'), r'struct { \2+ };'),
77        (CMatch('struct_group_attr'), r'struct { \3+ };'),
78        (CMatch('struct_group_tagged'), r'struct { \3+ };'),
79        (CMatch('__struct_group'), r'struct { \4+ };'),
80
81    ]
82
83    #: Transforms for function prototypes.
84    function_xforms = [
85        (KernRe(r"^static +"), ""),
86        (KernRe(r"^extern +"), ""),
87        (KernRe(r"^asmlinkage +"), ""),
88        (KernRe(r"^inline +"), ""),
89        (KernRe(r"^__inline__ +"), ""),
90        (KernRe(r"^__inline +"), ""),
91        (KernRe(r"^__always_inline +"), ""),
92        (KernRe(r"^noinline +"), ""),
93        (KernRe(r"^__FORTIFY_INLINE +"), ""),
94        (KernRe(r"__init +"), ""),
95        (KernRe(r"__init_or_module +"), ""),
96        (KernRe(r"__exit +"), ""),
97        (KernRe(r"__deprecated +"), ""),
98        (KernRe(r"__flatten +"), ""),
99        (KernRe(r"__meminit +"), ""),
100        (KernRe(r"__must_check +"), ""),
101        (KernRe(r"__weak +"), ""),
102        (KernRe(r"__sched +"), ""),
103        (KernRe(r"_noprof"), ""),
104        (KernRe(r"__always_unused *"), ""),
105        (KernRe(r"__printf\s*\(\s*\d*\s*,\s*\d*\s*\) +"), ""),
106        (KernRe(r"__(?:re)?alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\) +"), ""),
107        (KernRe(r"__diagnose_as\s*\(\s*\S+\s*(?:,\s*\d+\s*)*\) +"), ""),
108        (KernRe(r"DECL_BUCKET_PARAMS\s*\(\s*(\S+)\s*,\s*(\S+)\s*\)"), r"\1, \2"),
109        (KernRe(r"__no_context_analysis\s*"), ""),
110        (KernRe(r"__attribute_const__ +"), ""),
111        (KernRe(r"__attribute__\s*\(\((?:[\w\s]+(?:\([^)]*\))?\s*,?)+\)\)\s+"), ""),
112    ]
113
114    #: Transforms for variable prototypes.
115    var_xforms = [
116        (KernRe(r"__read_mostly"), ""),
117        (KernRe(r"__ro_after_init"), ""),
118        (KernRe(r'\s*__guarded_by\s*\([^\)]*\)', re.S), ""),
119        (KernRe(r'\s*__pt_guarded_by\s*\([^\)]*\)', re.S), ""),
120        (KernRe(r"LIST_HEAD\(([\w_]+)\)"), r"struct list_head \1"),
121        (KernRe(r"(?://.*)$"), ""),
122        (KernRe(r"(?:/\*.*\*/)"), ""),
123        (KernRe(r";$"), ""),
124    ]
125
126    #: Transforms main dictionary used at apply_transforms().
127    xforms = {
128        "struct": struct_xforms,
129        "func": function_xforms,
130        "var": var_xforms,
131    }
132
133    def apply(self, xforms_type, source):
134        """
135        Apply a set of transforms to a block of source.
136
137        As tokenizer is used here, this function also remove comments
138        at the end.
139        """
140        if xforms_type not in self.xforms:
141            return source
142
143        if isinstance(source, str):
144            source = CTokenizer(source)
145
146        for search, subst in self.xforms[xforms_type]:
147            #
148            # KernRe only accept strings.
149            #
150            if isinstance(search, KernRe):
151                source = str(source)
152
153            source = search.sub(subst, source)
154        return str(source)
155