Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic C++ namespace support #247

Merged
merged 3 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 33 additions & 4 deletions src/hawkmoth/doccursor.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,23 @@
)


def _get_semantic_parent_namespace(cursor, namespace):
semantic_parent = cursor.semantic_parent
if not semantic_parent:
return namespace

if semantic_parent.kind == CursorKind.NAMESPACE:
# parent is a namespace => add namespace in front
if namespace is not None:
namespace = f'{semantic_parent.spelling}::{namespace}'
else:
namespace = semantic_parent.spelling
# check again for nested namespaces
return _get_semantic_parent_namespace(semantic_parent, namespace)

return namespace


class DocCursor:
"""Documentation centric wrapper for Clang's own ``Cursor``.

Expand Down Expand Up @@ -66,7 +83,7 @@ def kind(self):

@property
def name(self):
return self._cc.spelling if self._cc.spelling else self.decl_name
return self.namespace_prefix + self._cc.spelling if self._cc.spelling else self.decl_name

@property
def decl_name(self):
Expand All @@ -81,7 +98,14 @@ def decl_name(self):
return self._type_definition_fixup()
else:
# self.name would recurse back here if self._cc.spelling is None
return self._cc.spelling
return self.namespace_prefix + self._cc.spelling if self._cc.spelling else None

@property
def namespace_prefix(self):
if self.domain != 'cpp':
return ''
namespace = _get_semantic_parent_namespace(self._cc, None)
return f'{namespace}::' if namespace else ''

@property
def type(self):
Expand Down Expand Up @@ -271,7 +295,7 @@ def _type_definition_fixup(self):
template = self._get_template_line()
template = template + ' ' if template else ''

return f'{template}{self._cc.spelling}{colon_suffix}'
return f'{template}{self.namespace_prefix}{self._cc.spelling}{colon_suffix}'

def _get_macro_args(self):
"""Get macro arguments.
Expand Down Expand Up @@ -511,7 +535,12 @@ def _get_inheritance(self):
if child._cc.kind == CursorKind.CXX_BASE_SPECIFIER:
def pad(s): return s + ' ' if s else ''
access_spec = child._get_access_specifier()
inherited.append(f'{pad(access_spec)}{child._cc.type.spelling}')
if child._cc.referenced.kind == CursorKind.CLASS_DECL:
# use referenced type if possible for full namespace
spelling = child._cc.referenced.type.spelling
else:
spelling = child._cc.type.spelling
inherited.append(f'{pad(access_spec)}{spelling}')

return ': ' + ', '.join(inherited) if len(inherited) > 0 else None

Expand Down
11 changes: 11 additions & 0 deletions src/hawkmoth/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,17 @@ def _parse_undocumented_block(errors, cursor, nest):
if c.comment:
ret.extend(_recursive_parse(errors, c, nest))

elif cursor.kind == CursorKind.NAMESPACE:
# ignore internal STL namespaces
if cursor.name in ['std', '__gnu_cxx', '__cxxabiv1', '__gnu_debug']:
return ret
# iterate over namespace
for c in cursor.get_children():
if c.comment:
ret.extend(_recursive_parse(errors, c, nest))
else:
ret.extend(_parse_undocumented_block(errors, c, nest))

return ret

def _language_option(filename, domain):
Expand Down
99 changes: 99 additions & 0 deletions test/cpp/namespace.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
namespace A {
namespace B {

/**
* Test fct A
*/
int testa(int a) { return a; }

/**
* Test cls B
*/
class TestB {
public:
/**
* Test fct B
*/
int testb(int b) { return b; }

private:
/** Not constant */
double b;
};


/** Some constant */
constexpr double CONSTANT = 5.;

} // namespace B

/**
* Test cls D
*/
class TestD : public B::TestB {
public:
/**
* Test fct D
*/
int testd() const { return d; }
private:
static double d;
};

/**
* Test fct C
*/
template<typename T>
int testc(int c) { return c; }

/**
* Test enum E
*/
enum class TestE {
/** enum member A */
A,
/** enum member B */
B,
};

} // namespace A


namespace foo {
/**
* foo_class
*/
class foo_class {
/** member */
int m;
};

/**
* foo_struct
*/
struct foo_struct {
/** member */
int m;
};

/**
* foo_union
*/
union foo_union {
/** member1 */
int m1;
/** member2 */
int m2;
};

/**
* Const.
*/
const int GLOBAL = 5;

/** enum */
enum foo_enum {
/** enumerator */
FOO_ENUMERATOR,
};
};
105 changes: 105 additions & 0 deletions test/cpp/namespace.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@

.. cpp:function:: int A::B::testa(int a)

Test fct A


.. cpp:class:: A::B::TestB

Test cls B


.. cpp:function:: public int testb(int b)

Test fct B


.. cpp:member:: private double b

Not constant


.. cpp:var:: constexpr double CONSTANT

Some constant


.. cpp:class:: A::TestD: public A::B::TestB

Test cls D


.. cpp:function:: public int testd(void) const

Test fct D


.. cpp:function:: template<typename T> int A::testc(int c)

Test fct C


.. cpp:enum-class:: A::TestE

Test enum E


.. cpp:enumerator:: A

enum member A


.. cpp:enumerator:: B

enum member B


.. cpp:class:: foo::foo_class

foo_class


.. cpp:member:: private int m

member


.. cpp:struct:: foo::foo_struct

foo_struct


.. cpp:member:: public int m

member


.. cpp:union:: foo::foo_union

foo_union


.. cpp:member:: int m1

member1


.. cpp:member:: int m2

member2


.. cpp:var:: const int GLOBAL

Const.


.. cpp:enum:: foo::foo_enum

enum


.. cpp:enumerator:: FOO_ENUMERATOR

enumerator

6 changes: 6 additions & 0 deletions test/cpp/namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
directives:
- domain: cpp
directive: autodoc
arguments:
- namespace.cpp
expected: namespace.rst
Loading