Skip to content

Commit 1e7dc6d

Browse files
committed
Add support for :private-members: option
Previously all constructs for a C file were auto documented unless the :members: option was used to limit to specific named items. Now by default the autocmodule directive will only autodocument members which are either non static functions, non static variables. Unless the module is a header file, .h, then all constructs will still be documented. The :private-members: option must be used to automatically auto document all of the c constructs in a module. The :no-private-members: option also becomes available to allow defaulting to :private-members: and selectivly limiting on a per module basis.
1 parent 60521f8 commit 1e7dc6d

File tree

8 files changed

+260
-19
lines changed

8 files changed

+260
-19
lines changed

CHANGELOG.rst

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,21 @@ This project adheres to `Semantic Versioning <https://semver.org/>`_.
99
`v0.3.0-dev`_ (unreleased)
1010
==========================
1111

12-
`v0.2.0`_ (2020-04-1)
12+
`v0.2.0`_ (2020-04-04)
1313
==========================
1414

1515
Added
1616
-----
1717

1818
* Viewcode functionality which allows for listing the source C files and
1919
providing links between the documentation and the C source listings.
20+
* :private-members: and :no-private-members: option for the autocmodule
21+
directive. This option set allows for controlling the documentation of
22+
constructs based on what is visible outside of the module. For header
23+
files this means everything will still be documented. For standard source
24+
files only non static functions and non static variables will be auto
25+
documented if the :private-members: is not specified, or the
26+
:no-private-members: is specified.
2027

2128
Fixes
2229
-----

docs/directives.rst

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ instance from being added to the index provide this option.
3636
This option has 4 states:
3737
3838
- Omitted will result in the ``members`` entry of
39-
`autodoc_default_options <https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_default_options>`_
40-
being used. If ``members`` is omitted from
41-
`autodoc_default_options <https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_default_options>`_ then no members will be automatically documented.
39+
`autodoc_default_options`_ being used. If ``members`` is omitted
40+
from `autodoc_default_options`_ then no members will be
41+
automatically documented.
4242
- Specified as ``:no-members:``, no members will be automatically
4343
documented.
4444
- Specified with no arguments, ``:members:``, then all supported C
@@ -47,6 +47,25 @@ instance from being added to the index provide this option.
4747
``:members: function_a, struct_b``, only the file members specified will
4848
be recursively documented.
4949
50+
.. rst:directive:option:: private-members
51+
52+
Specify if private members are to be documented. Since C doesn't
53+
actually have a true idea of public and private, the following rules
54+
are used to determine these characteristics.
55+
56+
Members are public if:
57+
58+
- They are in a header file, ends in `.h`. By nature header files are meant to
59+
be included in other files, thus anything declared there is
60+
deamed public.
61+
- They can be visible outside of the compilation unit. These are
62+
things the linker can get access to. Mainly this means functions
63+
and variables that are not static.
64+
65+
Just as for the standard `autodoc`_ options, one can use the negated
66+
form of ``:no-private-members:`` to selectivly turn off this option
67+
on a per module basis.
68+
5069
.. rst:directive:: .. autocfunction:: filename::function
5170
5271
Document the function ``function`` from file ``filename``.
@@ -78,10 +97,9 @@ instance from being added to the index provide this option.
7897
This option has 4 states:
7998
8099
- Omitted will result in the ``members`` entry of
81-
`autodoc_default_options <https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_default_options>`_
82-
being used. If ``members`` is omitted from
83-
`autodoc_default_options <https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_default_options>`_
84-
then no members will be automatically documented.
100+
`autodoc_default_options`_ being used. If ``members`` is omitted
101+
from `autodoc_default_options`_ then no members will be
102+
automatically documented.
85103
- Specified as ``:no-members:``, no members will be automatically
86104
documented.
87105
- Specified with no arguments, ``:members:``, then all fields (if struct
@@ -101,12 +119,13 @@ instance from being added to the index provide this option.
101119
constant (if an enum).
102120

103121
.. note:: This is one of the overloaded uses of the term **member**. This
104-
name was used to keep consistent with the
105-
`member <https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-c:member>`_
106-
wording of the `C domain`_.
122+
name was used to keep consistent with the `member`_ wording of the
123+
`C domain`_.
107124

108125
.. _autodoc: https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html
126+
.. _member: https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-c:member
109127
.. _domain: https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html
110128
.. _C domain: https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#the-c-domain
111129
.. _Sphinx: https://www.sphinx-doc.org/en/master/index.html
112130
.. _Doxygen: http://www.doxygen.nl/
131+
.. _autodoc_default_options: https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_default_options

src/sphinx_c_autodoc/__init__.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,11 @@ class CObjectDocumenter(Documenter):
7878
# objects
7979
priority = 11
8080

81-
option_spec = {"members": members_option, "noindex": bool_option}
81+
option_spec = {
82+
"members": members_option,
83+
"noindex": bool_option,
84+
"private-members": bool_option,
85+
}
8286

8387
@classmethod
8488
def can_document_member(
@@ -276,22 +280,30 @@ def filter_members(
276280
) -> List[Tuple[str, Any, bool]]:
277281
"""Filter the given member list.
278282
283+
:meth:`filter_members` is called *after* :meth:`get_object_members`,
284+
this means if `want_all` is False then only private members which
285+
were explicitly requested will be in this list. Only when `want_all`
286+
is True do we need to actually condition on private member.
287+
279288
Members are skipped if
280289
281290
- they are private (except if given explicitly or the private-members
282291
option is set)
283-
- they are special methods (except if given explicitly or the
284-
special-members option is set)
285292
- they are undocumented (except if the undoc-members option is set)
293+
TODO not implemented yet.
286294
295+
TODO not implemented yet.
287296
The user can override the skipping decision by connecting to the
288297
``autodoc-skip-member`` event.
289298
"""
290299
ret = []
291300
isattr = False
292301
for (membername, member) in members:
293-
ret.append((membername, member, isattr))
294-
302+
if not want_all:
303+
ret.append((membername, member, isattr))
304+
else:
305+
if member.is_public() or self.options.private_members:
306+
ret.append((membername, member, isattr))
295307
return ret
296308

297309
def format_name(self) -> str:

src/sphinx_c_autodoc/loader.py

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from bs4 import BeautifulSoup
1515
from bs4.element import Tag
1616
from clang import cindex
17-
from clang.cindex import Cursor, Token
17+
from clang.cindex import Cursor, Token, StorageClass
1818

1919
from sphinx_c_autodoc.clang.patches import patch_clang
2020

@@ -242,6 +242,29 @@ def get_paragraph(tag: Optional[Tag]) -> str:
242242
paragraph += "\n"
243243
return paragraph
244244

245+
def is_public(self) -> bool:
246+
"""
247+
Determines if this item is public.
248+
249+
C doesn't actually have public/private namespace so we're going to
250+
make up some rules.
251+
252+
Constructs are public if:
253+
254+
- They are in a header file. By nature header files are meant to
255+
be included in other files, thus they are deamed public.
256+
257+
- They can be visible outside of the compilation unit. These are
258+
things the linker can get access to. Mainly this means functions
259+
and variables that are not static.
260+
"""
261+
# Here we'll do the most common logic, and let specific constructs that
262+
# can be public do special logic.
263+
if self.node.location.file.name.endswith(".h"):
264+
return True
265+
266+
return False
267+
245268

246269
class DocumentedFile(DocumentedObject):
247270
"""
@@ -354,6 +377,13 @@ def get_parsed_declaration(self) -> str:
354377
type_ = self.node.type.spelling
355378
return f"{type_} {self.name}"
356379

380+
def is_public(self) -> bool:
381+
"""
382+
Members are always public, because it's their parents that determine
383+
public versus private.
384+
"""
385+
return True
386+
357387

358388
class DocumentedFunction(DocumentedObject):
359389
"""
@@ -447,6 +477,15 @@ def get_parsed_declaration(self) -> str:
447477

448478
return "{} {}({})".format(return_type, func.spelling, ", ".join(args))
449479

480+
def is_public(self) -> bool:
481+
"""
482+
Functions are public as long as they are not static.
483+
"""
484+
if self.node.storage_class == StorageClass.STATIC:
485+
return False
486+
487+
return True
488+
450489

451490
class DocumentedType(DocumentedObject):
452491
"""
@@ -517,7 +556,7 @@ class DocumentedUnion(DocumentedStructure):
517556

518557
class DocumentedEnum(DocumentedStructure):
519558
"""
520-
Class for unions. Same as structures with a different :attr:`type`.
559+
Class for Enumerations. Same as structures with a different :attr:`type`.
521560
"""
522561

523562
type_ = "enum"
@@ -547,6 +586,15 @@ def format_name(self) -> str:
547586
name, _, _ = decl.partition("=")
548587
return name
549588

589+
def is_public(self) -> bool:
590+
"""
591+
Variables are public as long as they are not static.
592+
"""
593+
if self.node.storage_class == StorageClass.STATIC:
594+
return False
595+
596+
return True
597+
550598

551599
CURSORKIND_TO_OBJECT_CLASS = {
552600
cindex.CursorKind.TRANSLATION_UNIT: DocumentedFile,
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Defines in C files are inherently private.
3+
*/
4+
#define PRIVATE_MACRO 3
5+
6+
/**
7+
* Function macros in C files should also be private
8+
*/
9+
#define PRIVATE_FUNCTION_MACRO(_a, _b)\
10+
(_a) + (_b)
11+
12+
/**
13+
* Types, in c files are inherently private.
14+
*/
15+
typedef int foo;
16+
17+
/**
18+
* static variables are inherently private
19+
*/
20+
static int my_var;
21+
22+
/**
23+
* Non static variables are not private
24+
*/
25+
float a_public_var;
26+
27+
/**
28+
* Enumerations in c files are inherently private
29+
*/
30+
enum private_enum {
31+
ENUM_1
32+
};
33+
34+
/**
35+
* structures in c files are inherently private
36+
*/
37+
struct private_struct {
38+
int a;
39+
};
40+
41+
/**
42+
* Non static functions are not private
43+
*/
44+
void function1(int a);
45+
46+
/**
47+
* static functions, in c files are inherently private.
48+
*/
49+
static void function2(int a);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/**
2+
* This should always be visible, even if ``no-private-members`` is in use.
3+
*/
4+
typedef float header_type;

tests/assets/conf.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@
192192

193193

194194
# -- Extension configuration -------------------------------------------------
195+
autodoc_default_options = {
196+
"private-members": True,
197+
}
195198

196199
primary_domain = "c"
197200
c_autodoc_roots = ["c_source", "c_source_2", "c_source_2/nested"]

0 commit comments

Comments
 (0)