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'
Showing the changes to scripts/kernel-doc (1 of 1 file). Show all
Unified · Split
| @@ -1030,15 +1030,16 @@ sub dump_struct($$) { · 1029 unmodified lines | ||
| 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*\).*)/) { |
| @@ -1049,30 +1050,48 @@ sub dump_struct($$) { · 4 unmodified lines | ||
| 1049 | 1050 | next if (!$name); |
| 1050 | 1051 | if ($id =~ m/^\s*$/) { |
| 1051 | 1052 | # anonymous struct/union |
| 1052 | − $newmember .= "$type$name$extra;"; | |
| 1053 | + $newmember .= "$type$name$extra; "; | |
| 1053 | 1054 | } else { |
| 1054 | − $newmember .= "$type$id.$name$extra;"; | |
| 1055 | + $newmember .= "$type$id.$name$extra; "; | |
| 1055 | 1056 | } |
| 1056 | 1057 | } else { |
| 1057 | − my $type = $arg; | |
| 1058 | − my $name = $arg; | |
| 1059 | − $type =~ s/\s\S+$//; | |
| 1060 | − $name =~ s/.*\s+//; | |
| 1061 | − $name =~ s/[:\[].*//; | |
| 1062 | − $name =~ s/^\*+//; | |
| 1063 | − next if (($name =~ m/^\s*$/)); | |
| 1064 | − if ($id =~ m/^\s*$/) { | |
| 1065 | − # anonymous struct/union | |
| 1066 | − $newmember .= "$type $name;"; | |
| 1058 | + my $type; | |
| 1059 | + my $names; | |
| 1060 | + $arg =~ s/^\s+//; | |
| 1061 | + $arg =~ s/\s+$//; | |
| 1062 | + # Handle bitmaps | |
| 1063 | + $arg =~ s/:\s*\d+\s*//g; | |
| 1064 | + # Handle arrays | |
| 1065 | + $arg =~ s/\[\S+\]//g; | |
| 1066 | + # The type may have multiple words, | |
| 1067 | + # and multiple IDs can be defined, like: | |
| 1068 | + # const struct foo, *bar, foobar | |
| 1069 | + # So, we remove spaces when parsing the | |
| 1070 | + # names, in order to match just names | |
| 1071 | + # and commas for the names | |
| 1072 | + $arg =~ s/\s*,\s*/,/g; | |
| 1073 | + if ($arg =~ m/(.*)\s+([\S+,]+)/) { | |
| 1074 | + $type = $1; | |
| 1075 | + $names = $2; | |
| 1067 | 1076 | } else { |
| 1068 | − $newmember .= "$type $id.$name;"; | |
| 1077 | + $newmember .= "$arg; "; | |
| 1078 | + next; | |
| 1079 | + } | |
| 1080 | + foreach my $name (split /,/, $names) { | |
| 1081 | + $name =~ s/^\s*\**(\S+)\s*/$1/; | |
| 1082 | + next if (($name =~ m/^\s*$/)); | |
| 1083 | + if ($id =~ m/^\s*$/) { | |
| 1084 | + # anonymous struct/union | |
| 1085 | + $newmember .= "$type $name; "; | |
| 1086 | + } else { | |
| 1087 | + $newmember .= "$type $id.$name; "; | |
| 1088 | + } | |
| 1069 | 1089 | } |
| 1070 | 1090 | } |
| 1071 | 1091 | } |
| 1072 | − $members =~ s/(struct|union)([^{};]+){([^{}]*)}([^{}\;]*)\;/$newmember/; | |
| 1073 | − $cont = 1; | |
| 1074 | − }; | |
| 1075 | − }; | |
| 1092 | + } | |
| 1093 | + $members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)}([^\{\}\;]*)\;/$newmember/; | |
| 1094 | + } | |
| 1076 | 1095 | |
| 1077 | 1096 | # Ignore other nested elements, like enums |
| 1078 | 1097 | $members =~ s/({[^\{\}]*})//g; |