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/lib/kdoc/kdoc_parser.py: move kernel entry to a class

The KernelDoc class is too complex. Start optimizing it by
placing the kernel-doc parser entry to a separate class.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Message-ID: <28b456f726a022011f0ce5810dbcc26827c1403a.1745564565.git.mchehab+huawei@kernel.org>

authored by

Mauro Carvalho Chehab and committed by
Jonathan Corbet
e3b42e94 a4bd43d6

+149 -124
+149 -124
scripts/lib/kdoc/kdoc_parser.py
··· 12 12 documentation comments 13 13 """ 14 14 15 - import argparse 16 15 import re 17 16 from pprint import pformat 18 17 ··· 103 104 "_ERROR", 104 105 ] 105 106 107 + SECTION_DEFAULT = "Description" # default section 108 + 109 + class KernelEntry: 110 + 111 + def __init__(self, config, ln): 112 + self.config = config 113 + 114 + self.contents = "" 115 + self.function = "" 116 + self.sectcheck = "" 117 + self.struct_actual = "" 118 + self.prototype = "" 119 + 120 + self.warnings = [] 121 + 122 + self.parameterlist = [] 123 + self.parameterdescs = {} 124 + self.parametertypes = {} 125 + self.parameterdesc_start_lines = {} 126 + 127 + self.section_start_lines = {} 128 + self.sectionlist = [] 129 + self.sections = {} 130 + 131 + self.anon_struct_union = False 132 + 133 + self.leading_space = None 134 + 135 + # State flags 136 + self.brcount = 0 137 + 138 + self.in_doc_sect = False 139 + self.declaration_start_line = ln + 1 140 + 141 + # TODO: rename to emit_message after removal of kernel-doc.pl 142 + def emit_msg(self, log_msg, warning=True): 143 + """Emit a message""" 144 + 145 + if not warning: 146 + self.config.log.info(log_msg) 147 + return 148 + 149 + # Delegate warning output to output logic, as this way it 150 + # will report warnings/info only for symbols that are output 151 + 152 + self.warnings.append(log_msg) 153 + return 154 + 155 + def dump_section(self, start_new=True): 156 + """ 157 + Dumps section contents to arrays/hashes intended for that purpose. 158 + """ 159 + 160 + name = self.section 161 + contents = self.contents 162 + 163 + if type_param.match(name): 164 + name = type_param.group(1) 165 + 166 + self.parameterdescs[name] = contents 167 + self.parameterdesc_start_lines[name] = self.new_start_line 168 + 169 + self.sectcheck += name + " " 170 + self.new_start_line = 0 171 + 172 + elif name == "@...": 173 + name = "..." 174 + self.parameterdescs[name] = contents 175 + self.sectcheck += name + " " 176 + self.parameterdesc_start_lines[name] = self.new_start_line 177 + self.new_start_line = 0 178 + 179 + else: 180 + if name in self.sections and self.sections[name] != "": 181 + # Only warn on user-specified duplicate section names 182 + if name != SECTION_DEFAULT: 183 + self.emit_msg(self.new_start_line, 184 + f"duplicate section name '{name}'\n") 185 + self.sections[name] += contents 186 + else: 187 + self.sections[name] = contents 188 + self.sectionlist.append(name) 189 + self.section_start_lines[name] = self.new_start_line 190 + self.new_start_line = 0 191 + 192 + # self.config.log.debug("Section: %s : %s", name, pformat(vars(self))) 193 + 194 + if start_new: 195 + self.section = SECTION_DEFAULT 196 + self.contents = "" 197 + 106 198 107 199 class KernelDoc: 108 200 """ ··· 203 113 204 114 # Section names 205 115 206 - section_default = "Description" # default section 207 116 section_intro = "Introduction" 208 117 section_context = "Context" 209 118 section_return = "Return" ··· 225 136 # Place all potential outputs into an array 226 137 self.entries = [] 227 138 228 - # TODO: rename to emit_message after removal of kernel-doc.pl 229 - def emit_warning(self, ln, msg, warning=True): 139 + def emit_msg(self, ln, msg, warning=True): 230 140 """Emit a message""" 231 141 232 142 log_msg = f"{self.fname}:{ln} {msg}" 233 143 234 - if not warning: 235 - self.config.log.info(log_msg) 236 - return 237 - 238 144 if self.entry: 239 - # Delegate warning output to output logic, as this way it 240 - # will report warnings/info only for symbols that are output 241 - 242 - self.entry.warnings.append(log_msg) 145 + self.entry.emit_msg(log_msg, warning) 243 146 return 244 147 245 - self.config.log.warning(log_msg) 148 + if warning: 149 + self.config.log.warning(log_msg) 150 + else: 151 + self.config.log.info(log_msg) 246 152 247 153 def dump_section(self, start_new=True): 248 154 """ 249 155 Dumps section contents to arrays/hashes intended for that purpose. 250 156 """ 251 157 252 - name = self.entry.section 253 - contents = self.entry.contents 254 - 255 - if type_param.match(name): 256 - name = type_param.group(1) 257 - 258 - self.entry.parameterdescs[name] = contents 259 - self.entry.parameterdesc_start_lines[name] = self.entry.new_start_line 260 - 261 - self.entry.sectcheck += name + " " 262 - self.entry.new_start_line = 0 263 - 264 - elif name == "@...": 265 - name = "..." 266 - self.entry.parameterdescs[name] = contents 267 - self.entry.sectcheck += name + " " 268 - self.entry.parameterdesc_start_lines[name] = self.entry.new_start_line 269 - self.entry.new_start_line = 0 270 - 271 - else: 272 - if name in self.entry.sections and self.entry.sections[name] != "": 273 - # Only warn on user-specified duplicate section names 274 - if name != self.section_default: 275 - self.emit_warning(self.entry.new_start_line, 276 - f"duplicate section name '{name}'\n") 277 - self.entry.sections[name] += contents 278 - else: 279 - self.entry.sections[name] = contents 280 - self.entry.sectionlist.append(name) 281 - self.entry.section_start_lines[name] = self.entry.new_start_line 282 - self.entry.new_start_line = 0 283 - 284 - # self.config.log.debug("Section: %s : %s", name, pformat(vars(self.entry))) 285 - 286 - if start_new: 287 - self.entry.section = self.section_default 288 - self.entry.contents = "" 158 + if self.entry: 159 + self.entry.dump_section(start_new) 289 160 290 161 # TODO: rename it to store_declaration after removal of kernel-doc.pl 291 162 def output_declaration(self, dtype, name, **args): ··· 290 241 variables used by the state machine. 291 242 """ 292 243 293 - self.entry = argparse.Namespace 294 - 295 - self.entry.contents = "" 296 - self.entry.function = "" 297 - self.entry.sectcheck = "" 298 - self.entry.struct_actual = "" 299 - self.entry.prototype = "" 300 - 301 - self.entry.warnings = [] 302 - 303 - self.entry.parameterlist = [] 304 - self.entry.parameterdescs = {} 305 - self.entry.parametertypes = {} 306 - self.entry.parameterdesc_start_lines = {} 307 - 308 - self.entry.section_start_lines = {} 309 - self.entry.sectionlist = [] 310 - self.entry.sections = {} 311 - 312 - self.entry.anon_struct_union = False 313 - 314 - self.entry.leading_space = None 244 + self.entry = KernelEntry(self.config, ln) 315 245 316 246 # State flags 317 247 self.state = state.NORMAL 318 248 self.inline_doc_state = state.INLINE_NA 319 - self.entry.brcount = 0 320 - 321 - self.entry.in_doc_sect = False 322 - self.entry.declaration_start_line = ln + 1 323 249 324 250 def push_parameter(self, ln, decl_type, param, dtype, 325 251 org_arg, declaration_name): ··· 352 328 else: 353 329 dname = f"{decl_type} member" 354 330 355 - self.emit_warning(ln, 356 - f"{dname} '{param}' not described in '{declaration_name}'") 331 + self.emit_msg(ln, 332 + f"{dname} '{param}' not described in '{declaration_name}'") 357 333 358 334 # Strip spaces from param so that it is one continuous string on 359 335 # parameterlist. This fixes a problem where check_sections() ··· 417 393 if r.match(arg): 418 394 param = r.group(1) 419 395 else: 420 - self.emit_warning(ln, f"Invalid param: {arg}") 396 + self.emit_msg(ln, f"Invalid param: {arg}") 421 397 param = arg 422 398 423 399 dtype = KernRe(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg) ··· 433 409 if r.match(arg): 434 410 param = r.group(1) 435 411 else: 436 - self.emit_warning(ln, f"Invalid param: {arg}") 412 + self.emit_msg(ln, f"Invalid param: {arg}") 437 413 param = arg 438 414 439 415 dtype = KernRe(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg) ··· 466 442 if KernRe(r'^(\*+)\s*(.*)').match(param): 467 443 r = KernRe(r'^(\*+)\s*(.*)') 468 444 if not r.match(param): 469 - self.emit_warning(ln, f"Invalid param: {param}") 445 + self.emit_msg(ln, f"Invalid param: {param}") 470 446 continue 471 447 472 448 param = r.group(1) ··· 479 455 elif KernRe(r'(.*?):(\w+)').search(param): 480 456 r = KernRe(r'(.*?):(\w+)') 481 457 if not r.match(param): 482 - self.emit_warning(ln, f"Invalid param: {param}") 458 + self.emit_msg(ln, f"Invalid param: {param}") 483 459 continue 484 460 485 461 if dtype != "": # Skip unnamed bit-fields ··· 527 503 else: 528 504 dname = f"{decl_type} member" 529 505 530 - self.emit_warning(ln, 531 - f"Excess {dname} '{sects[sx]}' description in '{decl_name}'") 506 + self.emit_msg(ln, 507 + f"Excess {dname} '{sects[sx]}' description in '{decl_name}'") 532 508 533 509 def check_return_section(self, ln, declaration_name, return_type): 534 510 """ ··· 545 521 return 546 522 547 523 if not self.entry.sections.get("Return", None): 548 - self.emit_warning(ln, 549 - f"No description found for return value of '{declaration_name}'") 524 + self.emit_msg(ln, 525 + f"No description found for return value of '{declaration_name}'") 550 526 551 527 def dump_struct(self, ln, proto): 552 528 """ ··· 585 561 members = r.group(2) 586 562 587 563 if not members: 588 - self.emit_warning(ln, f"{proto} error: Cannot parse struct or union!") 564 + self.emit_msg(ln, f"{proto} error: Cannot parse struct or union!") 589 565 return 590 566 591 567 if self.entry.identifier != declaration_name: 592 - self.emit_warning(ln, 593 - f"expecting prototype for {decl_type} {self.entry.identifier}. Prototype was for {decl_type} {declaration_name} instead\n") 568 + self.emit_msg(ln, 569 + f"expecting prototype for {decl_type} {self.entry.identifier}. Prototype was for {decl_type} {declaration_name} instead\n") 594 570 return 595 571 596 572 args_pattern = r'([^,)]+)' ··· 859 835 members = r.group(2).rstrip() 860 836 861 837 if not members: 862 - self.emit_warning(ln, f"{proto}: error: Cannot parse enum!") 838 + self.emit_msg(ln, f"{proto}: error: Cannot parse enum!") 863 839 return 864 840 865 841 if self.entry.identifier != declaration_name: 866 842 if self.entry.identifier == "": 867 - self.emit_warning(ln, 868 - f"{proto}: wrong kernel-doc identifier on prototype") 843 + self.emit_msg(ln, 844 + f"{proto}: wrong kernel-doc identifier on prototype") 869 845 else: 870 - self.emit_warning(ln, 871 - f"expecting prototype for enum {self.entry.identifier}. Prototype was for enum {declaration_name} instead") 846 + self.emit_msg(ln, 847 + f"expecting prototype for enum {self.entry.identifier}. Prototype was for enum {declaration_name} instead") 872 848 return 873 849 874 850 if not declaration_name: ··· 885 861 self.entry.parameterlist.append(arg) 886 862 if arg not in self.entry.parameterdescs: 887 863 self.entry.parameterdescs[arg] = self.undescribed 888 - self.emit_warning(ln, 889 - f"Enum value '{arg}' not described in enum '{declaration_name}'") 864 + self.emit_msg(ln, 865 + f"Enum value '{arg}' not described in enum '{declaration_name}'") 890 866 member_set.add(arg) 891 867 892 868 for k in self.entry.parameterdescs: 893 869 if k not in member_set: 894 - self.emit_warning(ln, 895 - f"Excess enum value '%{k}' description in '{declaration_name}'") 870 + self.emit_msg(ln, 871 + f"Excess enum value '%{k}' description in '{declaration_name}'") 896 872 897 873 self.output_declaration('enum', declaration_name, 898 874 enum=declaration_name, ··· 1047 1023 found = True 1048 1024 break 1049 1025 if not found: 1050 - self.emit_warning(ln, 1051 - f"cannot understand function prototype: '{prototype}'") 1026 + self.emit_msg(ln, 1027 + f"cannot understand function prototype: '{prototype}'") 1052 1028 return 1053 1029 1054 1030 if self.entry.identifier != declaration_name: 1055 - self.emit_warning(ln, 1056 - f"expecting prototype for {self.entry.identifier}(). Prototype was for {declaration_name}() instead") 1031 + self.emit_msg(ln, 1032 + f"expecting prototype for {self.entry.identifier}(). Prototype was for {declaration_name}() instead") 1057 1033 return 1058 1034 1059 1035 prms = " ".join(self.entry.parameterlist) ··· 1116 1092 args = r.group(3) 1117 1093 1118 1094 if self.entry.identifier != declaration_name: 1119 - self.emit_warning(ln, 1120 - f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n") 1095 + self.emit_msg(ln, 1096 + f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n") 1121 1097 return 1122 1098 1123 1099 decl_type = 'function' ··· 1148 1124 declaration_name = r.group(1) 1149 1125 1150 1126 if self.entry.identifier != declaration_name: 1151 - self.emit_warning(ln, f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n") 1127 + self.emit_msg(ln, 1128 + f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n") 1152 1129 return 1153 1130 1154 1131 self.output_declaration('typedef', declaration_name, ··· 1160 1135 purpose=self.entry.declaration_purpose) 1161 1136 return 1162 1137 1163 - self.emit_warning(ln, "error: Cannot parse typedef!") 1138 + self.emit_msg(ln, "error: Cannot parse typedef!") 1164 1139 1165 1140 @staticmethod 1166 1141 def process_export(function_set, line): ··· 1257 1232 self.state = state.BODY 1258 1233 1259 1234 # if there's no @param blocks need to set up default section here 1260 - self.entry.section = self.section_default 1235 + self.entry.section = SECTION_DEFAULT 1261 1236 self.entry.new_start_line = ln + 1 1262 1237 1263 1238 r = KernRe("[-:](.*)") ··· 1273 1248 self.entry.declaration_purpose = "" 1274 1249 1275 1250 if not self.entry.is_kernel_comment: 1276 - self.emit_warning(ln, 1277 - f"This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n{line}") 1251 + self.emit_msg(ln, 1252 + f"This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n{line}") 1278 1253 self.state = state.NORMAL 1279 1254 1280 1255 if not self.entry.declaration_purpose and self.config.wshort_desc: 1281 - self.emit_warning(ln, 1282 - f"missing initial short description on line:\n{line}") 1256 + self.emit_msg(ln, 1257 + f"missing initial short description on line:\n{line}") 1283 1258 1284 1259 if not self.entry.identifier and self.entry.decl_type != "enum": 1285 - self.emit_warning(ln, 1286 - f"wrong kernel-doc identifier on line:\n{line}") 1260 + self.emit_msg(ln, 1261 + f"wrong kernel-doc identifier on line:\n{line}") 1287 1262 self.state = state.NORMAL 1288 1263 1289 1264 if self.config.verbose: 1290 - self.emit_warning(ln, 1291 - f"Scanning doc for {self.entry.decl_type} {self.entry.identifier}", 1265 + self.emit_msg(ln, 1266 + f"Scanning doc for {self.entry.decl_type} {self.entry.identifier}", 1292 1267 warning=False) 1293 1268 1294 1269 return 1295 1270 1296 1271 # Failed to find an identifier. Emit a warning 1297 - self.emit_warning(ln, f"Cannot find identifier on line:\n{line}") 1272 + self.emit_msg(ln, f"Cannot find identifier on line:\n{line}") 1298 1273 1299 1274 def process_body(self, ln, line): 1300 1275 """ ··· 1305 1280 r = KernRe(r"\s*\*\s?\S") 1306 1281 if r.match(line): 1307 1282 self.dump_section() 1308 - self.entry.section = self.section_default 1283 + self.entry.section = SECTION_DEFAULT 1309 1284 self.entry.new_start_line = ln 1310 1285 self.entry.contents = "" 1311 1286 ··· 1350 1325 # Look for doc_com + <text> + doc_end: 1351 1326 r = KernRe(r'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') 1352 1327 if r.match(line): 1353 - self.emit_warning(ln, f"suspicious ending line: {line}") 1328 + self.emit_msg(ln, f"suspicious ending line: {line}") 1354 1329 1355 1330 self.entry.prototype = "" 1356 1331 self.entry.new_start_line = ln + 1 ··· 1368 1343 self.entry.new_start_line = ln 1369 1344 self.state = state.BODY 1370 1345 else: 1371 - if self.entry.section != self.section_default: 1346 + if self.entry.section != SECTION_DEFAULT: 1372 1347 self.state = state.BODY_WITH_BLANK_LINE 1373 1348 else: 1374 1349 self.state = state.BODY ··· 1413 1388 return 1414 1389 1415 1390 # Unknown line, ignore 1416 - self.emit_warning(ln, f"bad line: {line}") 1391 + self.emit_msg(ln, f"bad line: {line}") 1417 1392 1418 1393 def process_inline(self, ln, line): 1419 1394 """STATE_INLINE: docbook comments within a prototype.""" ··· 1446 1421 self.entry.contents = "" 1447 1422 1448 1423 elif self.inline_doc_state == state.INLINE_NAME: 1449 - self.emit_warning(ln, 1450 - f"Incorrect use of kernel-doc format: {line}") 1424 + self.emit_msg(ln, 1425 + f"Incorrect use of kernel-doc format: {line}") 1451 1426 1452 1427 self.inline_doc_state = state.INLINE_ERROR 1453 1428 ··· 1519 1494 tracepointargs = r.group(1) 1520 1495 1521 1496 if not tracepointname or not tracepointargs: 1522 - self.emit_warning(ln, 1523 - f"Unrecognized tracepoint format:\n{proto}\n") 1497 + self.emit_msg(ln, 1498 + f"Unrecognized tracepoint format:\n{proto}\n") 1524 1499 else: 1525 1500 proto = f"static inline void trace_{tracepointname}({tracepointargs})" 1526 1501 self.entry.identifier = f"trace_{self.entry.identifier}"