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