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("DEFINE_IDTENTRY_IRQ"), r"static void \1(struct pt_regs *regs, u32 vector)"), 94 (CMatch("__cond_acquires"), ""), 95 (CMatch("__cond_releases"), ""), 96 (CMatch("__acquires"), ""), 97 (CMatch("__releases"), ""), 98 (CMatch("__must_hold"), ""), 99 (CMatch("__must_not_hold"), ""), 100 (CMatch("__must_hold_shared"), ""), 101 (CMatch("__cond_acquires_shared"), ""), 102 (CMatch("__acquires_shared"), ""), 103 (CMatch("__releases_shared"), ""), 104 (CMatch("__no_context_analysis"), ""), 105 (CMatch("__attribute_const__"), ""), 106 (CMatch("__attribute__"), ""), 107 (CMatch("STATIC_IFN_KUNIT"), ""), 108 (CMatch("INLINE_IFN_KUNIT"), ""), 109 110 # 111 # HACK: this is similar to process_export() hack. It is meant to 112 # drop _noproof from function name. See for instance: 113 # ahash_request_alloc kernel-doc declaration at include/crypto/hash.h. 114 # 115 (KernRe("_noprof"), ""), 116 ] 117 118 #: Transforms for variable prototypes. 119 var_xforms = [ 120 (CMatch("__read_mostly"), ""), 121 (CMatch("__ro_after_init"), ""), 122 (CMatch("__guarded_by"), ""), 123 (CMatch("__pt_guarded_by"), ""), 124 (CMatch("LIST_HEAD"), r"struct list_head \1"), 125 (CMatch("DECLARE_PER_CPU"), r"\1 \2[PER_CPU]; }"), 126 127 (KernRe(r"(?://.*)$"), ""), 128 (KernRe(r"(?:/\*.*\*/)"), ""), 129 (KernRe(r";$"), ""), 130 ] 131 132 #: Transforms main dictionary used at apply_transforms(). 133 xforms = { 134 "struct": struct_xforms, 135 "func": function_xforms, 136 "var": var_xforms, 137 } 138 139 def apply(self, xforms_type, source): 140 """ 141 Apply a set of transforms to a block of source. 142 143 As tokenizer is used here, this function also remove comments 144 at the end. 145 """ 146 if xforms_type not in self.xforms: 147 return source 148 149 if isinstance(source, str): 150 source = CTokenizer(source) 151 152 for search, subst in self.xforms[xforms_type]: 153 # 154 # KernRe only accept strings. 155 # 156 if isinstance(search, KernRe): 157 source = str(source) 158 159 source = search.sub(subst, source) 160 return str(source) 161