Skip to content

Commit

Permalink
kernel-doc: fix nested & sub-nested handling (continued)
Browse files Browse the repository at this point in the history
This is the second patch improving the handling of nested & sub-nested
data type handling. With nested arguments are no longer ignored. The
patch allows to add documentation for such nested data types.

https://www.mail-archive.com/linux-doc@vger.kernel.org/msg15357.html

The origin comes from Mauro Carvalho Chehab [1] patching the Perl kernel-doc
parser in './scripts' folder of the Linux source tree. This patch here is a bit
more elaborated (see discussion at [1]).

[1] https://www.mail-archive.com/linux-doc@vger.kernel.org/msg15357.html

Reported-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
  • Loading branch information
return42 committed Sep 25, 2017
1 parent 8d9394a commit 518b4ef
Showing 1 changed file with 39 additions and 63 deletions.
102 changes: 39 additions & 63 deletions linuxdoc/kernel_doc.py
Expand Up @@ -630,6 +630,7 @@ def output_struct_decl(
, parametertypes = None # ctx.parametertypes
, sections = None # ctx.sections
, purpose = None # ctx.decl_purpose
, definition = None # ctx.definition
, ):
raise NotImplementedError

Expand Down Expand Up @@ -1010,6 +1011,7 @@ def output_struct_decl(
, parametertypes = None # ctx.parametertypes
, sections = None # ctx.sections
, purpose = None # ctx.decl_purpose
, definition = None # ctx.definition
, ):
self.parser.ctx.offset = self.parser.ctx.decl_offset
self.write_anchor(decl_name)
Expand All @@ -1034,32 +1036,20 @@ def output_struct_decl(
self.write("\n.. code-block:: c\n\n")
self.write(self.INDENT, decl_type, " ", decl_name, " {\n")

for p_name in parameterlist:
p_type = parametertypes[p_name]

if MACRO.match(p_name):
self.write(self.INDENT, "%s\n" % p_name)

elif self.FUNC_PTR.search(p_type):
# pointer to function
self.write(
self.INDENT * 2
, "%s%s)(%s);\n" % (self.FUNC_PTR[0], p_name, self.FUNC_PTR[1]))

elif self.BITFIELD.match(p_type):
self.write(
self.INDENT * 2
, "%s %s%s;\n" % (self.BITFIELD[0], p_name, self.BITFIELD[1]))
elif p_type.endswith("*"):
# pointer
self.write(
self.INDENT * 2
, "%s%s;\n" % (p_type, p_name))

definition = re.sub(r"(([{;]))", r"\1\n", definition)
level = 2
for clause in definition.split('\n'):
clause = normalize_ws(clause)
if not clause:
continue
if clause[0] == "}" and level > 2:
level -= 1
if MACRO.match(clause):
self.write(self.INDENT, clause[:-1].strip(), '\n')
else:
self.write(
self.INDENT * 2
, "%s %s;\n" % (p_type, p_name))
self.write(self.INDENT * level, clause, '\n')
if clause[-1] == "{":
level += 1

self.write(self.INDENT, "}\n")

Expand Down Expand Up @@ -2188,7 +2178,7 @@ def process_state3_type(self, line):

if MACRO.match(line):
# To distinguish preprocessor directive from regular declaration
# later.
# later (drop-semicolon).
line += ";"

m = RE(r"([^{};]*)([{};])(.*)")
Expand Down Expand Up @@ -2388,7 +2378,7 @@ def dump_function(self, proto):
, self.ctx.decl_type
, self.ctx.sectcheck
, self.ctx.parameterlist
, "")
)
if hasRetVal:
self.check_return_section(self.ctx.decl_name, self.ctx.return_type)

Expand Down Expand Up @@ -2426,7 +2416,8 @@ def dump_union(self, proto):
, parameterdescs = self.ctx.parameterdescs
, parametertypes = self.ctx.parametertypes
, sections = self.ctx.sections
, purpose = self.ctx.decl_purpose )
, purpose = self.ctx.decl_purpose
, definition = self.ctx.definition )

def dump_struct(self, proto):

Expand All @@ -2447,14 +2438,14 @@ def dump_struct(self, proto):
, parameterdescs = self.ctx.parameterdescs
, parametertypes = self.ctx.parametertypes
, sections = self.ctx.sections
, purpose = self.ctx.decl_purpose )
, purpose = self.ctx.decl_purpose
, definition = self.ctx.definition)

def prepare_struct_union(self, proto):
self.debug("prepare_struct_union(): '%(proto)s'", proto=proto)

retVal = False
members = ""
nested = ""

if C_STRUCT_UNION.match(proto):

Expand All @@ -2464,32 +2455,14 @@ def prepare_struct_union(self, proto):
% (C_STRUCT_UNION[0], self.ctx.decl_type, proto))
return False


self.ctx.decl_name = C_STRUCT_UNION[1]
members = C_STRUCT_UNION[2]

if "{" in members:
# ignore embedded structs or unions
m = members
members = ""
c = 0
for x in m:
if x == "{":
c += 1
if c == 0:
members += x
else:
nested += x
if x == "}":
c -= 1
self.ctx.definition = members = C89_comments.sub("", C_STRUCT_UNION[2])

# ignore members marked private:
members = re.sub(r"/\*\s*private:.*?/\*\s*public:.*?\*/", "", members, flags=re.I)
members = re.sub(r"/\*\s*private:.*", "", members, flags=re.I)

# strip comments:
members = C89_comments.sub("", members)
nested = C89_comments.sub("", nested)

# strip kmemcheck_bitfield_{begin,end}.*;
members = re.sub(r"kmemcheck_bitfield_.*?;", "", members)

Expand All @@ -2508,12 +2481,19 @@ def prepare_struct_union(self, proto):
, r"unsigned long \1[1 << ((\2) - 1)]"
, members )

# Split nested struct/union elements as newer ones
NESTED = RE(r"(struct|union)\s+{([^{}]*)}(\s*[^\s;]\s*)")
while NESTED.search(members):
members = NESTED.sub(r'\1 \3 \2 ', members)

# ignore other nested elements, like enums
members = re.sub(r"({[^\{\}]*})", '', members)
self.create_parameterlist(members, ';')
self.check_sections(self.ctx.decl_name
, self.ctx.decl_type
, self.ctx.sectcheck
, self.ctx.parameterlist # self.ctx.struct_actual.split(" ")
, nested)
)
retVal = True

else:
Expand Down Expand Up @@ -2557,8 +2537,7 @@ def dump_enum(self, proto):
self.check_sections(self.ctx.decl_name
, self.ctx.decl_type
, self.ctx.sectcheck
, self.ctx.parameterlist
, "")
, self.ctx.parameterlist )

self.output_decl(
self.ctx.decl_name, "enum_decl"
Expand Down Expand Up @@ -2601,8 +2580,7 @@ def dump_typedef(self, proto):
self.check_sections(self.ctx.decl_name
, self.ctx.decl_type
, self.ctx.sectcheck
, self.ctx.parameterlist
, "")
, self.ctx.parameterlist )
self.output_decl(
self.ctx.decl_name, "function_decl"
, function = self.ctx.decl_name
Expand Down Expand Up @@ -2634,8 +2612,7 @@ def dump_typedef(self, proto):
self.check_sections(self.ctx.decl_name
, self.ctx.decl_type
, self.ctx.sectcheck
, self.ctx.parameterlist
, "")
, self.ctx.parameterlist )
self.output_decl(
self.ctx.decl_name, "typedef_decl"
, typedef = self.ctx.decl_name
Expand All @@ -2661,7 +2638,6 @@ def create_parameterlist(self, parameter, splitchar):

self.debug("create_parameterlist(): params='%(y)s'", y=parameter)
for c, p in enumerate(parameter.split(splitchar)):

p = C99_comments.sub("", p)
p = p.strip()

Expand Down Expand Up @@ -2772,7 +2748,7 @@ def push_parameter(self, p_name, p_type):
# handle unnamed (anonymous) union or struct:
p_type = p_name
p_name = "{unnamed_" + p_name + "}"
self.ctx.parameterdescs[p_name] = "anonymous\n"
self.ctx.parameterdescs[p_name] = "anonymous"
self.anon_struct_union = True

self.debug(
Expand Down Expand Up @@ -2826,10 +2802,10 @@ def push_parameter(self, p_name, p_type):


def check_sections(self, decl_name, decl_type
, sectcheck, parameterlist, nested):
, sectcheck, parameterlist):
self.debug("check_sections(): decl_name='%(n)s' / decl_type='%(t)s' /"
" sectcheck=%(sc)s / parameterlist=%(pl)s / nested='%(nested)s'"
, n=decl_name, t=decl_type, sc=sectcheck, pl=parameterlist, nested=nested)
" sectcheck=%(sc)s / parameterlist=%(pl)s"
, n=decl_name, t=decl_type, sc=sectcheck, pl=parameterlist)

for sect in sectcheck:
sub_sect = re.sub(r"\..*", "", sect) # take @foo.bar sections as "foo" sub-section
Expand All @@ -2846,7 +2822,7 @@ def check_sections(self, decl_name, decl_type
"excess function parameter '%(sect)s' description in '%(decl_name)s'"
, sect = sect, decl_name = decl_name
, line_no = self.ctx.decl_offset )
elif not re.search(r"\b(" + sect + ")[^a-zA-Z0-9]", nested):
else:
self.warn(
"excess %(decl_type)s member '%(sect)s' description in '%(decl_name)s'"
, decl_type = decl_type, decl_name = decl_name, sect = sect
Expand Down

0 comments on commit 518b4ef

Please sign in to comment.