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