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

scripts: kernel-doc: improve nested logic to handle multiple identifiers

It is possible to use nested structs like:

struct {
struct {
void *arg1;
} st1, st2, *st3, st4;
};

Handling it requires to split each parameter. Change the logic
to allow such definitions.

In order to test the new nested logic, the following file
was used to test

<code>
struct foo { int a; }; /* Just to avoid errors if compiled */

/**
* struct my_struct - a struct with nested unions and structs
* @arg1: first argument of anonymous union/anonymous struct
* @arg2: second argument of anonymous union/anonymous struct
* @arg1b: first argument of anonymous union/anonymous struct
* @arg2b: second argument of anonymous union/anonymous struct
* @arg3: third argument of anonymous union/anonymous struct
* @arg4: fourth argument of anonymous union/anonymous struct
* @bar.st1.arg1: first argument of struct st1 on union bar
* @bar.st1.arg2: second argument of struct st1 on union bar
* @bar.st1.bar1: bar1 at st1
* @bar.st1.bar2: bar2 at st1
* @bar.st2.arg1: first argument of struct st2 on union bar
* @bar.st2.arg2: second argument of struct st2 on union bar
* @bar.st3.arg2: second argument of struct st3 on union bar
* @f1: nested function on anonimous union/struct
* @bar.st2.f2: nested function on named union/struct
*/
struct my_struct {
/* Anonymous union/struct*/
union {
struct {
char arg1 : 1;
char arg2 : 3;
};
struct {
int arg1b;
int arg2b;
};
struct {
void *arg3;
int arg4;
int (*f1)(char foo, int bar);
};
};
union {
struct {
int arg1;
int arg2;
struct foo bar1, *bar2;
} st1; /* bar.st1 is undocumented, cause a warning */
struct {
void *arg1; /* bar.st3.arg1 is undocumented, cause a warning */
int arg2;
int (*f2)(char foo, int bar); /* bar.st3.fn2 is undocumented, cause a warning */
} st2, st3, *st4;
int (*f3)(char foo, int bar); /* f3 is undocumented, cause a warning */
} bar; /* bar is undocumented, cause a warning */

/* private: */
int undoc_privat; /* is undocumented but private, no warning */

/* public: */
int undoc_public; /* is undocumented, cause a warning */
};
</code>

It produces the following warnings, as expected:

test2.h:57: warning: Function parameter or member 'bar' not described in 'my_struct'
test2.h:57: warning: Function parameter or member 'bar.st1' not described in 'my_struct'
test2.h:57: warning: Function parameter or member 'bar.st2' not described in 'my_struct'
test2.h:57: warning: Function parameter or member 'bar.st3' not described in 'my_struct'
test2.h:57: warning: Function parameter or member 'bar.st3.arg1' not described in 'my_struct'
test2.h:57: warning: Function parameter or member 'bar.st3.f2' not described in 'my_struct'
test2.h:57: warning: Function parameter or member 'bar.st4' not described in 'my_struct'
test2.h:57: warning: Function parameter or member 'bar.st4.arg1' not described in 'my_struct'
test2.h:57: warning: Function parameter or member 'bar.st4.arg2' not described in 'my_struct'
test2.h:57: warning: Function parameter or member 'bar.st4.f2' not described in 'my_struct'
test2.h:57: warning: Function parameter or member 'bar.f3' not described in 'my_struct'
test2.h:57: warning: Function parameter or member 'undoc_public' not described in 'my_struct'

Suggested-by: Markus Heiser <markus.heiser@darmarit.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Signed-off-by: Jonathan Corbet <corbet@lwn.net>

authored by

Mauro Carvalho Chehab and committed by
Jonathan Corbet
84ce5b98 7c0d7e87

+44 -25
+44 -25
scripts/kernel-doc
··· 1030 1030 my $declaration = $members; 1031 1031 1032 1032 # Split nested struct/union elements as newer ones 1033 - my $cont = 1; 1034 - while ($cont) { 1035 - $cont = 0; 1036 - while ($members =~ m/(struct|union)([^{};]+){([^{}]*)}([^{}\;]*)\;/) { 1037 - my $newmember = "$1 $4;"; 1038 - my $id = $4; 1039 - my $content = $3; 1033 + while ($members =~ m/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/) { 1034 + my $newmember; 1035 + my $maintype = $1; 1036 + my $ids = $4; 1037 + my $content = $3; 1038 + foreach my $id(split /,/, $ids) { 1039 + $newmember .= "$maintype $id; "; 1040 + 1040 1041 $id =~ s/[:\[].*//; 1041 - $id =~ s/^\*+//; 1042 + $id =~ s/^\s*\**(\S+)\s*/$1/; 1042 1043 foreach my $arg (split /;/, $content) { 1043 1044 next if ($arg =~ m/^\s*$/); 1044 1045 if ($arg =~ m/^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)/) { ··· 1050 1049 next if (!$name); 1051 1050 if ($id =~ m/^\s*$/) { 1052 1051 # anonymous struct/union 1053 - $newmember .= "$type$name$extra;"; 1052 + $newmember .= "$type$name$extra; "; 1054 1053 } else { 1055 - $newmember .= "$type$id.$name$extra;"; 1054 + $newmember .= "$type$id.$name$extra; "; 1056 1055 } 1057 1056 } else { 1058 - my $type = $arg; 1059 - my $name = $arg; 1060 - $type =~ s/\s\S+$//; 1061 - $name =~ s/.*\s+//; 1062 - $name =~ s/[:\[].*//; 1063 - $name =~ s/^\*+//; 1064 - next if (($name =~ m/^\s*$/)); 1065 - if ($id =~ m/^\s*$/) { 1066 - # anonymous struct/union 1067 - $newmember .= "$type $name;"; 1057 + my $type; 1058 + my $names; 1059 + $arg =~ s/^\s+//; 1060 + $arg =~ s/\s+$//; 1061 + # Handle bitmaps 1062 + $arg =~ s/:\s*\d+\s*//g; 1063 + # Handle arrays 1064 + $arg =~ s/\[\S+\]//g; 1065 + # The type may have multiple words, 1066 + # and multiple IDs can be defined, like: 1067 + # const struct foo, *bar, foobar 1068 + # So, we remove spaces when parsing the 1069 + # names, in order to match just names 1070 + # and commas for the names 1071 + $arg =~ s/\s*,\s*/,/g; 1072 + if ($arg =~ m/(.*)\s+([\S+,]+)/) { 1073 + $type = $1; 1074 + $names = $2; 1068 1075 } else { 1069 - $newmember .= "$type $id.$name;"; 1076 + $newmember .= "$arg; "; 1077 + next; 1078 + } 1079 + foreach my $name (split /,/, $names) { 1080 + $name =~ s/^\s*\**(\S+)\s*/$1/; 1081 + next if (($name =~ m/^\s*$/)); 1082 + if ($id =~ m/^\s*$/) { 1083 + # anonymous struct/union 1084 + $newmember .= "$type $name; "; 1085 + } else { 1086 + $newmember .= "$type $id.$name; "; 1087 + } 1070 1088 } 1071 1089 } 1072 1090 } 1073 - $members =~ s/(struct|union)([^{};]+){([^{}]*)}([^{}\;]*)\;/$newmember/; 1074 - $cont = 1; 1075 - }; 1076 - }; 1091 + } 1092 + $members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)}([^\{\}\;]*)\;/$newmember/; 1093 + } 1077 1094 1078 1095 # Ignore other nested elements, like enums 1079 1096 $members =~ s/({[^\{\}]*})//g;