Skip to content

Commit eda603f

Browse files
jmberg-inteltorvalds
authored andcommitted
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>
1 parent 1f3a668 commit eda603f

File tree

3 files changed

+183
-3
lines changed

3 files changed

+183
-3
lines changed

Documentation/kernel-doc-nano-HOWTO.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,5 +345,10 @@ documentation, in <filename>, for the functions listed.
345345
section titled <section title> from <filename>.
346346
Spaces are allowed in <section title>; do not quote the <section title>.
347347

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+
348353
Tim.
349354
*/ <twaugh@redhat.com>

scripts/basic/docproc.c

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@
3434
*
3535
*/
3636

37+
#define _GNU_SOURCE
3738
#include <stdio.h>
3839
#include <stdlib.h>
3940
#include <string.h>
4041
#include <ctype.h>
4142
#include <unistd.h>
4243
#include <limits.h>
44+
#include <errno.h>
4345
#include <sys/types.h>
4446
#include <sys/wait.h>
4547

@@ -54,6 +56,7 @@ typedef void FILEONLY(char * file);
5456
FILEONLY *internalfunctions;
5557
FILEONLY *externalfunctions;
5658
FILEONLY *symbolsonly;
59+
FILEONLY *findall;
5760

5861
typedef void FILELINE(char * file, char * line);
5962
FILELINE * singlefunctions;
@@ -65,12 +68,30 @@ FILELINE * docsection;
6568
#define KERNELDOCPATH "scripts/"
6669
#define KERNELDOC "kernel-doc"
6770
#define DOCBOOK "-docbook"
71+
#define LIST "-list"
6872
#define FUNCTION "-function"
6973
#define NOFUNCTION "-nofunction"
7074
#define NODOCSECTIONS "-no-doc-sections"
7175

7276
static char *srctree, *kernsrctree;
7377

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+
7495
static void usage (void)
7596
{
7697
fprintf(stderr, "Usage: docproc {doc|depend} file\n");
@@ -248,6 +269,7 @@ static void docfunctions(char * filename, char * type)
248269
struct symfile * sym = &symfilelist[i];
249270
for (j=0; j < sym->symbolcnt; j++) {
250271
vec[idx++] = type;
272+
consume_symbol(sym->symbollist[j].name);
251273
vec[idx++] = sym->symbollist[j].name;
252274
}
253275
}
@@ -287,6 +309,11 @@ static void singfunc(char * filename, char * line)
287309
vec[idx++] = &line[i];
288310
}
289311
}
312+
for (i = 0; i < idx; i++) {
313+
if (strcmp(vec[i], FUNCTION))
314+
continue;
315+
consume_symbol(vec[i + 1]);
316+
}
290317
vec[idx++] = filename;
291318
vec[idx] = NULL;
292319
exec_kernel_doc(vec);
@@ -306,6 +333,10 @@ static void docsect(char *filename, char *line)
306333
if (*s == '\n')
307334
*s = '\0';
308335

336+
asprintf(&s, "DOC: %s", line);
337+
consume_symbol(s);
338+
free(s);
339+
309340
vec[0] = KERNELDOC;
310341
vec[1] = DOCBOOK;
311342
vec[2] = FUNCTION;
@@ -315,14 +346,93 @@ static void docsect(char *filename, char *line)
315346
exec_kernel_doc(vec);
316347
}
317348

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+
318427
/*
319428
* Parse file, calling action specific functions for:
320429
* 1) Lines containing !E
321430
* 2) Lines containing !I
322431
* 3) Lines containing !D
323432
* 4) Lines containing !F
324433
* 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
326436
*/
327437
static void parse_file(FILE *infile)
328438
{
@@ -365,6 +475,12 @@ static void parse_file(FILE *infile)
365475
s++;
366476
docsection(line + 2, s);
367477
break;
478+
case 'C':
479+
while (*s && !isspace(*s)) s++;
480+
*s = '\0';
481+
if (findall)
482+
findall(line+2);
483+
break;
368484
default:
369485
defaultline(line);
370486
}
@@ -380,6 +496,7 @@ static void parse_file(FILE *infile)
380496
int main(int argc, char *argv[])
381497
{
382498
FILE * infile;
499+
int i;
383500

384501
srctree = getenv("SRCTREE");
385502
if (!srctree)
@@ -415,6 +532,7 @@ int main(int argc, char *argv[])
415532
symbolsonly = find_export_symbols;
416533
singlefunctions = noaction2;
417534
docsection = noaction2;
535+
findall = find_all_symbols;
418536
parse_file(infile);
419537

420538
/* Rewind to start from beginning of file again */
@@ -425,8 +543,16 @@ int main(int argc, char *argv[])
425543
symbolsonly = printline;
426544
singlefunctions = singfunc;
427545
docsection = docsect;
546+
findall = NULL;
428547

429548
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+
}
430556
}
431557
else if (strcmp("depend", argv[1]) == 0)
432558
{
@@ -439,6 +565,7 @@ int main(int argc, char *argv[])
439565
symbolsonly = adddep;
440566
singlefunctions = adddep2;
441567
docsection = adddep2;
568+
findall = adddep;
442569
parse_file(infile);
443570
printf("\n");
444571
}

scripts/kernel-doc

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,13 @@ use strict;
4444
# Note: This only supports 'c'.
4545

4646
# usage:
47-
# kernel-doc [ -docbook | -html | -text | -man ] [ -no-doc-sections ]
47+
# kernel-doc [ -docbook | -html | -text | -man | -list ] [ -no-doc-sections ]
4848
# [ -function funcname [ -function funcname ...] ] c file(s)s > outputfile
4949
# or
5050
# [ -nofunction funcname [ -function funcname ...] ] c file(s)s > outputfile
5151
#
5252
# Set output format using one of -docbook -html -text or -man. Default is man.
53+
# The -list format is for internal use by docproc.
5354
#
5455
# -no-doc-sections
5556
# Do not output DOC: sections
@@ -210,9 +211,16 @@ my %highlights_text = ( $type_constant, "\$1",
210211
$type_param, "\$1" );
211212
my $blankline_text = "";
212213

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 = "";
213220

214221
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";
216224
print " [ -function funcname [ -function funcname ...] ]\n";
217225
print " [ -nofunction funcname [ -nofunction funcname ...] ]\n";
218226
print " c source file(s) > outputfile\n";
@@ -318,6 +326,10 @@ while ($ARGV[0] =~ m/^-(.*)/) {
318326
$output_mode = "xml";
319327
%highlights = %highlights_xml;
320328
$blankline = $blankline_xml;
329+
} elsif ($cmd eq "-list") {
330+
$output_mode = "list";
331+
%highlights = %highlights_list;
332+
$blankline = $blankline_list;
321333
} elsif ($cmd eq "-gnome") {
322334
$output_mode = "gnome";
323335
%highlights = %highlights_gnome;
@@ -1361,6 +1373,42 @@ sub output_blockhead_text(%) {
13611373
}
13621374
}
13631375

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";
1409+
}
1410+
}
1411+
13641412
##
13651413
# generic output function for all types (function, struct/union, typedef, enum);
13661414
# calls the generated, variable output_ function name based on

0 commit comments

Comments
 (0)