Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

scripts/kernel_doc.py: better handle exported symbols

Change the logic which detects internal/external symbols in a way
that we can re-use it when calling via Sphinx extension.

While here, remove an unused self.config var and let it clearer
that self.config variables are read-only. This helps to allow
handling multiple times in parallel if ever needed.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Link: https://lore.kernel.org/r/6a69ba8d2b7ee6a6427abb53e60d09bd4d3565ee.1744106242.git.mchehab+huawei@kernel.org

authored by

Mauro Carvalho Chehab and committed by
Jonathan Corbet
16740c29 a566ba5a

+125 -80
+1 -1
scripts/kernel-doc.py
··· 287 287 288 288 for t in kfiles.msg(enable_lineno=args.enable_lineno, export=args.export, 289 289 internal=args.internal, symbol=args.symbol, 290 - nosymbol=args.nosymbol, 290 + nosymbol=args.nosymbol, export_file=args.export_file, 291 291 no_doc_sections=args.no_doc_sections): 292 292 msg = t[1] 293 293 if msg:
+76 -66
scripts/lib/kdoc/kdoc_files.py
··· 68 68 handling directories if any 69 69 """ 70 70 71 + if not file_list: 72 + return 73 + 71 74 for fname in file_list: 72 75 if self.srctree: 73 76 f = os.path.join(self.srctree, fname) ··· 87 84 88 85 class KernelFiles(): 89 86 """ 90 - Parse lernel-doc tags on multiple kernel source files. 87 + Parse kernel-doc tags on multiple kernel source files. 88 + 89 + There are two type of parsers defined here: 90 + - self.parse_file(): parses both kernel-doc markups and 91 + EXPORT_SYMBOL* macros; 92 + - self.process_export_file(): parses only EXPORT_SYMBOL* macros. 91 93 """ 94 + 95 + def warning(self, msg): 96 + """Ancillary routine to output a warning and increment error count""" 97 + 98 + self.config.log.warning(msg) 99 + self.errors += 1 100 + 101 + def error(self, msg): 102 + """Ancillary routine to output an error and increment error count""" 103 + 104 + self.config.log.error(msg) 105 + self.errors += 1 92 106 93 107 def parse_file(self, fname): 94 108 """ 95 109 Parse a single Kernel source. 96 110 """ 97 111 98 - doc = KernelDoc(self.config, fname) 99 - doc.run() 112 + # Prevent parsing the same file twice if results are cached 113 + if fname in self.files: 114 + return 100 115 101 - return doc.entries 116 + doc = KernelDoc(self.config, fname) 117 + export_table, entries = doc.parse_kdoc() 118 + 119 + self.export_table[fname] = export_table 120 + 121 + self.files.add(fname) 122 + self.export_files.add(fname) # parse_kdoc() already check exports 123 + 124 + self.results[fname] = entries 102 125 103 126 def process_export_file(self, fname): 104 127 """ 105 128 Parses EXPORT_SYMBOL* macros from a single Kernel source file. 106 129 """ 107 - try: 108 - with open(fname, "r", encoding="utf8", 109 - errors="backslashreplace") as fp: 110 - for line in fp: 111 - KernelDoc.process_export(self.config.function_table, line) 112 130 113 - except IOError: 114 - self.config.log.error("Error: Cannot open fname %s", fname) 115 - self.config.errors += 1 131 + # Prevent parsing the same file twice if results are cached 132 + if fname in self.export_files: 133 + return 134 + 135 + doc = KernelDoc(self.config, fname) 136 + export_table = doc.parse_export() 137 + 138 + if not export_table: 139 + self.error(f"Error: Cannot check EXPORT_SYMBOL* on {fname}") 140 + export_table = set() 141 + 142 + self.export_table[fname] = export_table 143 + self.export_files.add(fname) 116 144 117 145 def file_not_found_cb(self, fname): 118 146 """ 119 147 Callback to warn if a file was not found. 120 148 """ 121 149 122 - self.config.log.error("Cannot find file %s", fname) 123 - self.config.errors += 1 150 + self.error(f"Cannot find file {fname}") 124 151 125 152 def __init__(self, verbose=False, out_style=None, 126 153 werror=False, wreturn=False, wshort_desc=False, ··· 180 147 if kdoc_werror: 181 148 werror = kdoc_werror 182 149 183 - # Set global config data used on all files 150 + # Some variables are global to the parser logic as a whole as they are 151 + # used to send control configuration to KernelDoc class. As such, 152 + # those variables are read-only inside the KernelDoc. 184 153 self.config = argparse.Namespace 185 154 186 155 self.config.verbose = verbose ··· 191 156 self.config.wshort_desc = wshort_desc 192 157 self.config.wcontents_before_sections = wcontents_before_sections 193 158 194 - self.config.function_table = set() 195 - self.config.source_map = {} 196 - 197 159 if not logger: 198 160 self.config.log = logging.getLogger("kernel-doc") 199 161 else: 200 162 self.config.log = logger 201 163 202 - self.config.kernel_version = os.environ.get("KERNELVERSION", 203 - "unknown kernel version'") 164 + self.config.warning = self.warning 165 + 204 166 self.config.src_tree = os.environ.get("SRCTREE", None) 167 + 168 + # Initialize variables that are internal to KernelFiles 205 169 206 170 self.out_style = out_style 207 171 208 - # Initialize internal variables 209 - 210 - self.config.errors = 0 172 + self.errors = 0 211 173 self.results = {} 212 174 213 175 self.files = set() 214 176 self.export_files = set() 177 + self.export_table = {} 215 178 216 179 def parse(self, file_list, export_file=None): 217 180 """ ··· 218 185 219 186 glob = GlobSourceFiles(srctree=self.config.src_tree) 220 187 221 - # Prevent parsing the same file twice to speedup parsing and 222 - # avoid reporting errors multiple times 223 - 224 188 for fname in glob.parse_files(file_list, self.file_not_found_cb): 225 - if fname not in self.files: 226 - self.results[fname] = self.parse_file(fname) 227 - self.files.add(fname) 228 - 229 - # If a list of export files was provided, parse EXPORT_SYMBOL* 230 - # from files that weren't fully parsed 231 - 232 - if not export_file: 233 - return 234 - 235 - self.export_files |= self.files 236 - 237 - glob = GlobSourceFiles(srctree=self.config.src_tree) 189 + self.parse_file(fname) 238 190 239 191 for fname in glob.parse_files(export_file, self.file_not_found_cb): 240 - if fname not in self.export_files: 241 - self.process_export_file(fname) 242 - self.export_files.add(fname) 192 + self.process_export_file(fname) 243 193 244 194 def out_msg(self, fname, name, arg): 245 195 """ ··· 239 223 240 224 def msg(self, enable_lineno=False, export=False, internal=False, 241 225 symbol=None, nosymbol=None, no_doc_sections=False, 242 - filenames=None): 226 + filenames=None, export_file=None): 243 227 """ 244 228 Interacts over the kernel-doc results and output messages, 245 229 returning kernel-doc markups on each interaction 246 230 """ 247 231 248 - function_table = self.config.function_table 249 - 250 - if symbol: 251 - for s in symbol: 252 - function_table.add(s) 253 - 254 - # Output none mode: only warnings will be shown 255 - if not self.out_style: 256 - return 257 - 258 232 self.out_style.set_config(self.config) 259 - 260 - self.out_style.set_filter(export, internal, symbol, nosymbol, 261 - function_table, enable_lineno, 262 - no_doc_sections) 263 233 264 234 if not filenames: 265 235 filenames = sorted(self.results.keys()) 266 236 267 237 for fname in filenames: 238 + function_table = set() 239 + 240 + if internal or export: 241 + if not export_file: 242 + export_file = [fname] 243 + 244 + for f in export_file: 245 + function_table |= self.export_table[f] 246 + 247 + if symbol: 248 + for s in symbol: 249 + function_table.add(s) 250 + 251 + self.out_style.set_filter(export, internal, symbol, nosymbol, 252 + function_table, enable_lineno, 253 + no_doc_sections) 254 + 268 255 msg = "" 269 256 for name, arg in self.results[fname]: 270 257 msg += self.out_msg(fname, name, arg) ··· 280 261 fname, ln, dtype) 281 262 if msg: 282 263 yield fname, msg 283 - 284 - @property 285 - def errors(self): 286 - """ 287 - Return a count of the number of warnings found, including 288 - the ones displayed while interacting over self.msg. 289 - """ 290 - 291 - return self.config.errors
+3 -6
scripts/lib/kdoc/kdoc_output.py
··· 69 69 self.enable_lineno = None 70 70 self.nosymbol = {} 71 71 self.symbol = None 72 - self.function_table = set() 72 + self.function_table = None 73 73 self.config = None 74 74 self.no_doc_sections = False 75 75 ··· 94 94 95 95 self.enable_lineno = enable_lineno 96 96 self.no_doc_sections = no_doc_sections 97 + self.function_table = function_table 97 98 98 99 if symbol: 99 100 self.out_mode = self.OUTPUT_INCLUDE 100 - function_table = symbol 101 101 elif export: 102 102 self.out_mode = self.OUTPUT_EXPORTED 103 103 elif internal: ··· 108 108 if nosymbol: 109 109 self.nosymbol = set(nosymbol) 110 110 111 - if function_table: 112 - self.function_table = function_table 113 111 114 112 def highlight_block(self, block): 115 113 """ ··· 127 129 warnings = args.get('warnings', []) 128 130 129 131 for log_msg in warnings: 130 - self.config.log.warning(log_msg) 131 - self.config.errors += 1 132 + self.config.warning(log_msg) 132 133 133 134 def check_doc(self, name, args): 134 135 """Check if DOC should be output"""
+45 -7
scripts/lib/kdoc/kdoc_parser.py
··· 1133 1133 self.emit_warning(ln, "error: Cannot parse typedef!") 1134 1134 1135 1135 @staticmethod 1136 - def process_export(function_table, line): 1136 + def process_export(function_set, line): 1137 1137 """ 1138 1138 process EXPORT_SYMBOL* tags 1139 1139 1140 - This method is called both internally and externally, so, it 1141 - doesn't use self. 1140 + This method doesn't use any variable from the class, so declare it 1141 + with a staticmethod decorator. 1142 1142 """ 1143 + 1144 + # Note: it accepts only one EXPORT_SYMBOL* per line, as having 1145 + # multiple export lines would violate Kernel coding style. 1143 1146 1144 1147 if export_symbol.search(line): 1145 1148 symbol = export_symbol.group(2) 1146 - function_table.add(symbol) 1149 + function_set.add(symbol) 1150 + return 1147 1151 1148 1152 if export_symbol_ns.search(line): 1149 1153 symbol = export_symbol_ns.group(2) 1150 - function_table.add(symbol) 1154 + function_set.add(symbol) 1151 1155 1152 1156 def process_normal(self, ln, line): 1153 1157 """ ··· 1621 1617 elif doc_content.search(line): 1622 1618 self.entry.contents += doc_content.group(1) + "\n" 1623 1619 1624 - def run(self): 1620 + def parse_export(self): 1621 + """ 1622 + Parses EXPORT_SYMBOL* macros from a single Kernel source file. 1623 + """ 1624 + 1625 + export_table = set() 1626 + 1627 + try: 1628 + with open(self.fname, "r", encoding="utf8", 1629 + errors="backslashreplace") as fp: 1630 + 1631 + for line in fp: 1632 + self.process_export(export_table, line) 1633 + 1634 + except IOError: 1635 + return None 1636 + 1637 + return export_table 1638 + 1639 + def parse_kdoc(self): 1625 1640 """ 1626 1641 Open and process each line of a C source file. 1627 - he parsing is controlled via a state machine, and the line is passed 1642 + The parsing is controlled via a state machine, and the line is passed 1628 1643 to a different process function depending on the state. The process 1629 1644 function may update the state as needed. 1645 + 1646 + Besides parsing kernel-doc tags, it also parses export symbols. 1630 1647 """ 1631 1648 1632 1649 cont = False 1633 1650 prev = "" 1634 1651 prev_ln = None 1652 + export_table = set() 1635 1653 1636 1654 try: 1637 1655 with open(self.fname, "r", encoding="utf8", ··· 1685 1659 self.st_inline_name[self.inline_doc_state], 1686 1660 line) 1687 1661 1662 + # This is an optimization over the original script. 1663 + # There, when export_file was used for the same file, 1664 + # it was read twice. Here, we use the already-existing 1665 + # loop to parse exported symbols as well. 1666 + # 1667 + # TODO: It should be noticed that not all states are 1668 + # needed here. On a future cleanup, process export only 1669 + # at the states that aren't handling comment markups. 1670 + self.process_export(export_table, line) 1671 + 1688 1672 # Hand this line to the appropriate state handler 1689 1673 if self.state == self.STATE_NORMAL: 1690 1674 self.process_normal(ln, line) ··· 1711 1675 self.process_docblock(ln, line) 1712 1676 except OSError: 1713 1677 self.config.log.error(f"Error: Cannot open file {self.fname}") 1678 + 1679 + return export_table, self.entries