Commit eda603f6cdba4b14dbf80531fab2fe545232e7a0

Authored by Johannes Berg
Committed by Linus Torvalds
1 parent 1f3a66889c

docbook: warn on unused doc entries

When you don't use !E or !I but only !F, then it's very easy to miss
including some functions, structs etc.  in documentation.  To help
finding which ones were missed, allow printing out the unused ones as
warnings.

For example, using this on mac80211 yields a lot of warnings like this:

  Warning: didn't use docs for DOC: mac80211 workqueue
  Warning: didn't use docs for ieee80211_max_queues
  Warning: didn't use docs for ieee80211_bss_change
  Warning: didn't use docs for ieee80211_bss_conf

when generating the documentation for it.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 3 changed files with 183 additions and 3 deletions Side-by-side Diff

Documentation/kernel-doc-nano-HOWTO.txt
... ... @@ -345,6 +345,11 @@
345 345 section titled <section title> from <filename>.
346 346 Spaces are allowed in <section title>; do not quote the <section title>.
347 347  
  348 +!C<filename> is replaced by nothing, but makes the tools check that
  349 +all DOC: sections and documented functions, symbols, etc. are used.
  350 +This makes sense to use when you use !F/!P only and want to verify
  351 +that all documentation is included.
  352 +
348 353 Tim.
349 354 */ <twaugh@redhat.com>
scripts/basic/docproc.c
... ... @@ -34,12 +34,14 @@
34 34 *
35 35 */
36 36  
  37 +#define _GNU_SOURCE
37 38 #include <stdio.h>
38 39 #include <stdlib.h>
39 40 #include <string.h>
40 41 #include <ctype.h>
41 42 #include <unistd.h>
42 43 #include <limits.h>
  44 +#include <errno.h>
43 45 #include <sys/types.h>
44 46 #include <sys/wait.h>
45 47  
... ... @@ -54,6 +56,7 @@
54 56 FILEONLY *internalfunctions;
55 57 FILEONLY *externalfunctions;
56 58 FILEONLY *symbolsonly;
  59 +FILEONLY *findall;
57 60  
58 61 typedef void FILELINE(char * file, char * line);
59 62 FILELINE * singlefunctions;
60 63  
... ... @@ -65,12 +68,30 @@
65 68 #define KERNELDOCPATH "scripts/"
66 69 #define KERNELDOC "kernel-doc"
67 70 #define DOCBOOK "-docbook"
  71 +#define LIST "-list"
68 72 #define FUNCTION "-function"
69 73 #define NOFUNCTION "-nofunction"
70 74 #define NODOCSECTIONS "-no-doc-sections"
71 75  
72 76 static char *srctree, *kernsrctree;
73 77  
  78 +static char **all_list = NULL;
  79 +static int all_list_len = 0;
  80 +
  81 +static void consume_symbol(const char *sym)
  82 +{
  83 + int i;
  84 +
  85 + for (i = 0; i < all_list_len; i++) {
  86 + if (!all_list[i])
  87 + continue;
  88 + if (strcmp(sym, all_list[i]))
  89 + continue;
  90 + all_list[i] = NULL;
  91 + break;
  92 + }
  93 +}
  94 +
74 95 static void usage (void)
75 96 {
76 97 fprintf(stderr, "Usage: docproc {doc|depend} file\n");
... ... @@ -248,6 +269,7 @@
248 269 struct symfile * sym = &symfilelist[i];
249 270 for (j=0; j < sym->symbolcnt; j++) {
250 271 vec[idx++] = type;
  272 + consume_symbol(sym->symbollist[j].name);
251 273 vec[idx++] = sym->symbollist[j].name;
252 274 }
253 275 }
... ... @@ -287,6 +309,11 @@
287 309 vec[idx++] = &line[i];
288 310 }
289 311 }
  312 + for (i = 0; i < idx; i++) {
  313 + if (strcmp(vec[i], FUNCTION))
  314 + continue;
  315 + consume_symbol(vec[i + 1]);
  316 + }
290 317 vec[idx++] = filename;
291 318 vec[idx] = NULL;
292 319 exec_kernel_doc(vec);
... ... @@ -306,6 +333,10 @@
306 333 if (*s == '\n')
307 334 *s = '\0';
308 335  
  336 + asprintf(&s, "DOC: %s", line);
  337 + consume_symbol(s);
  338 + free(s);
  339 +
309 340 vec[0] = KERNELDOC;
310 341 vec[1] = DOCBOOK;
311 342 vec[2] = FUNCTION;
... ... @@ -315,6 +346,84 @@
315 346 exec_kernel_doc(vec);
316 347 }
317 348  
  349 +static void find_all_symbols(char *filename)
  350 +{
  351 + char *vec[4]; /* kerneldoc -list file NULL */
  352 + pid_t pid;
  353 + int ret, i, count, start;
  354 + char real_filename[PATH_MAX + 1];
  355 + int pipefd[2];
  356 + char *data, *str;
  357 + size_t data_len = 0;
  358 +
  359 + vec[0] = KERNELDOC;
  360 + vec[1] = LIST;
  361 + vec[2] = filename;
  362 + vec[3] = NULL;
  363 +
  364 + if (pipe(pipefd)) {
  365 + perror("pipe");
  366 + exit(1);
  367 + }
  368 +
  369 + switch (pid=fork()) {
  370 + case -1:
  371 + perror("fork");
  372 + exit(1);
  373 + case 0:
  374 + close(pipefd[0]);
  375 + dup2(pipefd[1], 1);
  376 + memset(real_filename, 0, sizeof(real_filename));
  377 + strncat(real_filename, kernsrctree, PATH_MAX);
  378 + strncat(real_filename, "/" KERNELDOCPATH KERNELDOC,
  379 + PATH_MAX - strlen(real_filename));
  380 + execvp(real_filename, vec);
  381 + fprintf(stderr, "exec ");
  382 + perror(real_filename);
  383 + exit(1);
  384 + default:
  385 + close(pipefd[1]);
  386 + data = malloc(4096);
  387 + do {
  388 + while ((ret = read(pipefd[0],
  389 + data + data_len,
  390 + 4096)) > 0) {
  391 + data_len += ret;
  392 + data = realloc(data, data_len + 4096);
  393 + }
  394 + } while (ret == -EAGAIN);
  395 + if (ret != 0) {
  396 + perror("read");
  397 + exit(1);
  398 + }
  399 + waitpid(pid, &ret ,0);
  400 + }
  401 + if (WIFEXITED(ret))
  402 + exitstatus |= WEXITSTATUS(ret);
  403 + else
  404 + exitstatus = 0xff;
  405 +
  406 + count = 0;
  407 + /* poor man's strtok, but with counting */
  408 + for (i = 0; i < data_len; i++) {
  409 + if (data[i] == '\n') {
  410 + count++;
  411 + data[i] = '\0';
  412 + }
  413 + }
  414 + start = all_list_len;
  415 + all_list_len += count;
  416 + all_list = realloc(all_list, sizeof(char *) * all_list_len);
  417 + str = data;
  418 + for (i = 0; i < data_len && start != all_list_len; i++) {
  419 + if (data[i] == '\0') {
  420 + all_list[start] = str;
  421 + str = data + i + 1;
  422 + start++;
  423 + }
  424 + }
  425 +}
  426 +
318 427 /*
319 428 * Parse file, calling action specific functions for:
320 429 * 1) Lines containing !E
... ... @@ -322,7 +431,8 @@
322 431 * 3) Lines containing !D
323 432 * 4) Lines containing !F
324 433 * 5) Lines containing !P
325   - * 6) Default lines - lines not matching the above
  434 + * 6) Lines containing !C
  435 + * 7) Default lines - lines not matching the above
326 436 */
327 437 static void parse_file(FILE *infile)
328 438 {
... ... @@ -365,6 +475,12 @@
365 475 s++;
366 476 docsection(line + 2, s);
367 477 break;
  478 + case 'C':
  479 + while (*s && !isspace(*s)) s++;
  480 + *s = '\0';
  481 + if (findall)
  482 + findall(line+2);
  483 + break;
368 484 default:
369 485 defaultline(line);
370 486 }
... ... @@ -380,6 +496,7 @@
380 496 int main(int argc, char *argv[])
381 497 {
382 498 FILE * infile;
  499 + int i;
383 500  
384 501 srctree = getenv("SRCTREE");
385 502 if (!srctree)
... ... @@ -415,6 +532,7 @@
415 532 symbolsonly = find_export_symbols;
416 533 singlefunctions = noaction2;
417 534 docsection = noaction2;
  535 + findall = find_all_symbols;
418 536 parse_file(infile);
419 537  
420 538 /* Rewind to start from beginning of file again */
421 539  
... ... @@ -425,8 +543,16 @@
425 543 symbolsonly = printline;
426 544 singlefunctions = singfunc;
427 545 docsection = docsect;
  546 + findall = NULL;
428 547  
429 548 parse_file(infile);
  549 +
  550 + for (i = 0; i < all_list_len; i++) {
  551 + if (!all_list[i])
  552 + continue;
  553 + fprintf(stderr, "Warning: didn't use docs for %s\n",
  554 + all_list[i]);
  555 + }
430 556 }
431 557 else if (strcmp("depend", argv[1]) == 0)
432 558 {
... ... @@ -439,6 +565,7 @@
439 565 symbolsonly = adddep;
440 566 singlefunctions = adddep2;
441 567 docsection = adddep2;
  568 + findall = adddep;
442 569 parse_file(infile);
443 570 printf("\n");
444 571 }
... ... @@ -44,12 +44,13 @@
44 44 # Note: This only supports 'c'.
45 45  
46 46 # usage:
47   -# kernel-doc [ -docbook | -html | -text | -man ] [ -no-doc-sections ]
  47 +# kernel-doc [ -docbook | -html | -text | -man | -list ] [ -no-doc-sections ]
48 48 # [ -function funcname [ -function funcname ...] ] c file(s)s > outputfile
49 49 # or
50 50 # [ -nofunction funcname [ -function funcname ...] ] c file(s)s > outputfile
51 51 #
52 52 # Set output format using one of -docbook -html -text or -man. Default is man.
  53 +# The -list format is for internal use by docproc.
53 54 #
54 55 # -no-doc-sections
55 56 # Do not output DOC: sections
56 57  
... ... @@ -210,9 +211,16 @@
210 211 $type_param, "\$1" );
211 212 my $blankline_text = "";
212 213  
  214 +# list mode
  215 +my %highlights_list = ( $type_constant, "\$1",
  216 + $type_func, "\$1",
  217 + $type_struct, "\$1",
  218 + $type_param, "\$1" );
  219 +my $blankline_list = "";
213 220  
214 221 sub usage {
215   - print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man ] [ -no-doc-sections ]\n";
  222 + print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man | -list ]\n";
  223 + print " [ -no-doc-sections ]\n";
216 224 print " [ -function funcname [ -function funcname ...] ]\n";
217 225 print " [ -nofunction funcname [ -nofunction funcname ...] ]\n";
218 226 print " c source file(s) > outputfile\n";
... ... @@ -318,6 +326,10 @@
318 326 $output_mode = "xml";
319 327 %highlights = %highlights_xml;
320 328 $blankline = $blankline_xml;
  329 + } elsif ($cmd eq "-list") {
  330 + $output_mode = "list";
  331 + %highlights = %highlights_list;
  332 + $blankline = $blankline_list;
321 333 } elsif ($cmd eq "-gnome") {
322 334 $output_mode = "gnome";
323 335 %highlights = %highlights_gnome;
... ... @@ -1358,6 +1370,42 @@
1358 1370 print " $section:\n";
1359 1371 print " -> ";
1360 1372 output_highlight($args{'sections'}{$section});
  1373 + }
  1374 +}
  1375 +
  1376 +## list mode output functions
  1377 +
  1378 +sub output_function_list(%) {
  1379 + my %args = %{$_[0]};
  1380 +
  1381 + print $args{'function'} . "\n";
  1382 +}
  1383 +
  1384 +# output enum in list
  1385 +sub output_enum_list(%) {
  1386 + my %args = %{$_[0]};
  1387 + print $args{'enum'} . "\n";
  1388 +}
  1389 +
  1390 +# output typedef in list
  1391 +sub output_typedef_list(%) {
  1392 + my %args = %{$_[0]};
  1393 + print $args{'typedef'} . "\n";
  1394 +}
  1395 +
  1396 +# output struct as list
  1397 +sub output_struct_list(%) {
  1398 + my %args = %{$_[0]};
  1399 +
  1400 + print $args{'struct'} . "\n";
  1401 +}
  1402 +
  1403 +sub output_blockhead_list(%) {
  1404 + my %args = %{$_[0]};
  1405 + my ($parameter, $section);
  1406 +
  1407 + foreach $section (@{$args{'sectionlist'}}) {
  1408 + print "DOC: $section\n";
1361 1409 }
1362 1410 }
1363 1411