Initial commit

This commit is contained in:
Dustin Spicuzza
2020-12-28 03:35:30 -05:00
commit ef5c22972b
37 changed files with 14826 additions and 0 deletions

25
tests/README.md Normal file
View File

@@ -0,0 +1,25 @@
Tests
=====
To run the tests, install `cxxheaderparser` and `pytest`, then just run:
pytest
Adding new tests
----------------
There's a helper script in cxxheaderparser explicitly for generating many of the
unit tests in this directory. To run it:
* Create a file with your C++ content in it
* Run `python -m cxxheaderparser.gentest FILENAME.h some_name`
* Copy the stdout to one of these `test_*.py` files
Content origin
--------------
* Some are scraps of real code derived from various sources
* Some were derived from the original `CppHeaderParser` tests
* Some have been derived from examples found on https://en.cppreference.com,
which are available under Creative Commons Attribution-Sharealike 3.0
Unported License (CC-BY-SA)

148
tests/test_attributes.py Normal file
View File

@@ -0,0 +1,148 @@
# Note: testcases generated via `python -m cxxheaderparser.gentest`
from cxxheaderparser.types import (
ClassDecl,
EnumDecl,
Enumerator,
Field,
Function,
FundamentalSpecifier,
NameSpecifier,
PQName,
Pointer,
Token,
Type,
Typedef,
Value,
Variable,
)
from cxxheaderparser.simple import (
ClassScope,
NamespaceScope,
parse_string,
ParsedData,
)
def test_attributes_everywhere():
# TODO: someday we'll actually support storing attributes,
# but for now just make sure they don't get in the way
content = """
struct [[deprecated]] S {};
[[deprecated]] typedef S *PS;
[[deprecated]] int x;
union U {
[[deprecated]] int n;
};
[[deprecated]] void f();
enum [[deprecated]] E{A [[deprecated]], B [[deprecated]] = 42};
struct alignas(8) AS {};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="S")], classkey="struct"
)
)
),
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="U")], classkey="union"
)
),
fields=[
Field(
access="public",
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
name="n",
)
],
),
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="AS")], classkey="struct"
)
)
),
],
enums=[
EnumDecl(
typename=PQName(
segments=[NameSpecifier(name="E")], classkey="enum"
),
values=[
Enumerator(name="A"),
Enumerator(name="B", value=Value(tokens=[Token(value="42")])),
],
)
],
functions=[
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="void")])
),
name=PQName(segments=[NameSpecifier(name="f")]),
parameters=[],
)
],
typedefs=[
Typedef(
type=Pointer(
ptr_to=Type(typename=PQName(segments=[NameSpecifier(name="S")]))
),
name="PS",
)
],
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="x")]),
type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
)
],
)
)
def test_attributes_gcc_enum_packed():
content = """
enum Wheat {
w1,
w2,
w3,
} __attribute__((packed));
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(
segments=[NameSpecifier(name="Wheat")], classkey="enum"
),
values=[
Enumerator(name="w1"),
Enumerator(name="w2"),
Enumerator(name="w3"),
],
)
]
)
)

2843
tests/test_class.py Normal file

File diff suppressed because it is too large Load Diff

247
tests/test_class_base.py Normal file
View File

@@ -0,0 +1,247 @@
# Note: testcases generated via `python -m cxxheaderparser.gentest`
from cxxheaderparser.types import (
BaseClass,
ClassDecl,
Field,
FundamentalSpecifier,
Method,
NameSpecifier,
PQName,
TemplateArgument,
TemplateSpecialization,
Token,
Type,
)
from cxxheaderparser.simple import (
ClassScope,
NamespaceScope,
parse_string,
ParsedData,
)
def test_class_private_base():
content = """
namespace Citrus
{
class BloodOrange { };
}
class Bananna: public Citrus::BloodOrange
{
};
class ExcellentCake: private Citrus::BloodOrange, Convoluted::Nested::Mixin
{
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="Bananna")], classkey="class"
),
bases=[
BaseClass(
access="public",
typename=PQName(
segments=[
NameSpecifier(name="Citrus"),
NameSpecifier(name="BloodOrange"),
]
),
)
],
)
),
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="ExcellentCake")],
classkey="class",
),
bases=[
BaseClass(
access="private",
typename=PQName(
segments=[
NameSpecifier(name="Citrus"),
NameSpecifier(name="BloodOrange"),
]
),
),
BaseClass(
access="private",
typename=PQName(
segments=[
NameSpecifier(name="Convoluted"),
NameSpecifier(name="Nested"),
NameSpecifier(name="Mixin"),
]
),
),
],
)
),
],
namespaces={
"Citrus": NamespaceScope(
name="Citrus",
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="BloodOrange")],
classkey="class",
)
)
)
],
)
},
)
)
def test_class_virtual_base():
content = """
class BaseMangoClass {};
class MangoClass : virtual public BaseMangoClass {};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="BaseMangoClass")],
classkey="class",
)
)
),
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="MangoClass")],
classkey="class",
),
bases=[
BaseClass(
access="public",
typename=PQName(
segments=[NameSpecifier(name="BaseMangoClass")]
),
virtual=True,
)
],
)
),
]
)
)
def test_class_multiple_base_with_virtual():
content = """
class BlueJay : public Bird, public virtual Food {
public:
BlueJay() {}
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="BlueJay")], classkey="class"
),
bases=[
BaseClass(
access="public",
typename=PQName(segments=[NameSpecifier(name="Bird")]),
),
BaseClass(
access="public",
typename=PQName(segments=[NameSpecifier(name="Food")]),
virtual=True,
),
],
),
methods=[
Method(
return_type=None,
name=PQName(segments=[NameSpecifier(name="BlueJay")]),
parameters=[],
has_body=True,
access="public",
constructor=True,
)
],
)
]
)
)
def test_class_base_specialized():
content = """
class Pea : public Vegetable<Green> {
int i;
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="Pea")], classkey="class"
),
bases=[
BaseClass(
access="public",
typename=PQName(
segments=[
NameSpecifier(
name="Vegetable",
specialization=TemplateSpecialization(
args=[
TemplateArgument(
tokens=[Token(value="Green")]
)
]
),
)
]
),
)
],
),
fields=[
Field(
access="private",
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
name="i",
)
],
)
]
)
)

221
tests/test_doxygen.py Normal file
View File

@@ -0,0 +1,221 @@
# Note: testcases generated via `python -m cxxheaderparser.gentest`
from cxxheaderparser.types import (
AnonymousName,
Array,
BaseClass,
ClassDecl,
EnumDecl,
Enumerator,
Field,
ForwardDecl,
Function,
FundamentalSpecifier,
Method,
MoveReference,
NameSpecifier,
Operator,
PQName,
Parameter,
Pointer,
Reference,
TemplateArgument,
TemplateDecl,
TemplateSpecialization,
TemplateTypeParam,
Token,
Type,
Typedef,
UsingDecl,
Value,
Variable,
)
from cxxheaderparser.simple import (
ClassScope,
NamespaceScope,
parse_string,
ParsedData,
)
r"""
class SampleClass: public BaseSampleClass
{
public:
enum Elephant
{
EL_ONE = 1,
EL_TWO = 2,
EL_NINE = 9,
EL_TEN,
};
SampleClass();
/*!
* Method 1
*/
string meth1();
///
/// Method 2 description
///
/// @param v1 Variable 1
///
int meth2(int v1);
/**
* Method 3 description
*
* \param v1 Variable 1 with a really long
* wrapping description
* \param v2 Variable 2
*/
void meth3(const string & v1, vector<string> & v2);
/**********************************
* Method 4 description
*
* @return Return value
*********************************/
unsigned int meth4();
private:
void * meth5(){return NULL;}
/// prop1 description
string prop1;
//! prop5 description
int prop5;
bool prop6; /*!< prop6 description */
double prop7; //!< prop7 description
//!< with two lines
/// prop8 description
int prop8;
};
namespace Alpha
{
class AlphaClass
{
public:
AlphaClass();
void alphaMethod();
string alphaString;
protected:
typedef enum
{
Z_A,
Z_B = 0x2B,
Z_C = 'j',
Z_D,
} Zebra;
};
namespace Omega
{
class OmegaClass
{
public:
OmegaClass();
string omegaString;
protected:
///
/// @brief Rino Numbers, not that that means anything
///
typedef enum
{
RI_ZERO, /// item zero
RI_ONE, /** item one */
RI_TWO, //!< item two
RI_THREE,
/// item four
RI_FOUR,
} Rino;
};
};
}
"""
# def test_doxygen_messy():
# content = """
# // clang-format off
# /// fn comment
# void
# fn();
# /// var comment
# int
# v1 = 0;
# int
# v2 = 0; /// var2 comment
# /// cls comment
# class
# C {};
# /// template comment
# template <typename T>
# class
# C2 {};
# """
# data = parse_string(content, cleandoc=True)
# assert data == ParsedData(
# namespace=NamespaceScope(
# classes=[
# ClassScope(
# class_decl=ClassDecl(
# typename=PQName(
# segments=[NameSpecifier(name="C")], classkey="class"
# ),
# doxygen="/// cls comment",
# )
# ),
# ClassScope(
# class_decl=ClassDecl(
# typename=PQName(
# segments=[NameSpecifier(name="C2")], classkey="class"
# ),
# template=TemplateDecl(
# params=[TemplateTypeParam(typekey="typename", name="T")]
# ),
# doxygen="/// template comment",
# )
# ),
# ],
# functions=[
# Function(
# return_type=Type(
# typename=PQName(segments=[FundamentalSpecifier(name="void")])
# ),
# name=PQName(segments=[NameSpecifier(name="fn")]),
# parameters=[],
# doxygen="/// fn comment",
# )
# ],
# variables=[
# Variable(
# name=PQName(segments=[NameSpecifier(name="v1")]),
# type=Type(
# typename=PQName(segments=[FundamentalSpecifier(name="int")])
# ),
# value=Value(tokens=[Token(value="0")]),
# doxygen="/// var comment",
# ),
# Variable(
# name=PQName(segments=[NameSpecifier(name="v2")]),
# type=Type(
# typename=PQName(segments=[FundamentalSpecifier(name="int")])
# ),
# value=Value(tokens=[Token(value="0")]),
# ),
# ],
# )
# )

649
tests/test_enum.py Normal file
View File

@@ -0,0 +1,649 @@
from cxxheaderparser.types import (
AnonymousName,
ClassDecl,
EnumDecl,
Enumerator,
Field,
ForwardDecl,
Function,
FundamentalSpecifier,
NameSpecifier,
PQName,
Parameter,
Pointer,
Token,
Type,
Typedef,
Value,
Variable,
)
from cxxheaderparser.simple import (
ClassScope,
NamespaceScope,
parse_string,
ParsedData,
)
def test_basic_enum():
content = """
enum Foo {
A,
B,
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(
segments=[NameSpecifier(name="Foo")], classkey="enum"
),
values=[Enumerator(name="A"), Enumerator(name="B")],
)
]
)
)
def test_enum_w_expr():
content = """
enum Foo {
A = (1 / 2),
B = 3,
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(
segments=[NameSpecifier(name="Foo")], classkey="enum"
),
values=[
Enumerator(
name="A",
value=Value(
tokens=[
Token(value="("),
Token(value="1"),
Token(value="/"),
Token(value="2"),
Token(value=")"),
]
),
),
Enumerator(name="B", value=Value(tokens=[Token(value="3")])),
],
)
]
)
)
def test_enum_w_multiline_expr():
content = r"""
// clang-format off
enum Author
{
NAME = ('J' << 24 | \
'A' << 16 | \
'S' << 8 | \
'H'),
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(
segments=[NameSpecifier(name="Author")], classkey="enum"
),
values=[
Enumerator(
name="NAME",
value=Value(
tokens=[
Token(value="("),
Token(value="'J'"),
Token(value="<<"),
Token(value="24"),
Token(value="|"),
Token(value="\\"),
Token(value="'A'"),
Token(value="<<"),
Token(value="16"),
Token(value="|"),
Token(value="\\"),
Token(value="'S'"),
Token(value="<<"),
Token(value="8"),
Token(value="|"),
Token(value="\\"),
Token(value="'H'"),
Token(value=")"),
]
),
)
],
)
]
)
)
def test_basic_enum_class():
content = """
enum class BE { BEX };
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(
segments=[NameSpecifier(name="BE")], classkey="enum class"
),
values=[Enumerator(name="BEX")],
)
]
)
)
def test_basic_enum_struct():
content = """
enum struct BE { BEX };
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(
segments=[NameSpecifier(name="BE")], classkey="enum struct"
),
values=[Enumerator(name="BEX")],
)
]
)
)
def test_enum_base():
content = """
enum class E : int {};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(
segments=[NameSpecifier(name="E")], classkey="enum class"
),
values=[],
base=PQName(segments=[FundamentalSpecifier(name="int")]),
)
]
)
)
# instances
def test_enum_instance_1():
content = """
enum class BE { BEX } be1;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(
segments=[NameSpecifier(name="BE")], classkey="enum class"
),
values=[Enumerator(name="BEX")],
)
],
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="be1")]),
type=Type(
typename=PQName(
segments=[NameSpecifier(name="BE")], classkey="enum class"
)
),
)
],
)
)
def test_enum_instance_2():
content = """
enum class BE { BEX } be1, *be2;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(
segments=[NameSpecifier(name="BE")], classkey="enum class"
),
values=[Enumerator(name="BEX")],
)
],
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="be1")]),
type=Type(
typename=PQName(
segments=[NameSpecifier(name="BE")], classkey="enum class"
)
),
),
Variable(
name=PQName(segments=[NameSpecifier(name="be2")]),
type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[NameSpecifier(name="BE")],
classkey="enum class",
)
)
),
),
],
)
)
# bases in namespaces
def test_enum_base_in_ns():
content = """
namespace EN {
typedef int EINT;
};
enum class BE : EN::EINT { BEX };
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(
segments=[NameSpecifier(name="BE")], classkey="enum class"
),
values=[Enumerator(name="BEX")],
base=PQName(
segments=[NameSpecifier(name="EN"), NameSpecifier(name="EINT")]
),
)
],
namespaces={
"EN": NamespaceScope(
name="EN",
typedefs=[
Typedef(
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
name="EINT",
)
],
)
},
)
)
# forward declarations
def test_enum_fwd():
content = """
enum class BE1;
enum class BE2 : EN::EINT;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
forward_decls=[
ForwardDecl(
typename=PQName(
segments=[NameSpecifier(name="BE1")], classkey="enum class"
)
),
ForwardDecl(
typename=PQName(
segments=[NameSpecifier(name="BE2")], classkey="enum class"
),
enum_base=PQName(
segments=[NameSpecifier(name="EN"), NameSpecifier(name="EINT")]
),
),
]
)
)
def test_enum_private_in_class():
content = """
class C {
enum E { E1 };
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="C")], classkey="class"
)
),
enums=[
EnumDecl(
typename=PQName(
segments=[NameSpecifier(name="E")], classkey="enum"
),
values=[Enumerator(name="E1")],
access="private",
)
],
)
]
)
)
def test_enum_public_in_class():
content = """
class C {
public:
enum E { E1 };
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="C")], classkey="class"
)
),
enums=[
EnumDecl(
typename=PQName(
segments=[NameSpecifier(name="E")], classkey="enum"
),
values=[Enumerator(name="E1")],
access="public",
)
],
)
]
)
)
def test_default_enum():
content = """
class A {
enum {
v1,
v2,
} m_v1 = v1;
enum { vv1, vv2, vv3 } m_v2 = vv2, m_v3 = vv3;
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="A")], classkey="class"
)
),
enums=[
EnumDecl(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="enum"
),
values=[Enumerator(name="v1"), Enumerator(name="v2")],
access="private",
),
EnumDecl(
typename=PQName(
segments=[AnonymousName(id=2)], classkey="enum"
),
values=[
Enumerator(name="vv1"),
Enumerator(name="vv2"),
Enumerator(name="vv3"),
],
access="private",
),
],
fields=[
Field(
access="private",
type=Type(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="enum"
)
),
name="m_v1",
value=Value(tokens=[Token(value="v1")]),
),
Field(
access="private",
type=Type(
typename=PQName(
segments=[AnonymousName(id=2)], classkey="enum"
)
),
name="m_v2",
value=Value(tokens=[Token(value="vv2")]),
),
Field(
access="private",
type=Type(
typename=PQName(
segments=[AnonymousName(id=2)], classkey="enum"
)
),
name="m_v3",
value=Value(tokens=[Token(value="vv3")]),
),
],
)
]
)
)
def test_enum_template_vals():
content = """
enum {
IsRandomAccess = std::is_base_of<std::random_access_iterator_tag,
IteratorCategoryT>::value,
IsBidirectional = std::is_base_of<std::bidirectional_iterator_tag,
IteratorCategoryT>::value,
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(segments=[AnonymousName(id=1)], classkey="enum"),
values=[
Enumerator(
name="IsRandomAccess",
value=Value(
tokens=[
Token(value="std"),
Token(value="::"),
Token(value="is_base_of"),
Token(value="<"),
Token(value="std"),
Token(value="::"),
Token(value="random_access_iterator_tag"),
Token(value=","),
Token(value="IteratorCategoryT"),
Token(value=">"),
Token(value="::"),
Token(value="value"),
]
),
),
Enumerator(
name="IsBidirectional",
value=Value(
tokens=[
Token(value="std"),
Token(value="::"),
Token(value="is_base_of"),
Token(value="<"),
Token(value="std"),
Token(value="::"),
Token(value="bidirectional_iterator_tag"),
Token(value=","),
Token(value="IteratorCategoryT"),
Token(value=">"),
Token(value="::"),
Token(value="value"),
]
),
),
],
)
]
)
)
def test_enum_fn():
content = """
enum E {
VALUE,
};
void fn_with_enum_param1(const enum E e);
void fn_with_enum_param2(const enum E e) {
// code here
}
enum E fn_with_enum_retval1(void);
enum E fn_with_enum_retval2(void) {
// code here
}
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(
segments=[NameSpecifier(name="E")], classkey="enum"
),
values=[Enumerator(name="VALUE")],
)
],
functions=[
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="void")])
),
name=PQName(segments=[NameSpecifier(name="fn_with_enum_param1")]),
parameters=[
Parameter(
type=Type(
typename=PQName(
segments=[NameSpecifier(name="E")], classkey="enum"
),
const=True,
),
name="e",
)
],
),
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="void")])
),
name=PQName(segments=[NameSpecifier(name="fn_with_enum_param2")]),
parameters=[
Parameter(
type=Type(
typename=PQName(
segments=[NameSpecifier(name="E")], classkey="enum"
),
const=True,
),
name="e",
)
],
has_body=True,
),
Function(
return_type=Type(
typename=PQName(
segments=[NameSpecifier(name="E")], classkey="enum"
)
),
name=PQName(segments=[NameSpecifier(name="fn_with_enum_retval1")]),
parameters=[],
),
Function(
return_type=Type(
typename=PQName(
segments=[NameSpecifier(name="E")], classkey="enum"
)
),
name=PQName(segments=[NameSpecifier(name="fn_with_enum_retval2")]),
parameters=[],
has_body=True,
),
],
)
)

506
tests/test_fn.py Normal file
View File

@@ -0,0 +1,506 @@
# Note: testcases generated via `python -m cxxheaderparser.gentest`
from cxxheaderparser.types import (
Array,
AutoSpecifier,
Function,
FundamentalSpecifier,
NameSpecifier,
PQName,
Parameter,
Pointer,
Reference,
TemplateArgument,
TemplateDecl,
TemplateSpecialization,
TemplateTypeParam,
Token,
Type,
)
from cxxheaderparser.simple import (
NamespaceScope,
parse_string,
ParsedData,
)
def test_fn_returns_class():
content = """
class X *fn1();
struct Y fn2();
enum E fn3();
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[NameSpecifier(name="X")], classkey="class"
)
)
),
name=PQName(segments=[NameSpecifier(name="fn1")]),
parameters=[],
),
Function(
return_type=Type(
typename=PQName(
segments=[NameSpecifier(name="Y")], classkey="struct"
)
),
name=PQName(segments=[NameSpecifier(name="fn2")]),
parameters=[],
),
Function(
return_type=Type(
typename=PQName(
segments=[NameSpecifier(name="E")], classkey="enum"
)
),
name=PQName(segments=[NameSpecifier(name="fn3")]),
parameters=[],
),
]
)
)
def test_fn_pointer_params():
content = """
int fn1(int *);
int fn2(int *p);
int fn3(int(*p));
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
name=PQName(segments=[NameSpecifier(name="fn1")]),
parameters=[
Parameter(
type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
)
),
)
],
),
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
name=PQName(segments=[NameSpecifier(name="fn2")]),
parameters=[
Parameter(
name="p",
type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
)
),
)
],
),
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
name=PQName(segments=[NameSpecifier(name="fn3")]),
parameters=[
Parameter(
name="p",
type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
)
),
)
],
),
]
)
)
def test_fn_void_is_no_params():
content = """
int fn(void);
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
name=PQName(segments=[NameSpecifier(name="fn")]),
parameters=[],
)
]
)
)
def test_fn_array_param():
content = """
void fn(int array[]);
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="void")])
),
name=PQName(segments=[NameSpecifier(name="fn")]),
parameters=[
Parameter(
name="array",
type=Array(
array_of=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
size=None,
),
)
],
)
]
)
)
def test_fn_weird_refs():
content = """
int aref(int(&x));
void ptr_ref(int(*&name));
void ref_to_array(int (&array)[]);
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
name=PQName(segments=[NameSpecifier(name="aref")]),
parameters=[
Parameter(
name="x",
type=Reference(
ref_to=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
)
),
)
],
),
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="void")])
),
name=PQName(segments=[NameSpecifier(name="ptr_ref")]),
parameters=[
Parameter(
name="name",
type=Reference(
ref_to=Pointer(
ptr_to=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
)
)
),
)
],
),
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="void")])
),
name=PQName(segments=[NameSpecifier(name="ref_to_array")]),
parameters=[
Parameter(
name="array",
type=Reference(
ref_to=Array(
array_of=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
size=None,
)
),
)
],
),
]
)
)
def test_fn_too_many_parens():
content = """
int fn1(int (x));
void (fn2 (int (*const (name))));
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
name=PQName(segments=[NameSpecifier(name="fn1")]),
parameters=[
Parameter(
name="x",
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
)
],
),
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="void")])
),
name=PQName(segments=[NameSpecifier(name="fn2")]),
parameters=[
Parameter(
name="name",
type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
const=True,
),
)
],
),
]
)
)
# TODO calling conventions
"""
void __stdcall fn();
void (__stdcall * fn)
"""
def test_fn_same_line():
# multiple functions on the same line
content = """
void fn1(), fn2();
void *fn3(), fn4();
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="void")])
),
name=PQName(segments=[NameSpecifier(name="fn1")]),
parameters=[],
),
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="void")])
),
name=PQName(segments=[NameSpecifier(name="fn2")]),
parameters=[],
),
Function(
return_type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
)
),
name=PQName(segments=[NameSpecifier(name="fn3")]),
parameters=[],
),
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="void")])
),
name=PQName(segments=[NameSpecifier(name="fn4")]),
parameters=[],
),
]
)
)
def test_fn_auto_template():
content = """
template<class T, class U>
auto add(T t, U u) { return t + u; }
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Type(typename=PQName(segments=[AutoSpecifier()])),
name=PQName(segments=[NameSpecifier(name="add")]),
parameters=[
Parameter(
type=Type(
typename=PQName(segments=[NameSpecifier(name="T")])
),
name="t",
),
Parameter(
type=Type(
typename=PQName(segments=[NameSpecifier(name="U")])
),
name="u",
),
],
has_body=True,
template=TemplateDecl(
params=[
TemplateTypeParam(typekey="class", name="T"),
TemplateTypeParam(typekey="class", name="U"),
]
),
)
]
)
)
def test_fn_template_ptr():
content = """
std::vector<Pointer *> *fn(std::vector<Pointer *> *ps);
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[
NameSpecifier(name="std"),
NameSpecifier(
name="vector",
specialization=TemplateSpecialization(
args=[
TemplateArgument(
tokens=[
Token(value="Pointer"),
Token(value="*"),
]
)
]
),
),
]
)
)
),
name=PQName(segments=[NameSpecifier(name="fn")]),
parameters=[
Parameter(
type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[
NameSpecifier(name="std"),
NameSpecifier(
name="vector",
specialization=TemplateSpecialization(
args=[
TemplateArgument(
tokens=[
Token(value="Pointer"),
Token(value="*"),
]
)
]
),
),
]
)
)
),
name="ps",
)
],
)
]
)
)
def test_fn_with_impl():
content = """
// clang-format off
void termite(void)
{
return ((structA*) (Func())->element);
}
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="void")])
),
name=PQName(segments=[NameSpecifier(name="termite")]),
parameters=[],
has_body=True,
)
]
)
)

382
tests/test_friends.py Normal file
View File

@@ -0,0 +1,382 @@
# Note: testcases generated via `python -m cxxheaderparser.gentest`
from cxxheaderparser.types import (
ClassDecl,
Field,
ForwardDecl,
FriendDecl,
FundamentalSpecifier,
Method,
NameSpecifier,
PQName,
Parameter,
Reference,
TemplateDecl,
TemplateTypeParam,
Type,
)
from cxxheaderparser.simple import (
ClassScope,
NamespaceScope,
parse_string,
ParsedData,
)
# friends
def test_various_friends():
content = """
class FX {
public:
FX(char);
~FX();
void fn() const;
};
class FF {
friend class FX;
friend FX::FX(char), FX::~FX();
friend void FX::fn() const;
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="FX")], classkey="class"
)
),
methods=[
Method(
return_type=None,
name=PQName(segments=[NameSpecifier(name="FX")]),
parameters=[
Parameter(
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="char")]
)
)
)
],
access="public",
constructor=True,
),
Method(
return_type=None,
name=PQName(segments=[NameSpecifier(name="~FX")]),
parameters=[],
access="public",
destructor=True,
),
Method(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="fn")]),
parameters=[],
access="public",
const=True,
),
],
),
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="FF")], classkey="class"
)
),
friends=[
FriendDecl(
cls=ForwardDecl(
typename=PQName(
segments=[NameSpecifier(name="FX")],
classkey="class",
),
access="private",
)
),
FriendDecl(
fn=Method(
return_type=None,
name=PQName(
segments=[
NameSpecifier(name="FX"),
NameSpecifier(name="FX"),
]
),
parameters=[
Parameter(
type=Type(
typename=PQName(
segments=[
FundamentalSpecifier(name="char")
]
)
)
)
],
access="private",
constructor=True,
)
),
FriendDecl(
fn=Method(
return_type=Type(
typename=PQName(
segments=[
NameSpecifier(name="FX"),
NameSpecifier(name="FX"),
]
)
),
name=PQName(
segments=[
NameSpecifier(name="FX"),
NameSpecifier(name="~FX"),
]
),
parameters=[],
access="private",
)
),
FriendDecl(
fn=Method(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(
segments=[
NameSpecifier(name="FX"),
NameSpecifier(name="fn"),
]
),
parameters=[],
access="private",
const=True,
)
),
],
),
]
)
)
def test_more_friends():
content = """
template <typename T> struct X { static int x; };
struct BFF {
void fn() const;
};
struct F {
friend enum B;
friend void BFF::fn() const;
template <typename T> friend class X;
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="X")], classkey="struct"
),
template=TemplateDecl(
params=[TemplateTypeParam(typekey="typename", name="T")]
),
),
fields=[
Field(
name="x",
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
access="public",
static=True,
)
],
),
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="BFF")], classkey="struct"
)
),
methods=[
Method(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="fn")]),
parameters=[],
access="public",
const=True,
)
],
),
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="F")], classkey="struct"
)
),
friends=[
FriendDecl(
cls=ForwardDecl(
typename=PQName(
segments=[NameSpecifier(name="B")], classkey="enum"
),
access="public",
)
),
FriendDecl(
fn=Method(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(
segments=[
NameSpecifier(name="BFF"),
NameSpecifier(name="fn"),
]
),
parameters=[],
access="public",
const=True,
)
),
FriendDecl(
cls=ForwardDecl(
typename=PQName(
segments=[NameSpecifier(name="X")], classkey="class"
),
template=TemplateDecl(
params=[
TemplateTypeParam(typekey="typename", name="T")
]
),
access="public",
)
),
],
),
]
)
)
def test_friend_type_no_class():
content = """
class DogClass;
class CatClass {
friend DogClass;
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="CatClass")], classkey="class"
)
),
friends=[
FriendDecl(
cls=ForwardDecl(
typename=PQName(
segments=[NameSpecifier(name="DogClass")]
),
access="private",
)
)
],
)
],
forward_decls=[
ForwardDecl(
typename=PQName(
segments=[NameSpecifier(name="DogClass")], classkey="class"
)
)
],
)
)
def test_friend_with_impl():
content = """
// clang-format off
class Garlic {
public:
friend int genNum(C& a)
{
return obj.meth().num();
}
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="Garlic")], classkey="class"
)
),
friends=[
FriendDecl(
fn=Method(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
name=PQName(segments=[NameSpecifier(name="genNum")]),
parameters=[
Parameter(
type=Reference(
ref_to=Type(
typename=PQName(
segments=[NameSpecifier(name="C")]
)
)
),
name="a",
)
],
has_body=True,
access="public",
)
)
],
)
]
)
)

170
tests/test_misc.py Normal file
View File

@@ -0,0 +1,170 @@
# Note: testcases generated via `python -m cxxheaderparser.gentest`
from cxxheaderparser.types import (
Function,
FundamentalSpecifier,
NameSpecifier,
PQName,
Parameter,
Type,
Variable,
)
from cxxheaderparser.simple import (
Include,
NamespaceScope,
Pragma,
parse_string,
ParsedData,
Define,
)
#
# minimal preprocessor support
#
def test_define():
content = """
#define simple
#define complex(thing) stuff(thing)
# define spaced
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
defines=[
Define(content="simple"),
Define(content="complex(thing) stuff(thing)"),
Define(content="spaced"),
],
)
def test_includes():
content = """
#include <global.h>
#include "local.h"
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(includes=[Include("<global.h>"), Include('"local.h"')])
def test_pragma():
content = """
#pragma once
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(pragmas=[Pragma(content="once")])
#
# extern "C"
#
def test_extern_c():
content = """
extern "C" {
int x;
};
int y;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="x")]),
type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
),
Variable(
name=PQName(segments=[NameSpecifier(name="y")]),
type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
),
]
)
)
def test_misc_extern_inline():
content = """
extern "C++" {
inline HAL_Value HAL_GetSimValue(HAL_SimValueHandle handle) {
HAL_Value v;
return v;
}
} // extern "C++"
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Type(
typename=PQName(segments=[NameSpecifier(name="HAL_Value")])
),
name=PQName(segments=[NameSpecifier(name="HAL_GetSimValue")]),
parameters=[
Parameter(
type=Type(
typename=PQName(
segments=[NameSpecifier(name="HAL_SimValueHandle")]
)
),
name="handle",
)
],
inline=True,
has_body=True,
)
]
)
)
#
# Misc
#
def test_static_assert_1():
# static_assert should be ignored
content = """
static_assert(x == 1);
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData()
def test_static_assert_2():
# static_assert should be ignored
content = """
static_assert(sizeof(int) == 4,
"integer size is wrong"
"for some reason");
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData()
def test_comment_eof():
content = """
namespace a {} // namespace a"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(namespaces={"a": NamespaceScope(name="a")})
)

121
tests/test_namespaces.py Normal file
View File

@@ -0,0 +1,121 @@
# Note: testcases generated via `python -m cxxheaderparser.gentest`
from cxxheaderparser.types import (
FundamentalSpecifier,
NameSpecifier,
PQName,
Token,
Type,
Value,
Variable,
)
from cxxheaderparser.simple import (
NamespaceScope,
parse_string,
ParsedData,
)
def test_dups_in_different_ns():
content = """
namespace {
int x = 4;
}
int x = 5;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="x")]),
type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
value=Value(tokens=[Token(value="5")]),
)
],
namespaces={
"": NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="x")]),
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
value=Value(tokens=[Token(value="4")]),
)
]
)
},
)
)
def test_correct_ns():
content = """
namespace a::b::c {
int i1;
}
namespace a {
namespace b {
namespace c {
int i2;
}
}
}
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
namespaces={
"a": NamespaceScope(
name="a",
namespaces={
"b": NamespaceScope(
name="b",
namespaces={
"c": NamespaceScope(
name="c",
variables=[
Variable(
name=PQName(
segments=[NameSpecifier(name="i1")]
),
type=Type(
typename=PQName(
segments=[
FundamentalSpecifier(name="int")
]
)
),
),
Variable(
name=PQName(
segments=[NameSpecifier(name="i2")]
),
type=Type(
typename=PQName(
segments=[
FundamentalSpecifier(name="int")
]
)
),
),
],
)
},
)
},
)
}
)
)

554
tests/test_operators.py Normal file
View File

@@ -0,0 +1,554 @@
# Note: testcases generated via `python -m cxxheaderparser.gentest`
from cxxheaderparser.types import (
ClassDecl,
FundamentalSpecifier,
NameSpecifier,
Operator,
PQName,
Parameter,
Reference,
Type,
)
from cxxheaderparser.simple import (
ClassScope,
NamespaceScope,
parse_string,
ParsedData,
)
def test_class_operators():
content = r"""
class OperatorClass {
public:
void operator=(const Sample25Class &);
void operator-=(const Sample25Class &);
void operator+=();
void operator[]();
bool operator==(const int &b);
OperatorClass &operator+();
void operator-();
void operator*();
void operator\();
void operator%();
void operator^();
void operator|();
void operator&();
void operator~();
void operator<<();
void operator>>();
void operator!=();
void operator<();
void operator>();
void operator>=();
void operator<=();
void operator!();
void operator&&();
void operator||();
void operator+=();
void operator-=();
void operator*=();
void operator\=();
void operator%=();
void operator&=();
void operator|=();
void operator^=();
void operator<<=();
void operator>>=();
void operator++();
void operator--();
void operator()();
void operator->();
void operator,();
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="OperatorClass")],
classkey="class",
)
),
methods=[
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator=")]),
parameters=[
Parameter(
type=Reference(
ref_to=Type(
typename=PQName(
segments=[
NameSpecifier(name="Sample25Class")
]
),
const=True,
)
)
)
],
access="public",
operator="=",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator-=")]),
parameters=[
Parameter(
type=Reference(
ref_to=Type(
typename=PQName(
segments=[
NameSpecifier(name="Sample25Class")
]
),
const=True,
)
)
)
],
access="public",
operator="-=",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator+=")]),
parameters=[],
access="public",
operator="+=",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator[]")]),
parameters=[],
access="public",
operator="[]",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="bool")]
)
),
name=PQName(segments=[NameSpecifier(name="operator==")]),
parameters=[
Parameter(
type=Reference(
ref_to=Type(
typename=PQName(
segments=[
FundamentalSpecifier(name="int")
]
),
const=True,
)
),
name="b",
)
],
access="public",
operator="==",
),
Operator(
return_type=Reference(
ref_to=Type(
typename=PQName(
segments=[NameSpecifier(name="OperatorClass")]
)
)
),
name=PQName(segments=[NameSpecifier(name="operator+")]),
parameters=[],
access="public",
operator="+",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator-")]),
parameters=[],
access="public",
operator="-",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator*")]),
parameters=[],
access="public",
operator="*",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator\\")]),
parameters=[],
access="public",
operator="\\",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator%")]),
parameters=[],
access="public",
operator="%",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator^")]),
parameters=[],
access="public",
operator="^",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator|")]),
parameters=[],
access="public",
operator="|",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator&")]),
parameters=[],
access="public",
operator="&",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator~")]),
parameters=[],
access="public",
operator="~",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator<<")]),
parameters=[],
access="public",
operator="<<",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator>>")]),
parameters=[],
access="public",
operator=">>",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator!=")]),
parameters=[],
access="public",
operator="!=",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator<")]),
parameters=[],
access="public",
operator="<",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator>")]),
parameters=[],
access="public",
operator=">",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator>=")]),
parameters=[],
access="public",
operator=">=",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator<=")]),
parameters=[],
access="public",
operator="<=",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator!")]),
parameters=[],
access="public",
operator="!",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator&&")]),
parameters=[],
access="public",
operator="&&",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator||")]),
parameters=[],
access="public",
operator="||",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator+=")]),
parameters=[],
access="public",
operator="+=",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator-=")]),
parameters=[],
access="public",
operator="-=",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator*=")]),
parameters=[],
access="public",
operator="*=",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator\\=")]),
parameters=[],
access="public",
operator="\\=",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator%=")]),
parameters=[],
access="public",
operator="%=",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator&=")]),
parameters=[],
access="public",
operator="&=",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator|=")]),
parameters=[],
access="public",
operator="|=",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator^=")]),
parameters=[],
access="public",
operator="^=",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator<<=")]),
parameters=[],
access="public",
operator="<<=",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator>>=")]),
parameters=[],
access="public",
operator=">>=",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator++")]),
parameters=[],
access="public",
operator="++",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator--")]),
parameters=[],
access="public",
operator="--",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator()")]),
parameters=[],
access="public",
operator="()",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator->")]),
parameters=[],
access="public",
operator="->",
),
Operator(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="operator,")]),
parameters=[],
access="public",
operator=",",
),
],
)
]
)
)

1290
tests/test_template.py Normal file

File diff suppressed because it is too large Load Diff

52
tests/test_tokfmt.py Normal file
View File

@@ -0,0 +1,52 @@
import pytest
from cxxheaderparser.lexer import Lexer
from cxxheaderparser.tokfmt import tokfmt
@pytest.mark.parametrize(
"instr",
[
"int",
"unsigned int",
"::uint8_t",
"void *",
"const char *",
"const char[]",
"void * (*)()",
"void (*)(void * buf, int buflen)",
"void (* fnType)(void * buf, int buflen)",
"TypeName<int, void>& x",
"vector<string>&",
"std::vector<Pointer *> *",
"Alpha::Omega",
"Convoluted::Nested::Mixin",
"std::function<void ()>",
"std::shared_ptr<std::function<void (void)>>",
"tr1::shared_ptr<SnailTemplateClass<SnailNamespace::SnailClass>>",
"std::map<unsigned, std::pair<unsigned, SnailTemplateClass<SnailNamespace::SnailClass>>>",
"std::is_base_of<std::random_access_iterator_tag, IteratorCategoryT>::value",
"const char&&",
"something<T, U>{1, 2, 3}",
"operator-=",
"operator[]",
"operator*",
"operator>=",
],
)
def test_tokfmt(instr):
"""
Each input string is exactly what the output of tokfmt should be
"""
toks = []
lexer = Lexer("")
lexer.input(instr)
while True:
tok = lexer.token_eof_ok()
if not tok:
break
toks.append(tok)
assert tokfmt(toks) == instr

870
tests/test_typedef.py Normal file
View File

@@ -0,0 +1,870 @@
# Note: testcases generated via `python -m cxxheaderparser.gentest`
from cxxheaderparser.types import (
AnonymousName,
Array,
BaseClass,
ClassDecl,
EnumDecl,
Enumerator,
Field,
FunctionType,
FundamentalSpecifier,
NameSpecifier,
PQName,
Parameter,
Pointer,
Reference,
TemplateArgument,
TemplateSpecialization,
Token,
Type,
Typedef,
Value,
)
from cxxheaderparser.simple import ClassScope, NamespaceScope, ParsedData, parse_string
def test_simple_typedef():
content = """
typedef std::vector<int> IntVector;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
typedefs=[
Typedef(
type=Type(
typename=PQName(
segments=[
NameSpecifier(name="std"),
NameSpecifier(
name="vector",
specialization=TemplateSpecialization(
args=[
TemplateArgument(
tokens=[Token(value="int")]
)
]
),
),
]
)
),
name="IntVector",
)
]
)
)
def test_struct_typedef_1():
content = """
typedef struct {
int m;
} unnamed_struct, *punnamed_struct;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="struct"
)
),
fields=[
Field(
name="m",
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
access="public",
)
],
)
],
typedefs=[
Typedef(
type=Type(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="struct"
)
),
name="unnamed_struct",
),
Typedef(
type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="struct"
)
)
),
name="punnamed_struct",
),
],
)
)
def test_struct_typedef_2():
content = """
typedef struct {
int m;
} * punnamed_struct, unnamed_struct;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="struct"
)
),
fields=[
Field(
name="m",
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
access="public",
)
],
)
],
typedefs=[
Typedef(
type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="struct"
)
)
),
name="punnamed_struct",
),
Typedef(
type=Type(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="struct"
)
),
name="unnamed_struct",
),
],
)
)
def test_typedef_array():
content = """
typedef char TenCharArray[10];
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
typedefs=[
Typedef(
type=Array(
array_of=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="char")]
)
),
size=Value(tokens=[Token(value="10")]),
),
name="TenCharArray",
)
]
)
)
def test_typedef_array_of_struct():
content = """
typedef struct{} tx[3], ty;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="struct"
)
)
)
],
typedefs=[
Typedef(
type=Array(
array_of=Type(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="struct"
)
),
size=Value(tokens=[Token(value="3")]),
),
name="tx",
),
Typedef(
type=Type(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="struct"
)
),
name="ty",
),
],
)
)
def test_typedef_class_w_base():
content = """
typedef class XX : public F {} G;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="XX")], classkey="class"
),
bases=[
BaseClass(
access="public",
typename=PQName(segments=[NameSpecifier(name="F")]),
)
],
)
)
],
typedefs=[
Typedef(
type=Type(
typename=PQName(
segments=[NameSpecifier(name="XX")], classkey="class"
)
),
name="G",
)
],
)
)
def test_complicated_typedef():
content = """
typedef int int_t, *intp_t, (&fp)(int, ulong), arr_t[10];
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
typedefs=[
Typedef(
type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
name="int_t",
),
Typedef(
type=Pointer(
ptr_to=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
)
),
name="intp_t",
),
Typedef(
type=Reference(
ref_to=FunctionType(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
parameters=[
Parameter(
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
)
),
Parameter(
type=Type(
typename=PQName(
segments=[NameSpecifier(name="ulong")]
)
)
),
],
)
),
name="fp",
),
Typedef(
type=Array(
array_of=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
size=Value(tokens=[Token(value="10")]),
),
name="arr_t",
),
]
)
)
def test_typedef_c_struct_idiom():
content = """
// common C idiom to avoid having to write "struct S"
typedef struct {int a; int b;} S, *pS;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="struct"
)
),
fields=[
Field(
name="a",
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
access="public",
),
Field(
name="b",
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
access="public",
),
],
)
],
typedefs=[
Typedef(
type=Type(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="struct"
)
),
name="S",
),
Typedef(
type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="struct"
)
)
),
name="pS",
),
],
)
)
def test_typedef_struct_same_name():
content = """
typedef struct Fig {
int a;
} Fig;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="Fig")], classkey="struct"
)
),
fields=[
Field(
access="public",
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
name="a",
)
],
)
],
typedefs=[
Typedef(
type=Type(
typename=PQName(
segments=[NameSpecifier(name="Fig")], classkey="struct"
)
),
name="Fig",
)
],
)
)
def test_typedef_struct_w_enum():
content = """
typedef struct {
enum BeetEnum : int { FAIL = 0, PASS = 1 };
} BeetStruct;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="struct"
)
),
enums=[
EnumDecl(
typename=PQName(
segments=[NameSpecifier(name="BeetEnum")],
classkey="enum",
),
values=[
Enumerator(
name="FAIL", value=Value(tokens=[Token(value="0")])
),
Enumerator(
name="PASS", value=Value(tokens=[Token(value="1")])
),
],
base=PQName(segments=[FundamentalSpecifier(name="int")]),
access="public",
)
],
)
],
typedefs=[
Typedef(
type=Type(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="struct"
)
),
name="BeetStruct",
)
],
)
)
def test_typedef_union():
content = """
typedef union apricot_t {
int i;
float f;
char s[20];
} Apricot;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="apricot_t")], classkey="union"
)
),
fields=[
Field(
access="public",
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
name="i",
),
Field(
access="public",
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="float")]
)
),
name="f",
),
Field(
access="public",
type=Array(
array_of=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="char")]
)
),
size=Value(tokens=[Token(value="20")]),
),
name="s",
),
],
)
],
typedefs=[
Typedef(
type=Type(
typename=PQName(
segments=[NameSpecifier(name="apricot_t")], classkey="union"
)
),
name="Apricot",
)
],
)
)
def test_typedef_fnptr():
content = """
typedef void *(*fndef)(int);
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
typedefs=[
Typedef(
type=Pointer(
ptr_to=FunctionType(
return_type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
)
),
parameters=[
Parameter(
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
)
)
],
)
),
name="fndef",
)
]
)
)
def test_typedef_const():
content = """
typedef int theint, *const ptheint;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
typedefs=[
Typedef(
type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
name="theint",
),
Typedef(
type=Pointer(
ptr_to=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
const=True,
),
name="ptheint",
),
]
)
)
def test_enum_typedef_1():
content = """
typedef enum {} E;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(segments=[AnonymousName(id=1)], classkey="enum"),
values=[],
)
],
typedefs=[
Typedef(
type=Type(
typename=PQName(segments=[AnonymousName(id=1)], classkey="enum")
),
name="E",
)
],
)
)
def test_enum_typedef_2():
content = """
typedef enum { E1 } BE;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(segments=[AnonymousName(id=1)], classkey="enum"),
values=[Enumerator(name="E1")],
)
],
typedefs=[
Typedef(
type=Type(
typename=PQName(segments=[AnonymousName(id=1)], classkey="enum")
),
name="BE",
)
],
)
)
def test_enum_typedef_3():
content = """
typedef enum { E1, E2, } E;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(segments=[AnonymousName(id=1)], classkey="enum"),
values=[Enumerator(name="E1"), Enumerator(name="E2")],
)
],
typedefs=[
Typedef(
type=Type(
typename=PQName(segments=[AnonymousName(id=1)], classkey="enum")
),
name="E",
)
],
)
)
def test_enum_typedef_3():
content = """
typedef enum { E1 } * PBE;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(segments=[AnonymousName(id=1)], classkey="enum"),
values=[Enumerator(name="E1")],
)
],
typedefs=[
Typedef(
type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="enum"
)
)
),
name="PBE",
)
],
)
)
def test_enum_typedef_4():
content = """
typedef enum { E1 } * PBE, BE;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(segments=[AnonymousName(id=1)], classkey="enum"),
values=[Enumerator(name="E1")],
)
],
typedefs=[
Typedef(
type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="enum"
)
)
),
name="PBE",
),
Typedef(
type=Type(
typename=PQName(segments=[AnonymousName(id=1)], classkey="enum")
),
name="BE",
),
],
)
)
def test_enum_typedef_5():
content = """
typedef enum { E1 } BE, *PBE;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(segments=[AnonymousName(id=1)], classkey="enum"),
values=[Enumerator(name="E1")],
)
],
typedefs=[
Typedef(
type=Type(
typename=PQName(segments=[AnonymousName(id=1)], classkey="enum")
),
name="BE",
),
Typedef(
type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="enum"
)
)
),
name="PBE",
),
],
)
)
def test_enum_typedef_fwd():
content = """
typedef enum BE BET;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
typedefs=[
Typedef(
type=Type(
typename=PQName(
segments=[NameSpecifier(name="BE")], classkey="enum"
)
),
name="BET",
)
]
)
)
def test_typedef_enum_expr():
content = """
typedef enum { StarFruit = (2 + 2) / 2 } Carambola;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(segments=[AnonymousName(id=1)], classkey="enum"),
values=[
Enumerator(
name="StarFruit",
value=Value(
tokens=[
Token(value="("),
Token(value="2"),
Token(value="+"),
Token(value="2"),
Token(value=")"),
Token(value="/"),
Token(value="2"),
]
),
)
],
)
],
typedefs=[
Typedef(
type=Type(
typename=PQName(segments=[AnonymousName(id=1)], classkey="enum")
),
name="Carambola",
)
],
)
)

154
tests/test_union.py Normal file
View File

@@ -0,0 +1,154 @@
# Note: testcases generated via `python -m cxxheaderparser.gentest`
from cxxheaderparser.types import (
AnonymousName,
ClassDecl,
Field,
FundamentalSpecifier,
NameSpecifier,
PQName,
Type,
)
from cxxheaderparser.simple import (
ClassScope,
NamespaceScope,
parse_string,
ParsedData,
)
def test_union_basic():
content = """
struct HAL_Value {
union {
int v_int;
HAL_Bool v_boolean;
} data;
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="HAL_Value")],
classkey="struct",
)
),
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="union"
),
access="public",
),
fields=[
Field(
access="public",
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
name="v_int",
),
Field(
access="public",
type=Type(
typename=PQName(
segments=[NameSpecifier(name="HAL_Bool")]
)
),
name="v_boolean",
),
],
)
],
fields=[
Field(
access="public",
type=Type(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="union"
)
),
name="data",
)
],
)
]
)
)
def test_union_anon_in_struct():
content = """
struct Outer {
union {
int x;
int y;
};
int z;
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="Outer")], classkey="struct"
)
),
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[AnonymousName(id=1)], classkey="union"
),
access="public",
),
fields=[
Field(
access="public",
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
name="x",
),
Field(
access="public",
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
name="y",
),
],
)
],
fields=[
Field(
access="public",
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
name="z",
)
],
)
]
)
)

511
tests/test_using.py Normal file
View File

@@ -0,0 +1,511 @@
# Note: testcases generated via `python -m cxxheaderparser.gentest`
from cxxheaderparser.types import (
BaseClass,
ClassDecl,
Function,
FundamentalSpecifier,
Method,
NameSpecifier,
PQName,
Parameter,
Pointer,
Reference,
TemplateArgument,
TemplateDecl,
TemplateSpecialization,
TemplateTypeParam,
Token,
Type,
UsingAlias,
UsingDecl,
)
from cxxheaderparser.simple import (
ClassScope,
NamespaceScope,
UsingNamespace,
parse_string,
ParsedData,
)
def test_using_namespace():
content = """
using namespace foo;
using namespace foo::bar;
using namespace ::foo;
using namespace ::foo::bar;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
using_ns=[
UsingNamespace(ns="foo"),
UsingNamespace(ns="foo::bar"),
UsingNamespace(ns="::foo"),
UsingNamespace(ns="::foo::bar"),
]
)
)
def test_using_declaration():
content = """
using ::foo;
using foo::bar;
using ::foo::bar;
using typename ::foo::bar;
using typename foo::bar;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
using=[
UsingDecl(
typename=PQName(
segments=[NameSpecifier(name=""), NameSpecifier(name="foo")]
)
),
UsingDecl(
typename=PQName(
segments=[NameSpecifier(name="foo"), NameSpecifier(name="bar")]
)
),
UsingDecl(
typename=PQName(
segments=[
NameSpecifier(name=""),
NameSpecifier(name="foo"),
NameSpecifier(name="bar"),
]
)
),
UsingDecl(
typename=PQName(
segments=[
NameSpecifier(name=""),
NameSpecifier(name="foo"),
NameSpecifier(name="bar"),
]
)
),
UsingDecl(
typename=PQName(
segments=[NameSpecifier(name="foo"), NameSpecifier(name="bar")]
)
),
]
)
)
# alias-declaration
def test_alias_declaration_1():
content = """
using alias = foo;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
using_alias=[
UsingAlias(
alias="alias",
type=Type(typename=PQName(segments=[NameSpecifier(name="foo")])),
)
]
)
)
def test_alias_declaration_2():
content = """
template <typename T> using alias = foo<T>;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
using_alias=[
UsingAlias(
alias="alias",
type=Type(
typename=PQName(
segments=[
NameSpecifier(
name="foo",
specialization=TemplateSpecialization(
args=[
TemplateArgument(tokens=[Token(value="T")])
]
),
)
]
)
),
template=TemplateDecl(
params=[TemplateTypeParam(typekey="typename", name="T")]
),
)
]
)
)
def test_alias_declaration_3():
content = """
using alias = ::foo::bar;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
using_alias=[
UsingAlias(
alias="alias",
type=Type(
typename=PQName(
segments=[
NameSpecifier(name=""),
NameSpecifier(name="foo"),
NameSpecifier(name="bar"),
]
)
),
)
]
)
)
def test_alias_declaration_4():
content = """
template <typename T> using alias = ::foo::bar<T>;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
using_alias=[
UsingAlias(
alias="alias",
type=Type(
typename=PQName(
segments=[
NameSpecifier(name=""),
NameSpecifier(name="foo"),
NameSpecifier(
name="bar",
specialization=TemplateSpecialization(
args=[
TemplateArgument(tokens=[Token(value="T")])
]
),
),
]
)
),
template=TemplateDecl(
params=[TemplateTypeParam(typekey="typename", name="T")]
),
)
]
)
)
def test_alias_declaration_5():
content = """
using alias = foo::bar;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
using_alias=[
UsingAlias(
alias="alias",
type=Type(
typename=PQName(
segments=[
NameSpecifier(name="foo"),
NameSpecifier(name="bar"),
]
)
),
)
]
)
)
def test_alias_declaration_6():
content = """
template <typename T> using alias = foo<T>::bar;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
using_alias=[
UsingAlias(
alias="alias",
type=Type(
typename=PQName(
segments=[
NameSpecifier(
name="foo",
specialization=TemplateSpecialization(
args=[
TemplateArgument(tokens=[Token(value="T")])
]
),
),
NameSpecifier(name="bar"),
]
)
),
template=TemplateDecl(
params=[TemplateTypeParam(typekey="typename", name="T")]
),
)
]
)
)
def test_using_many_things():
content = """
// clang-format off
using std::thing;
using MyThing = SomeThing;
namespace a {
using std::string;
using VoidFunction = std::function<void()>;
void fn(string &s, VoidFunction fn, thing * t);
class A : public B {
public:
using B::B;
using IntFunction = std::function<int()>;
void a(string &s, IntFunction fn, thing * t);
};
}
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
using=[
UsingDecl(
typename=PQName(
segments=[
NameSpecifier(name="std"),
NameSpecifier(name="thing"),
]
)
)
],
using_alias=[
UsingAlias(
alias="MyThing",
type=Type(
typename=PQName(segments=[NameSpecifier(name="SomeThing")])
),
)
],
namespaces={
"a": NamespaceScope(
name="a",
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="A")], classkey="class"
),
bases=[
BaseClass(
access="public",
typename=PQName(
segments=[NameSpecifier(name="B")]
),
)
],
),
methods=[
Method(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="a")]),
parameters=[
Parameter(
type=Reference(
ref_to=Type(
typename=PQName(
segments=[
NameSpecifier(name="string")
]
)
)
),
name="s",
),
Parameter(
type=Type(
typename=PQName(
segments=[
NameSpecifier(
name="IntFunction"
)
]
)
),
name="fn",
),
Parameter(
type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[
NameSpecifier(name="thing")
]
)
)
),
name="t",
),
],
access="public",
)
],
using=[
UsingDecl(
typename=PQName(
segments=[
NameSpecifier(name="B"),
NameSpecifier(name="B"),
]
),
access="public",
)
],
using_alias=[
UsingAlias(
alias="IntFunction",
type=Type(
typename=PQName(
segments=[
NameSpecifier(name="std"),
NameSpecifier(
name="function",
specialization=TemplateSpecialization(
args=[
TemplateArgument(
tokens=[
Token(value="int"),
Token(value="("),
Token(value=")"),
]
)
]
),
),
]
)
),
access="public",
)
],
)
],
functions=[
Function(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="fn")]),
parameters=[
Parameter(
type=Reference(
ref_to=Type(
typename=PQName(
segments=[NameSpecifier(name="string")]
)
)
),
name="s",
),
Parameter(
type=Type(
typename=PQName(
segments=[
NameSpecifier(name="VoidFunction")
]
)
),
name="fn",
),
Parameter(
type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[NameSpecifier(name="thing")]
)
)
),
name="t",
),
],
)
],
using=[
UsingDecl(
typename=PQName(
segments=[
NameSpecifier(name="std"),
NameSpecifier(name="string"),
]
)
)
],
using_alias=[
UsingAlias(
alias="VoidFunction",
type=Type(
typename=PQName(
segments=[
NameSpecifier(name="std"),
NameSpecifier(
name="function",
specialization=TemplateSpecialization(
args=[
TemplateArgument(
tokens=[
Token(value="void"),
Token(value="("),
Token(value=")"),
]
)
]
),
),
]
)
),
)
],
)
},
)
)

768
tests/test_var.py Normal file
View File

@@ -0,0 +1,768 @@
# Note: testcases generated via `python -m cxxheaderparser.gentest`
from cxxheaderparser.types import (
Array,
ClassDecl,
EnumDecl,
Enumerator,
Field,
FunctionType,
FundamentalSpecifier,
NameSpecifier,
PQName,
Parameter,
Pointer,
Reference,
Token,
Type,
Value,
Variable,
)
from cxxheaderparser.simple import ClassScope, NamespaceScope, ParsedData, parse_string
def test_var_unixwiz_ridiculous():
# http://unixwiz.net/techtips/reading-cdecl.html
#
# .. "we have no idea how this variable is useful, but at least we can
# describe the type correctly"
content = """
char *(*(**foo[][8])())[];
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="foo")]),
type=Array(
array_of=Array(
array_of=Pointer(
ptr_to=Pointer(
ptr_to=FunctionType(
return_type=Pointer(
ptr_to=Array(
array_of=Pointer(
ptr_to=Type(
typename=PQName(
segments=[
FundamentalSpecifier(
name="char"
)
]
)
)
),
size=None,
)
),
parameters=[],
)
)
),
size=Value(tokens=[Token(value="8")]),
),
size=None,
),
)
]
)
)
def test_var_ptr_to_array15_of_ptr_to_int():
content = """
int *(*crocodile)[15];
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="crocodile")]),
type=Pointer(
ptr_to=Array(
array_of=Pointer(
ptr_to=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
)
),
size=Value(tokens=[Token(value="15")]),
)
),
)
]
)
)
def test_var_ref_to_array():
content = """
int abase[3];
int (&aname)[3] = abase;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="abase")]),
type=Array(
array_of=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
size=Value(tokens=[Token(value="3")]),
),
),
Variable(
name=PQName(segments=[NameSpecifier(name="aname")]),
type=Reference(
ref_to=Array(
array_of=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
size=Value(tokens=[Token(value="3")]),
)
),
value=Value(tokens=[Token(value="abase")]),
),
]
)
)
def test_var_ptr_to_array():
content = """
int zz, (*aname)[3] = &abase;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="zz")]),
type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
),
Variable(
name=PQName(segments=[NameSpecifier(name="aname")]),
type=Pointer(
ptr_to=Array(
array_of=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
size=Value(tokens=[Token(value="3")]),
)
),
value=Value(tokens=[Token(value="&"), Token(value="abase")]),
),
]
)
)
def test_var_multi_1():
content = """
int zz, (&aname)[3] = abase;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="zz")]),
type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
),
Variable(
name=PQName(segments=[NameSpecifier(name="aname")]),
type=Reference(
ref_to=Array(
array_of=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
size=Value(tokens=[Token(value="3")]),
)
),
value=Value(tokens=[Token(value="abase")]),
),
]
)
)
def test_var_array_of_fnptr_varargs():
content = """
void (*a3[3])(int, ...);
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="a3")]),
type=Array(
array_of=Pointer(
ptr_to=FunctionType(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
parameters=[
Parameter(
type=Type(
typename=PQName(
segments=[
FundamentalSpecifier(name="int")
]
)
)
)
],
vararg=True,
)
),
size=Value(tokens=[Token(value="3")]),
),
)
]
)
)
def test_var_double_fnptr_varargs():
content = """
void (*(*a4))(int, ...);
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="a4")]),
type=Pointer(
ptr_to=Pointer(
ptr_to=FunctionType(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
parameters=[
Parameter(
type=Type(
typename=PQName(
segments=[
FundamentalSpecifier(name="int")
]
)
)
)
],
vararg=True,
)
)
),
)
]
)
)
def test_var_fnptr_voidstar():
content = """
void(*(*a5)(int));
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="a5")]),
type=Pointer(
ptr_to=FunctionType(
return_type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
)
),
parameters=[
Parameter(
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
)
)
],
)
),
)
]
)
)
def test_var_fnptr_moreparens():
content = """
void (*x)(int(p1), int);
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="x")]),
type=Pointer(
ptr_to=FunctionType(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
parameters=[
Parameter(
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
name="p1",
),
Parameter(
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
)
),
],
)
),
)
]
)
)
# From pycparser:
# Pointer decls nest from inside out. This is important when different
# levels have different qualifiers. For example:
#
# char * const * p;
#
# Means "pointer to const pointer to char"
#
# While:
#
# char ** const p;
#
# Means "const pointer to pointer to char"
def test_var_ptr_to_const_ptr_to_char():
content = """
char *const *p;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="p")]),
type=Pointer(
ptr_to=Pointer(
ptr_to=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="char")]
)
),
const=True,
)
),
)
]
)
)
def test_var_const_ptr_to_ptr_to_char():
content = """
char **const p;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="p")]),
type=Pointer(
ptr_to=Pointer(
ptr_to=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="char")]
)
)
),
const=True,
),
)
]
)
)
def test_var_array_initializer1():
content = """
int x[3]{1, 2, 3};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="x")]),
type=Array(
array_of=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
size=Value(tokens=[Token(value="3")]),
),
value=Value(
tokens=[
Token(value="{"),
Token(value="1"),
Token(value=","),
Token(value="2"),
Token(value=","),
Token(value="3"),
Token(value="}"),
]
),
)
]
)
)
def test_var_array_initializer2():
content = """
int x[3] = {1, 2, 3};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="x")]),
type=Array(
array_of=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
size=Value(tokens=[Token(value="3")]),
),
value=Value(
tokens=[
Token(value="{"),
Token(value="1"),
Token(value=","),
Token(value="2"),
Token(value=","),
Token(value="3"),
Token(value="}"),
]
),
)
]
)
)
def test_var_extern_c():
content = """
extern "C" int x;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="x")]),
type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
# TODO: store linkage
extern=True,
)
]
)
)
def test_var_ns_1():
content = """
int N::x;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(
segments=[NameSpecifier(name="N"), NameSpecifier(name="x")]
),
type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
)
]
)
)
def test_var_ns_2():
content = """
int N::x = 4;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(
segments=[NameSpecifier(name="N"), NameSpecifier(name="x")]
),
type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
value=Value(tokens=[Token(value="4")]),
)
]
)
)
def test_var_ns_3():
content = """
int N::x{4};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(
segments=[NameSpecifier(name="N"), NameSpecifier(name="x")]
),
type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
value=Value(
tokens=[Token(value="{"), Token(value="4"), Token(value="}")]
),
)
]
)
)
def test_var_static_struct():
content = """
constexpr static struct SS {} s;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="SS")], classkey="struct"
)
)
)
],
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="s")]),
type=Type(
typename=PQName(
segments=[NameSpecifier(name="SS")], classkey="struct"
)
),
constexpr=True,
static=True,
)
],
)
)
def test_var_constexpr_enum():
content = """
constexpr enum E { EE } e = EE;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
enums=[
EnumDecl(
typename=PQName(
segments=[NameSpecifier(name="E")], classkey="enum"
),
values=[Enumerator(name="EE")],
)
],
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="e")]),
type=Type(
typename=PQName(
segments=[NameSpecifier(name="E")], classkey="enum"
)
),
value=Value(tokens=[Token(value="EE")]),
constexpr=True,
)
],
)
)
def test_var_fnptr_in_class():
content = """
struct DriverFuncs {
void *(*init)();
void (*write)(void *buf, int buflen);
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="DriverFuncs")],
classkey="struct",
)
),
fields=[
Field(
access="public",
type=Pointer(
ptr_to=FunctionType(
return_type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[
FundamentalSpecifier(name="void")
]
)
)
),
parameters=[],
)
),
name="init",
),
Field(
access="public",
type=Pointer(
ptr_to=FunctionType(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
parameters=[
Parameter(
type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[
FundamentalSpecifier(
name="void"
)
]
)
)
),
name="buf",
),
Parameter(
type=Type(
typename=PQName(
segments=[
FundamentalSpecifier(name="int")
]
)
),
name="buflen",
),
],
)
),
name="write",
),
],
)
]
)
)
def test_var_extern():
content = """
extern int externVar;
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
variables=[
Variable(
name=PQName(segments=[NameSpecifier(name="externVar")]),
type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
extern=True,
)
]
)
)