Skip to content

Commit 8ad7216

Browse files
mchehabJonathan Corbet
authored andcommitted
scripts: kernel-doc: parse next structs/unions
There are several places within the Kernel tree with nested structs/unions, like this one: struct ingenic_cgu_clk_info { const char *name; enum { CGU_CLK_NONE = 0, CGU_CLK_EXT = BIT(0), CGU_CLK_PLL = BIT(1), CGU_CLK_GATE = BIT(2), CGU_CLK_MUX = BIT(3), CGU_CLK_MUX_GLITCHFREE = BIT(4), CGU_CLK_DIV = BIT(5), CGU_CLK_FIXDIV = BIT(6), CGU_CLK_CUSTOM = BIT(7), } type; int parents[4]; union { struct ingenic_cgu_pll_info pll; struct { struct ingenic_cgu_gate_info gate; struct ingenic_cgu_mux_info mux; struct ingenic_cgu_div_info div; struct ingenic_cgu_fixdiv_info fixdiv; }; struct ingenic_cgu_custom_info custom; }; }; Currently, such struct is documented as: **Definition** :: struct ingenic_cgu_clk_info { const char * name; }; **Members** ``name`` name of the clock With is obvioulsy wrong. It also generates an error: drivers/clk/ingenic/cgu.h:169: warning: No description found for parameter 'enum' However, there's nothing wrong with this kernel-doc markup: everything is documented there. It makes sense to document all fields there. So, add a way for the core to parse those structs. With this patch, all documented fields will properly generate documentation. Signed-off-by: Mauro Carvalho Chehab <[email protected]> Signed-off-by: Jonathan Corbet <[email protected]>
1 parent 7c9aa01 commit 8ad7216

File tree

2 files changed

+114
-53
lines changed

2 files changed

+114
-53
lines changed

Documentation/doc-guide/kernel-doc.rst

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,52 @@ comment block.
281281
The kernel-doc data structure comments describe each member of the structure,
282282
in order, with the member descriptions.
283283

284+
Nested structs/unions
285+
~~~~~~~~~~~~~~~~~~~~~
286+
287+
It is possible to document nested structs unions, like::
288+
289+
/**
290+
* struct nested_foobar - a struct with nested unions and structs
291+
* @arg1: - first argument of anonymous union/anonymous struct
292+
* @arg2: - second argument of anonymous union/anonymous struct
293+
* @arg3: - third argument of anonymous union/anonymous struct
294+
* @arg4: - fourth argument of anonymous union/anonymous struct
295+
* @bar.st1.arg1 - first argument of struct st1 on union bar
296+
* @bar.st1.arg2 - second argument of struct st1 on union bar
297+
* @bar.st2.arg1 - first argument of struct st2 on union bar
298+
* @bar.st2.arg2 - second argument of struct st2 on union bar
299+
struct nested_foobar {
300+
/* Anonymous union/struct*/
301+
union {
302+
struct {
303+
int arg1;
304+
int arg2;
305+
}
306+
struct {
307+
void *arg3;
308+
int arg4;
309+
}
310+
}
311+
union {
312+
struct {
313+
int arg1;
314+
int arg2;
315+
} st1;
316+
struct {
317+
void *arg1;
318+
int arg2;
319+
} st2;
320+
} bar;
321+
};
322+
323+
.. note::
324+
325+
#) When documenting nested structs or unions, if the struct/union ``foo``
326+
is named, the argument ``bar`` inside it should be documented as
327+
``@foo.bar:``
328+
#) When the nested struct/union is anonymous, the argument ``bar`` on it
329+
should be documented as ``@bar:``
284330

285331
Typedef documentation
286332
---------------------

scripts/kernel-doc

Lines changed: 68 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ my $anon_struct_union = 0;
211211
my $type_constant = '\b``([^\`]+)``\b';
212212
my $type_constant2 = '\%([-_\w]+)';
213213
my $type_func = '(\w+)\(\)';
214-
my $type_param = '\@(\w+(\.\.\.)?)';
214+
my $type_param = '\@(\w*(\.\w+)*(\.\.\.)?)';
215215
my $type_fp_param = '\@(\w+)\(\)'; # Special RST handling for func ptr params
216216
my $type_env = '(\$\w+)';
217217
my $type_enum = '\&(enum\s*([_\w]+))';
@@ -670,32 +670,12 @@ sub output_struct_man(%) {
670670
print ".SH NAME\n";
671671
print $args{'type'} . " " . $args{'struct'} . " \\- " . $args{'purpose'} . "\n";
672672

673+
my $declaration = $args{'definition'};
674+
$declaration =~ s/\t/ /g;
675+
$declaration =~ s/\n/"\n.br\n.BI \"/g;
673676
print ".SH SYNOPSIS\n";
674677
print $args{'type'} . " " . $args{'struct'} . " {\n.br\n";
675-
676-
foreach my $parameter (@{$args{'parameterlist'}}) {
677-
if ($parameter =~ /^#/) {
678-
print ".BI \"$parameter\"\n.br\n";
679-
next;
680-
}
681-
my $parameter_name = $parameter;
682-
$parameter_name =~ s/\[.*//;
683-
684-
($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
685-
$type = $args{'parametertypes'}{$parameter};
686-
if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
687-
# pointer-to-function
688-
print ".BI \" " . $1 . "\" " . $parameter . " \") (" . $2 . ")" . "\"\n;\n";
689-
} elsif ($type =~ m/^(.*?)\s*(:.*)/) {
690-
# bitfield
691-
print ".BI \" " . $1 . "\ \" " . $parameter . $2 . " \"" . "\"\n;\n";
692-
} else {
693-
$type =~ s/([^\*])$/$1 /;
694-
print ".BI \" " . $type . "\" " . $parameter . " \"" . "\"\n;\n";
695-
}
696-
print "\n.br\n";
697-
}
698-
print "};\n.br\n";
678+
print ".BI \"$declaration\n};\n.br\n\n";
699679

700680
print ".SH Members\n";
701681
foreach $parameter (@{$args{'parameterlist'}}) {
@@ -933,29 +913,9 @@ sub output_struct_rst(%) {
933913

934914
print "**Definition**\n\n";
935915
print "::\n\n";
936-
print " " . $args{'type'} . " " . $args{'struct'} . " {\n";
937-
foreach $parameter (@{$args{'parameterlist'}}) {
938-
if ($parameter =~ /^#/) {
939-
print " " . "$parameter\n";
940-
next;
941-
}
942-
943-
my $parameter_name = $parameter;
944-
$parameter_name =~ s/\[.*//;
945-
946-
($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
947-
$type = $args{'parametertypes'}{$parameter};
948-
if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
949-
# pointer-to-function
950-
print " $1 $parameter) ($2);\n";
951-
} elsif ($type =~ m/^(.*?)\s*(:.*)/) {
952-
# bitfield
953-
print " $1 $parameter$2;\n";
954-
} else {
955-
print " " . $type . " " . $parameter . ";\n";
956-
}
957-
}
958-
print " };\n\n";
916+
my $declaration = $args{'definition'};
917+
$declaration =~ s/\t/ /g;
918+
print " " . $args{'type'} . " " . $args{'struct'} . " {\n$declaration };\n\n";
959919

960920
print "**Members**\n\n";
961921
$lineprefix = " ";
@@ -1050,16 +1010,11 @@ sub dump_struct($$) {
10501010
$declaration_name = $2;
10511011
my $members = $3;
10521012

1053-
# ignore embedded structs or unions
1054-
$members =~ s/({.*})//g;
1055-
$nested = $1;
1056-
10571013
# ignore members marked private:
10581014
$members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gosi;
10591015
$members =~ s/\/\*\s*private:.*//gosi;
10601016
# strip comments:
10611017
$members =~ s/\/\*.*?\*\///gos;
1062-
$nested =~ s/\/\*.*?\*\///gos;
10631018
# strip attributes
10641019
$members =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i;
10651020
$members =~ s/__aligned\s*\([^;]*\)//gos;
@@ -1073,13 +1028,73 @@ sub dump_struct($$) {
10731028
# replace DECLARE_KFIFO_PTR
10741029
$members =~ s/DECLARE_KFIFO_PTR\s*\(([^,)]+),\s*([^,)]+)\)/$2 \*$1/gos;
10751030

1031+
my $declaration = $members;
1032+
1033+
# Split nested struct/union elements as newer ones
1034+
my $cont = 1;
1035+
while ($cont) {
1036+
$cont = 0;
1037+
while ($members =~ m/(struct|union)([^{};]+){([^{}]*)}([^{}\;]*)\;/) {
1038+
my $newmember = "$1 $4;";
1039+
my $id = $4;
1040+
my $content = $3;
1041+
$id =~ s/[:\[].*//;
1042+
$id =~ s/^\*+//;
1043+
foreach my $arg (split /;/, $content) {
1044+
next if ($arg =~ m/^\s*$/);
1045+
my $type = $arg;
1046+
my $name = $arg;
1047+
$type =~ s/\s\S+$//;
1048+
$name =~ s/.*\s//;
1049+
$name =~ s/[:\[].*//;
1050+
$name =~ s/^\*+//;
1051+
next if (($name =~ m/^\s*$/));
1052+
if ($id =~ m/^\s*$/) {
1053+
# anonymous struct/union
1054+
$newmember .= "$type $name;";
1055+
} else {
1056+
$newmember .= "$type $id.$name;";
1057+
}
1058+
}
1059+
$members =~ s/(struct|union)([^{};]+){([^{}]*)}([^{}\;]*)\;/$newmember/;
1060+
$cont = 1;
1061+
};
1062+
};
1063+
1064+
# Ignore other nested elements, like enums
1065+
$members =~ s/({[^\{\}]*})//g;
1066+
$nested = $decl_type;
1067+
$nested =~ s/\/\*.*?\*\///gos;
1068+
10761069
create_parameterlist($members, ';', $file);
10771070
check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual, $nested);
10781071

1072+
# Adjust declaration for better display
1073+
$declaration =~ s/([{;])/$1\n/g;
1074+
$declaration =~ s/}\s+;/};/g;
1075+
# Better handle inlined enums
1076+
do {} while ($declaration =~ s/(enum\s+{[^}]+),([^\n])/$1,\n$2/);
1077+
1078+
my @def_args = split /\n/, $declaration;
1079+
my $level = 1;
1080+
$declaration = "";
1081+
foreach my $clause (@def_args) {
1082+
$clause =~ s/^\s+//;
1083+
$clause =~ s/\s+$//;
1084+
$clause =~ s/\s+/ /;
1085+
next if (!$clause);
1086+
$level-- if ($clause =~ m/(})/ && $level > 1);
1087+
if (!($clause =~ m/^\s*#/)) {
1088+
$declaration .= "\t" x $level;
1089+
}
1090+
$declaration .= "\t" . $clause . "\n";
1091+
$level++ if ($clause =~ m/({)/ && !($clause =~m/}/));
1092+
}
10791093
output_declaration($declaration_name,
10801094
'struct',
10811095
{'struct' => $declaration_name,
10821096
'module' => $modulename,
1097+
'definition' => $declaration,
10831098
'parameterlist' => \@parameterlist,
10841099
'parameterdescs' => \%parameterdescs,
10851100
'parametertypes' => \%parametertypes,

0 commit comments

Comments
 (0)