Merged in jakobla/sphinx (pull request #263)

Rewrite of C++ domain (also fixes #1013, #1103)
This commit is contained in:
Takayuki Shimizukawa 2014-08-10 20:02:37 +09:00
commit 8dcd094a30
3 changed files with 1475 additions and 1176 deletions

View File

@ -520,23 +520,26 @@ The C++ Domain
The C++ domain (name **cpp**) supports documenting C++ projects.
The following directives are available:
The following directives are available. All declarations can start with a visibility statement
(``public``, ``private`` or ``protected``).
.. rst:directive:: .. cpp:class:: signatures
.. cpp:function:: signatures
.. cpp:member:: signatures
.. cpp:type:: signatures
.. rst:directive:: .. cpp:class:: class speicifer
Describe a C++ object. Full signature specification is supported -- give the
signature as you would in the declaration. Here some examples::
Describe a class/struct, possibly with specification of inheritance, e.g.,::
.. cpp:class:: SomeName::SomeClass : public MyBase, MyOtherBase
.. rst:directive:: .. cpp:function:: (member-)function prototype
Describe a function or member function, e.g.,::
.. cpp:function:: bool namespaced::theclass::method(int arg1, std::string arg2)
Describes a method with parameters and types.
.. cpp:function:: bool namespaced::theclass::method(arg1, arg2)
.. cpp:function:: bool namespaced::theclass::method(T1, T2)
Describes a method without types.
Describes a method with unnamed parameters.
.. cpp:function:: const T &array<T>::operator[]() const
@ -550,43 +553,41 @@ The following directives are available:
Describe a constexpr function here.
.. cpp:member:: std::string theclass::name
.. cpp:function:: MyClass::MyClass(const MyClass&) = default
.. cpp:member:: std::string theclass::name[N][M]
Describe a copy constructor with default implementation.
.. cpp:type:: theclass::const_iterator
.. rst:directive:: .. cpp:member:: variable or member declaration
Will be rendered like this:
.. cpp:function:: bool namespaced::theclass::method(int arg1, std::string arg2)
Describes a method with parameters and types.
.. cpp:function:: bool namespaced::theclass::method(arg1, arg2)
Describes a method without types.
.. cpp:function:: const T &array<T>::operator[]() const
Describes the constant indexing operator of a templated array.
.. cpp:function:: operator bool() const
Describe a casting operator here.
.. cpp:function:: constexpr void foo(std::string &bar[2]) noexcept
Describe a constexpr function here.
Describe a varible or member variable, e.g.,::
.. cpp:member:: std::string theclass::name
.. cpp:member:: std::string theclass::name[N][M]
.. rst:directive:: .. cpp:type:: typedef-like declaration
.. cpp:type:: name
Describe a type as in a typedef declaration, or the name of a type with unspecified type, e.g.,::
.. cpp:type:: std::vector<int> MyList
A typedef-like declaration of a type.
.. cpp:type:: theclass::const_iterator
Declaration of a type alias with unspecified type.
.. rst:directive:: .. cpp:namespace:: namespace
Select the current C++ namespace for the following objects.
Select the current namespace for the following objects. Note that the namespace
does not need to correspond to C++ namespaces, but can end in names of classes, e.g.,::
.. cpp:namespace:: Namespace1::Namespace2::SomeClass::AnInnerClass
All following objects will be defined as if their name were declared with the namespace
prepended. The following cross-references will be search for by both their specified name
and with the namespace prepended.
.. _cpp-roles:
@ -598,7 +599,7 @@ These roles link to the given object types:
cpp:member
cpp:type
Reference a C++ object. You can give the full signature (and need to, for
Reference a C++ object. You can give the full specification (and need to, for
overloaded functions.)
.. note::
@ -619,6 +620,12 @@ These roles link to the given object types:
specific overload. Currently Sphinx will link to the first overloaded
version of the method / function.
.. admonition:: Note on Template Delcarations
The C++ domain currently does not support template classes/functions/aliases/variables
(e.g., ``template<typename T> MyClass``), only template instantiations
(e.g., ``MyClass<T>``).
The Standard Domain
-------------------

File diff suppressed because it is too large Load Diff

View File

@ -15,147 +15,113 @@ from util import raises
from sphinx.domains.cpp import DefinitionParser, DefinitionError
def parse(name, string):
return getattr(DefinitionParser(string), 'parse_' + name)()
parser = DefinitionParser(string)
res = getattr(parser, "parse_" + name + "_object")()
if not parser.eof:
print("Parsing stopped at", parser.pos)
print(string)
print('-'*parser.pos + '^')
raise DefinitionError("")
return res
def check(name, input, output=None):
# first a simple check of the AST
if output == None: output = input
ast = parse(name, input)
res = text_type(ast)
if res != output:
print("Input: ", text_type(input))
print("Result: ", res)
print("Expected: ", output)
raise DefinitionError("")
ast.describe_signature([], 'lastIsName', None)
ast.prefixedName = ast.name # otherwise the get_id fails, it would be set in handle_signarue
ast.get_id()
#print ".. %s:: %s" % (name, input)
def test_type_definitions():
rv = parse('member_object', ' const std::string & name = 42')
assert text_type(rv) == 'const std::string& name = 42'
check("type", "public bool b", "bool b")
check("type", "bool A::b")
check("type", "bool *b")
check("type", "bool *const b")
check("type", "bool *volatile const b")
check("type", "bool *volatile const b")
check("type", "bool *volatile const *b")
check("type", "bool &b")
check("type", "bool b[]")
check("type", "std::pair<int, int> coord")
check("type", "long long int foo")
check("type", 'std::vector<std::pair<std::string, long long>> module::blah')
check("type", "std::function<void()> F")
check("type", "std::function<R(A1, A2, A3)> F")
check("type", "std::function<R(A1, A2, A3, As...)> F")
check("type", "MyContainer::const_iterator")
check("type", "public MyContainer::const_iterator", "MyContainer::const_iterator")
check('member', ' const std::string & name = 42', 'const std::string &name = 42')
check('member', ' const std::string & name', 'const std::string &name')
check('member', ' const std::string & name [ n ]', 'const std::string &name[n]')
check('member', 'const std::vector< unsigned int, long> &name', 'const std::vector<unsigned int, long> &name')
check('member', 'module::myclass foo[n]')
rv = parse('member_object', ' const std::string & name leftover')
assert text_type(rv) == 'const std::string& name'
check('function', 'operator bool() const')
check('function', 'bool namespaced::theclass::method(arg1, arg2)')
x = 'std::vector<std::pair<std::string, int>> &module::test(register ' \
'foo, bar, std::string baz = "foobar, blah, bleh") const = 0'
check('function', x)
check('function', 'explicit module::myclass::foo::foo()')
check('function', 'module::myclass::foo::~foo()')
check('function', 'int printf(const char *fmt, ...)')
check('function', 'int foo(const unsigned int j)')
check('function', 'int foo(const int *const ptr)')
check('function', 'module::myclass::operator std::vector<std::string>()')
check('function', 'void operator()(const boost::array<VertexID, 2> &v) const')
check('function', 'void operator()(const boost::array<VertexID, 2, "foo, bar"> &v) const')
check('function', 'MyClass::MyClass(MyClass::MyClass&&)')
check('function', 'constexpr int get_value()')
check('function', 'static constexpr int get_value()')
check('function', 'int get_value() const noexcept')
check('function', 'int get_value() const noexcept = delete')
check('function', 'MyClass::MyClass(MyClass::MyClass&&) = default')
check('function', 'virtual MyClass::a_virtual_function() const override')
check('function', 'A B() override')
check('function', 'A B() final')
check('function', 'A B() final override')
check('function', 'A B() override final', 'A B() final override')
check('function', 'MyClass::a_member_function() volatile')
check('function', 'MyClass::a_member_function() volatile const')
check('function', 'MyClass::a_member_function() &&')
check('function', 'MyClass::a_member_function() &')
check('function', 'MyClass::a_member_function() const &')
check('function', 'int main(int argc, char *argv[])')
check('function', 'MyClass &MyClass::operator++()')
check('function', 'MyClass::pointer MyClass::operator->()')
rv = parse('member_object', ' const std::string & name [n] leftover')
assert text_type(rv) == 'const std::string& name[n]'
rv = parse('member_object', 'const std::vector< unsigned int, long> &name')
assert text_type(rv) == 'const std::vector<unsigned int, long>& name'
x = 'std::vector<std::pair<std::string, int>>& module::test(register ' \
'foo, bar, std::string baz="foobar, blah, bleh") const = 0'
assert text_type(parse('function', x)) == x
x = 'module::myclass::operator std::vector<std::string>()'
assert text_type(parse('function', x)) == x
x = 'explicit module::myclass::foo::foo()'
assert text_type(parse('function', x)) == x
x = 'int printf(const char* fmt, ...)'
assert text_type(parse('function', x)) == x
x = 'int foo(const unsigned int j)'
assert text_type(parse('function', x)) == x
x = 'int foo(const unsigned int const j)'
assert text_type(parse('function', x)) == x
x = 'int foo(const int* const ptr)'
assert text_type(parse('function', x)) == x
x = 'std::vector<std::pair<std::string, long long>> module::blah'
assert text_type(parse('type_object', x)) == x
assert text_type(parse('type_object', 'long long int foo')) == 'long long foo'
x = 'void operator()(const boost::array<VertexID, 2>& v) const'
assert text_type(parse('function', x)) == x
x = 'void operator()(const boost::array<VertexID, 2, "foo, bar">& v) const'
assert text_type(parse('function', x)) == x
x = 'MyClass::MyClass(MyClass::MyClass&&)'
assert text_type(parse('function', x)) == x
x = 'constexpr int get_value()'
assert text_type(parse('function', x)) == x
x = 'static constexpr int get_value()'
assert text_type(parse('function', x)) == x
x = 'int get_value() const noexcept'
assert text_type(parse('function', x)) == x
x = 'int get_value() const noexcept = delete'
assert text_type(parse('function', x)) == x
x = 'MyClass::MyClass(MyClass::MyClass&&) = default'
assert text_type(parse('function', x)) == x
x = 'MyClass::a_virtual_function() const override'
assert text_type(parse('function', x)) == x
x = 'MyClass::a_member_function() volatile'
assert text_type(parse('function', x)) == x
x = 'MyClass::a_member_function() const volatile'
assert text_type(parse('function', x)) == x
x = 'MyClass::a_member_function() &&'
assert text_type(parse('function', x)) == x
x = 'MyClass::a_member_function() &'
assert text_type(parse('function', x)) == x
x = 'MyClass::a_member_function() const &'
assert text_type(parse('function', x)) == x
x = 'int main(int argc, char* argv[][])'
assert text_type(parse('function', x)) == x
x = 'std::vector<std::pair<std::string, int>>& module::test(register ' \
'foo, bar[n], std::string baz="foobar, blah, bleh") const = 0'
assert text_type(parse('function', x)) == x
x = 'module::myclass foo[n]'
assert text_type(parse('member_object', x)) == x
x = 'int foo(Foo f=Foo(double(), std::make_pair(int(2), double(3.4))))'
assert text_type(parse('function', x)) == x
x = 'int foo(A a=x(a))'
assert text_type(parse('function', x)) == x
x = 'int foo(B b=x(a)'
raises(DefinitionError, parse, 'function', x)
x = 'int foo)C c=x(a))'
raises(DefinitionError, parse, 'function', x)
x = 'int foo(D d=x(a'
raises(DefinitionError, parse, 'function', x)
x = 'int foo(const A&... a)'
assert text_type(parse('function', x)) == x
x = 'std::vector<std::pair<std::string, int>> &module::test(register ' \
'foo, bar[n], std::string baz = "foobar, blah, bleh") const = 0'
check('function', x)
check('function', 'int foo(Foo f = Foo(double(), std::make_pair(int(2), double(3.4))))')
check('function', 'int foo(A a = x(a))')
raises(DefinitionError, parse, 'function', 'int foo(B b=x(a)')
raises(DefinitionError, parse, 'function', 'int foo)C c=x(a))')
raises(DefinitionError, parse, 'function', 'int foo(D d=x(a')
check('function', 'int foo(const A&... a)')
check('function', 'virtual void f()')
def test_bases():
x = 'A'
assert text_type(parse('class', x)) == x
x = 'A : B'
assert text_type(parse('class', x)) == x
x = 'A : private B'
assert text_type(parse('class', x)) == 'A : B'
x = 'A : public B'
assert text_type(parse('class', x)) == x
x = 'A : B, C'
assert text_type(parse('class', x)) == x
x = 'A : B, protected C, D'
assert text_type(parse('class', x)) == x
check('class', 'A')
check('class', 'A::B::C')
check('class', 'A : B')
check('class', 'A : private B', 'A : B')
check('class', 'A : public B')
check('class', 'A : B, C')
check('class', 'A : B, protected C, D')
def test_operators():
x = parse('function', 'void operator new [ ] ()')
assert text_type(x) == 'void operator new[]()'
x = parse('function', 'void operator delete ()')
assert text_type(x) == 'void operator delete()'
check('function', 'void operator new [ ] ()', 'void operator new[]()')
check('function', 'void operator delete ()', 'void operator delete()')
check('function', 'void operator bool() const', 'void operator bool() const')
for op in '*-+=/%!':
x = parse('function', 'void operator %s ()' % op)
assert text_type(x) == 'void operator%s()' % op
check('function', 'void operator %s ()' % op, 'void operator%s()' % op)