diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 0000000..a69c2a8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,21 @@ +name: Bug Report +description: We are no longer making fixes ourselves to robotpy-cppheaderparser, but we will accept pull requests with appropriately tested fixes. We recommend all users migrate to cxxheaderparser. +title: "[BUG]: " +body: + - type: textarea + id: description + attributes: + label: Problem description + placeholder: >- + Provide a short description, state the expected behavior and what + actually happens. + validations: + required: true + + - type: textarea + id: code + attributes: + label: Reproducible example code + placeholder: >- + Minimal code to reproduce this issue + render: text \ No newline at end of file diff --git a/.github/workflows/dist.yml b/.github/workflows/dist.yml new file mode 100644 index 0000000..95df148 --- /dev/null +++ b/.github/workflows/dist.yml @@ -0,0 +1,90 @@ +--- +name: dist + +on: [push, pull_request] + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: psf/black@stable + + check-doc: + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - uses: actions/setup-python@v4 + with: + python-version: 3.8 + - name: Sphinx + run: | + pip --disable-pip-version-check install -e . + pip --disable-pip-version-check install -r docs/requirements.txt + cd docs && make clean html SPHINXOPTS="-W --keep-going" + + test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [windows-latest, macos-13, ubuntu-20.04] + python_version: [3.8] + architecture: [x64] + exclude: + - os: macos-13 + architecture: x86 + - os: ubuntu-20.04 + architecture: x86 + + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python_version }} + architecture: ${{ matrix.architecture }} + + - name: Install build dependencies + run: python -m pip --disable-pip-version-check install wheel + + - name: Build wheel + run: python setup.py bdist_wheel + + - name: Test wheel + shell: bash + run: | + cd dist + python -m pip --disable-pip-version-check install *.whl + cd ../test + python test_CppHeaderParser.py + + publish: + runs-on: ubuntu-latest + needs: [check, check-doc, test] + if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') + permissions: + id-token: write + + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - uses: actions/setup-python@v4 + with: + python-version: 3.8 + - run: pip --disable-pip-version-check install wheel + + - name: Build packages + run: python setup.py sdist bdist_wheel + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dd90c37 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*.pyc +*.egg-info +build +dist +_build + +/CppHeaderParser/version.py + +__pycache__ +.vscode diff --git a/CppHeaderParser/CppHeaderParser.py b/CppHeaderParser/CppHeaderParser.py index 06a17fc..c6061e6 100644 --- a/CppHeaderParser/CppHeaderParser.py +++ b/CppHeaderParser/CppHeaderParser.py @@ -44,164 +44,109 @@ # # http://www.opensource.org/licenses/bsd-license.php # -"""Parse C++ header files and generate a data structure -representing the class -""" -import ply.lex as lex +from __future__ import print_function + + +from collections import deque import os import sys import re +import io import inspect -def lineno(): - """Returns the current line number in our program.""" - return inspect.currentframe().f_back.f_lineno - -version = __version__ = "2.7.4" - -tokens = [ - 'NUMBER', - 'FLOAT_NUMBER', - 'TEMPLATE_NAME', - 'NAME', - 'OPEN_PAREN', - 'CLOSE_PAREN', - 'OPEN_BRACE', - 'CLOSE_BRACE', - 'OPEN_SQUARE_BRACKET', - 'CLOSE_SQUARE_BRACKET', - 'COLON', - 'SEMI_COLON', - 'COMMA', - 'TAB', - 'BACKSLASH', - 'PIPE', - 'PERCENT', - 'EXCLAMATION', - 'CARET', - 'COMMENT_SINGLELINE', - 'COMMENT_MULTILINE', - 'PRECOMP_MACRO', - 'PRECOMP_MACRO_CONT', - 'ASTERISK', - 'AMPERSTAND', - 'EQUALS', - 'MINUS', - 'PLUS', - 'DIVIDE', - 'CHAR_LITERAL', - 'STRING_LITERAL', - 'NEW_LINE', - 'SQUOTE', -] - -t_ignore = " \r.?@\f" -t_NUMBER = r'[0-9][0-9XxA-Fa-f]*' -t_FLOAT_NUMBER = r'[-+]?[0-9]*\.[0-9]+([eE][-+]?[0-9]+)?' -t_TEMPLATE_NAME = r'CppHeaderParser_template_[0-9]+' -t_NAME = r'[<>A-Za-z_~][A-Za-z0-9_]*' -t_OPEN_PAREN = r'\(' -t_CLOSE_PAREN = r'\)' -t_OPEN_BRACE = r'{' -t_CLOSE_BRACE = r'}' -t_OPEN_SQUARE_BRACKET = r'\[' -t_CLOSE_SQUARE_BRACKET = r'\]' -t_SEMI_COLON = r';' -t_COLON = r':' -t_COMMA = r',' -t_TAB = r'\t' -t_BACKSLASH = r'\\' -t_PIPE = r'\|' -t_PERCENT = r'%' -t_CARET = r'\^' -t_EXCLAMATION = r'!' -t_PRECOMP_MACRO = r'\#.*' -t_PRECOMP_MACRO_CONT = r'.*\\\n' -def t_COMMENT_SINGLELINE(t): - r'\/\/.*\n' - global doxygenCommentCache - if t.value.startswith("///") or t.value.startswith("//!"): - if doxygenCommentCache: - doxygenCommentCache += "\n" - if t.value.endswith("\n"): - doxygenCommentCache += t.value[:-1] - else: - doxygenCommentCache += t.value - t.lexer.lineno += len([a for a in t.value if a=="\n"]) -t_ASTERISK = r'\*' -t_MINUS = r'\-' -t_PLUS = r'\+' -t_DIVIDE = r'/(?!/)' -t_AMPERSTAND = r'&' -t_EQUALS = r'=' -t_CHAR_LITERAL = "'.'" -t_SQUOTE = "'" -#found at http://wordaligned.org/articles/string-literals-and-regular-expressions -#TODO: This does not work with the string "bla \" bla" -t_STRING_LITERAL = r'"([^"\\]|\\.)*"' -#Found at http://ostermiller.org/findcomment.html -def t_COMMENT_MULTILINE(t): - r'/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/' - global doxygenCommentCache - if t.value.startswith("/**") or t.value.startswith("/*!"): - #not sure why, but get double new lines - v = t.value.replace("\n\n", "\n") - #strip prefixing whitespace - v = re.sub("\n[\s]+\*", "\n*", v) - doxygenCommentCache += v - t.lexer.lineno += len([a for a in t.value if a=="\n"]) -def t_NEWLINE(t): - r'\n+' - t.lexer.lineno += len(t.value) - -def t_error(v): - print(( "Lex error: ", v )) - -lex.lex() +from .lexer import Lexer +from .doxygen import extract_doxygen_method_params + +try: + from .version import __version__ +except ImportError: + __version__ = "devel" + +version = __version__ + # Controls error_print print_errors = 1 # Controls warning_print print_warnings = 1 # Controls debug_print -debug = 0 +debug = 1 if os.environ.get("CPPHEADERPARSER_DEBUG") == "1" else 0 # Controls trace_print debug_trace = 0 -def error_print(arg): - if print_errors: print(("[%4d] %s"%(inspect.currentframe().f_back.f_lineno, arg))) +if sys.version_info >= (3, 3): + # `raise e from src_e` syntax only supported on python 3.3+ + exec("def raise_exc(e, src_e): raise e from src_e", globals()) +else: + + def raise_exc(e, src_e): + raise e + + +def error_print(fmt, *args): + if print_errors: + fmt = "[%4d] " + fmt + args = (inspect.currentframe().f_back.f_lineno,) + args + print(fmt % args) + + +def warning_print(fmt, *args): + if print_warnings: + fmt = "[%4d] " + fmt + args = (inspect.currentframe().f_back.f_lineno,) + args + print(fmt % args) + + +if debug: + + class _debug_caller_lineno: + def __str__(self): + return str(inspect.currentframe().f_back.f_back.f_back.f_lineno) + + debug_caller_lineno = _debug_caller_lineno() + + def debug_print(fmt, *args): + fmt = "[%4d] " + fmt + args = (inspect.currentframe().f_back.f_lineno,) + args + print(fmt % args) -def warning_print(arg): - if print_warnings: print(("[%4d] %s"%(inspect.currentframe().f_back.f_lineno, arg))) +else: + debug_caller_lineno = None -def debug_print(arg): - global debug - if debug: print(("[%4d] %s"%(inspect.currentframe().f_back.f_lineno, arg))) + def debug_print(fmt, *args): + pass -def trace_print(*arg): - global debug_trace - if debug_trace: - sys.stdout.write("[%s] "%(inspect.currentframe().f_back.f_lineno)) - for a in arg: sys.stdout.write("%s "%a) + +if debug_trace: + + def trace_print(*args): + sys.stdout.write("[%s]" % (inspect.currentframe().f_back.f_lineno)) + for a in args: + sys.stdout.write(" %s" % a) sys.stdout.write("\n") -supportedAccessSpecifier = [ - 'public', - 'protected', - 'private' -] +else: + + def trace_print(*args): + pass + -#Symbols to ignore, usually special macros -ignoreSymbols = [ - 'Q_OBJECT', -] +#: Access specifiers +supportedAccessSpecifier = ["public", "protected", "private"] -doxygenCommentCache = "" +#: Symbols to ignore, usually special macros +ignoreSymbols = ["Q_OBJECT"] -#Track what was added in what order and at what depth +_BRACE_REASON_OTHER = 0 +_BRACE_REASON_NS = 1 +_BRACE_REASON_EXTERN = 2 +_BRACE_REASON_VARIABLE = 3 + +# Track what was added in what order and at what depth parseHistory = [] + def is_namespace(nameStack): """Determines if a namespace is being specified""" if len(nameStack) == 0: @@ -210,21 +155,32 @@ def is_namespace(nameStack): return True return False -def is_enum_namestack(nameStack): - """Determines if a namestack is an enum namestack""" - if len(nameStack) == 0: - return False - if nameStack[0] == "enum": - return True - if len(nameStack) > 1 and nameStack[0] == "typedef" and nameStack[1] == "enum": - return True - return False + +_fundamentals = { + "size_t", + "struct", + "union", + "unsigned", + "signed", + "bool", + "char", + "short", + "int", + "float", + "double", + "long", + "void", + "*", +} + def is_fundamental(s): for a in s.split(): - if a not in ["size_t", "struct", "union", "unsigned", "signed", "bool", "char", "short", "int", "float", "double", "long", "void", "*"]: return False + if a not in _fundamentals: + return False return True + def is_function_pointer_stack(stack): """Count how many non-nested paranthesis are in the stack. Useful for determining if a stack is a function pointer""" paren_depth = 0 @@ -241,557 +197,867 @@ def is_function_pointer_stack(stack): elif e == "*" and last_e == "(" and paren_count == 0 and paren_depth == 1: star_after_first_paren = True last_e = e - + if star_after_first_paren and paren_count == 2: return True else: return False + def is_method_namestack(stack): r = False - if '(' not in stack: r = False - elif stack[0] == 'typedef': r = False # TODO deal with typedef function prototypes - #elif '=' in stack and stack.index('=') < stack.index('(') and stack[stack.index('=')-1] != 'operator': r = False #disabled July6th - allow all operators - elif 'operator' in stack: r = True # allow all operators - elif '{' in stack and stack.index('{') < stack.index('('): r = False # struct that looks like a method/class - elif '(' in stack and ')' in stack: - if '{' in stack and '}' in stack: r = True - elif stack[-1] == ';': + if "(" not in stack: + r = False + elif stack[0] == "typedef": + r = False # TODO deal with typedef function prototypes + # elif '=' in stack and stack.index('=') < stack.index('(') and stack[stack.index('=')-1] != 'operator': r = False #disabled July6th - allow all operators + elif "operator" in stack: + r = True # allow all operators + elif "{" in stack and stack.index("{") < stack.index("("): + r = False # struct that looks like a method/class + elif "(" in stack and ")" in stack: + if stack[-1] == ":": + r = True + elif "{" in stack and "}" in stack: + r = True + elif stack[-1] == ";": if is_function_pointer_stack(stack): r = False else: r = True - elif '{' in stack: r = True # ideally we catch both braces... TODO - else: r = False - #Test for case of property set to something with parens such as "static const int CONST_A = (1 << 7) - 1;" - if r and "(" in stack and "=" in stack and 'operator' not in stack: - if stack.index("=") < stack.index("("): r = False + elif "{" in stack: + r = True # ideally we catch both braces... TODO + else: + r = False + # Test for case of property set to something with parens such as "static const int CONST_A = (1 << 7) - 1;" + if r and "(" in stack and "=" in stack and "operator" not in stack: + if stack.index("=") < stack.index("("): + r = False return r + def is_property_namestack(nameStack): r = False - if '(' not in nameStack and ')' not in nameStack: r = True - elif "(" in nameStack and "=" in nameStack and nameStack.index("=") < nameStack.index("("): r = True - #See if we are a function pointer - if not r and is_function_pointer_stack(nameStack): r = True + if "(" not in nameStack and ")" not in nameStack: + r = True + elif "(" in nameStack and ( + ( # = initialization + "=" in nameStack and nameStack.index("=") < nameStack.index("(") + ) + or ( # {} initialization + "{" in nameStack and nameStack.index("{") < nameStack.index("(") + ) + ): + r = True + # See if we are a function pointer + if not r and is_function_pointer_stack(nameStack): + r = True return r -def detect_lineno(s): - """Detect the line number for a given token string""" - try: - rtn = s.lineno() - if rtn != -1: - return rtn - except: pass - global curLine - return curLine - -def filter_out_attribute_keyword(stack): - """Strips __attribute__ and its parenthetical expression from the stack""" - if "__attribute__" not in stack: return stack - try: - debug_print("Stripping __attribute__ from %s"% stack) - attr_index = stack.index("__attribute__") - attr_end = attr_index + 1 #Assuming not followed by parenthetical expression which wont happen - #Find final paren - if stack[attr_index + 1] == '(': - paren_count = 1 - for i in range(attr_index + 2, len(stack)): - elm = stack[i] - if elm == '(': - paren_count += 1 - elif elm == ')': - paren_count -= 1 - if paren_count == 0: - attr_end = i + 1 - break - new_stack = stack[0:attr_index] + stack[attr_end:] - debug_print("stripped stack is %s"% new_stack) - return new_stack - except: - return stack - + +def is_enum_namestack(nameStack): + """Determines if a namestack is an enum namestack""" + if not nameStack: + return False + if nameStack[0] == "enum": + return True + if len(nameStack) > 1 and nameStack[0] == "typedef" and nameStack[1] == "enum": + return True + return False + + +def set_location_info(thing, location): + filename, line_number = location + if filename: + thing["filename"] = filename + thing["line_number"] = line_number + + +_nhack = re.compile(r"[A-Za-z_][A-Za-z0-9_]*") + + +def _split_namespace(namestack): + """ + Given a list of name elements, find the namespace portion + and return that as a string + + :rtype: Tuple[str, list] + """ + # TODO: this should be using tokens instead of nhack + typename = None + if namestack and namestack[0] == "typename": + typename = namestack[0] + namestack = namestack[1:] + + last_colon = None + for i, n in enumerate(namestack): + if n == "::": + last_colon = i + if i and n != "::" and not _nhack.match(n): + break + + if last_colon: + ns, namestack = ( + "".join(namestack[: last_colon + 1]), + namestack[last_colon + 1 :], + ) + else: + ns = "" + + if typename: + namestack = [typename] + namestack + + return ns, namestack + + +def _iter_ns_str_reversed(namespace): + """ + Take a namespace string, and yield successively smaller portions + of it (ex foo::bar::baz::, foo::bar::, foo::). The last item yielded + will always be an empty string + """ + if namespace: + parts = namespace.split("::") + for i in range(len(parts) - 1, 0, -1): + yield "::".join(parts[:i]) + "::" + + yield "" + + +def _split_by_comma(namestack): + while namestack: + if "," not in namestack: + yield namestack + break + idx = namestack.index(",") + ns = namestack[:idx] + yield ns + namestack = namestack[idx + 1 :] + class TagStr(str): """Wrapper for a string that allows us to store the line number associated with it""" - lineno_reg = {} - def __new__(cls,*args,**kw): - new_obj = str.__new__(cls,*args) - if "lineno" in kw: - TagStr.lineno_reg[id(new_obj)] = kw["lineno"] - return new_obj - - def __del__(self): - try: - del TagStr.lineno_reg[id(self)] - except: pass - - def lineno(self): - return TagStr.lineno_reg.get(id(self), -1) - -class CppParseError(Exception): pass - + + def __new__(cls, *args, **kwargs): + location = kwargs.pop("location") + s = str.__new__(cls, *args, **kwargs) + s.location = location + return s + + +class CppParseError(Exception): + def __init__(self, msg, tok=None): + Exception.__init__(self, msg) + self.tok = tok + + +class CppTemplateParam(dict): + """ + Dictionary that contains the following: + + - ``decltype`` - If True, this is a decltype + - ``param`` - Parameter value or typename + - ``params`` - Only present if a template specialization. Is a list of + :class:`.CppTemplateParam` + - ``...`` - If True, indicates a parameter pack + """ + + def __init__(self): + self["param"] = "" + self["decltype"] = False + self["..."] = False + + def __str__(self): + s = [] + if self["decltype"]: + s.append("decltype") + + s.append(self["param"]) + + params = self.get("params") + if params is not None: + s.append("<%s>" % ",".join(str(p) for p in params)) + + if self["..."]: + if s: + s[-1] = s[-1] + "..." + else: + s.append("...") + + return "".join(s) + + +class CppBaseDecl(dict): + """ + Dictionary that contains the following + + - ``access`` - Anything in supportedAccessSpecifier + - ``class`` - Name of the type, along with template specializations + - ``decl_name`` - Name of the type only + - ``decl_params`` - Only present if a template specialization (Foo). + Is a list of :class:`.CppTemplateParam`. + - ``decltype`` - True/False indicates a decltype, the contents are in + ``decl_name`` + - ``virtual`` - True/False indicates virtual inheritance + - ``...`` - True/False indicates a parameter pack + + """ + + def __init__(self, default_access): + self["access"] = default_access + self["class"] = "" + self["decl_name"] = "" + self["decltype"] = False + self["virtual"] = False + self["..."] = False + + def _fix_classname(self): + # set class to the full decl for legacy reasons + params = self.get("decl_params") + + if self["decltype"]: + s = "decltype" + else: + s = "" + + s += self["decl_name"] + if params: + s += "<%s>" % (",".join(str(p) for p in params)) + + if self["..."]: + s += "..." + + return s + + +def _consume_parens(stack): + i = 0 + sl = len(stack) + nested = 1 + while i < sl: + t = stack[i] + i += 1 + if t == ")": + nested -= 1 + if nested == 0: + return i + elif t == "(": + nested += 1 + + raise CppParseError("Unmatched (") + + +def _parse_template_decl(stack): + debug_print("_parse_template_decl: %s", stack) + params = [] + param = CppTemplateParam() + i = 0 + sl = len(stack) + init = True + require_ending = False + while i < sl: + t = stack[i] + i += 1 + if init: + init = False + if t == "decltype": + param["decltype"] = True + continue + + if t == ",": + params.append(param) + init = True + require_ending = False + param = CppTemplateParam() + + continue + elif t == ">": + params.append(param) + return params, i - 1 + + if require_ending: + raise CppParseError("expected comma, found %s" % t) + + if t == "...": + param["..."] = True + require_ending = True + elif t == "(": + s = stack[i:] + n = _consume_parens(s) + i += n + param["param"] = param["param"] + "".join(s[:n]) + else: + if t and t[0] == "<": + param["params"], n = _parse_template_decl([t[1:]] + stack[i:]) + i += n + else: + param["param"] = param["param"] + t + + raise CppParseError("Unmatched <") + + +def _parse_cppclass_name(c, stack): + # ignore first thing + i = 1 + sl = len(stack) + name = "" + require_ending = False + while i < sl: + t = stack[i] + i += 1 + + if t == ":": + if i >= sl: + raise CppParseError("class decl ended with ':'") + break + elif t == "::": + name += "::" + continue + elif t == "final": + c["final"] = True + continue + + if require_ending: + raise CppParseError("Unexpected '%s' in class" % ("".join(stack[i - 1 :]))) + + if t and t[0] == "<": + c["class_params"], n = _parse_template_decl([t[1:]] + stack[i:]) + i += n + require_ending = True + else: + name += t + + c["namespace"] = "" + + # backwards compat + if name.startswith("anon-"): + if ( + name.startswith("anon-class-") + or name.startswith("anon-struct-") + or name.startswith("anon-union-") + ): + name = "<" + name + ">" + c["name"] = name + c["bare_name"] = name + debug_print("Found class '%s'", name) + + # backwards compat + classParams = c.get("class_params") + if classParams is not None: + c["name"] = c["name"] + "<%s>" % ",".join(str(p) for p in classParams) + + return i + + +def _parse_cpp_base(stack, default_access): + debug_print("Parsing base: %s (access %s)", stack, default_access) + inherits = [] + i = 0 + sl = len(stack) + init = True + base = CppBaseDecl(default_access) + require_ending = False + while i < sl: + t = stack[i] + i += 1 + + if init: + if t in supportedAccessSpecifier: + base["access"] = t + continue + elif t == "virtual": + base["virtual"] = True + continue + + init = False + + if t == "decltype": + base["decltype"] = True + continue + + if t == ",": + inherits.append(base) + base = CppBaseDecl(default_access) + init = True + require_ending = False + continue + + if require_ending: + if t == "::": + if "decl_params" in base: + base["decl_name"] = base._fix_classname() + del base["decl_params"] + base["..."] + require_ending = False + else: + raise CppParseError("expected comma, found '%s'" % t) + + if t == "(": + s = stack[i:] + n = _consume_parens(s) + i += n + base["decl_name"] = base["decl_name"] + "".join(s[:n]) + elif t == "...": + base["..."] = True + require_ending = True + else: + if t[0] == "<": + base["decl_params"], n = _parse_template_decl([t[1:]] + stack[i:]) + i += n + require_ending = True + else: + base["decl_name"] = base["decl_name"] + t + + # backwards compat + inherits.append(base) + for base in inherits: + base["class"] = base._fix_classname() + + return inherits + + class CppClass(dict): - """Takes a name stack and turns it into a class - - Contains the following Keys: - self['name'] - Name of the class - self['doxygen'] - Doxygen comments associated with the class if they exist - self['inherits'] - List of Classes that this one inherits where the values - are of the form {"access": Anything in supportedAccessSpecifier - "class": Name of the class - self['methods'] - Dictionary where keys are from supportedAccessSpecifier - and values are a lists of CppMethod's - self['properties'] - Dictionary where keys are from supportedAccessSpecifier - and values are lists of CppVariable's - self['enums'] - Dictionary where keys are from supportedAccessSpecifier and - values are lists of CppEnum's - self['structs'] - Dictionary where keys are from supportedAccessSpecifier and - values are lists of nested Struct's - - An example of how this could look is as follows: - #self = - { - 'name': "" - 'inherits':[] - 'methods': - { - 'public':[], - 'protected':[], - 'private':[] - }, - 'properties': - { - 'public':[], - 'protected':[], - 'private':[] - }, - 'enums': + """ + Dictionary that contains at least the following keys: + + * ``name`` - Name of the class + * ``doxygen`` - Doxygen comments associated with the class if they exist + * ``inherits`` - List of Classes that this one inherits. Values are + :class:`.CppBaseDecl` + * ``methods`` - Dictionary where keys are from supportedAccessSpecifier + and values are a lists of :class:`.CppMethod` + * ``namespace`` - Namespace of class + * ``properties`` - Dictionary where keys are from supportedAccessSpecifier + and values are lists of :class:`.CppVariable` + * ``enums`` - Dictionary where keys are from supportedAccessSpecifier and + values are lists of :class:`.CppEnum` + * ``nested_classes`` - Classes and structs defined within this class + * ``final`` - True if final + * ``abstract`` - True if abstract + * ``using`` - Using directives in this class scope: key is name for lookup, + value is :class:`.CppVariable` + * ``parent`` - If not None, the class that this class is nested in + + An example of how this could look is as follows:: + { - 'public':[], - 'protected':[], - 'private':[] + 'name': "" + 'inherits':[] + 'methods': + { + 'public':[], + 'protected':[], + 'private':[] + }, + 'properties': + { + 'public':[], + 'protected':[], + 'private':[] + }, + 'enums': + { + 'public':[], + 'protected':[], + 'private':[] + } } - } """ def get_all_methods(self): r = [] - for typ in supportedAccessSpecifier: r += self['methods'][typ] + for typ in supportedAccessSpecifier: + r += self["methods"][typ] return r - def get_all_method_names( self ): + def get_all_method_names(self): r = [] - for typ in supportedAccessSpecifier: r += self.get_method_names(typ) # returns list + for typ in supportedAccessSpecifier: + r += self.get_method_names(typ) # returns list return r - def get_all_pure_virtual_methods( self ): + def get_all_pure_virtual_methods(self): r = {} - for typ in supportedAccessSpecifier: r.update(self.get_pure_virtual_methods(typ)) # returns dict + for typ in supportedAccessSpecifier: + r.update(self.get_pure_virtual_methods(typ)) # returns dict return r + def get_method_names(self, type="public"): + return [meth["name"] for meth in self["methods"][type]] - def get_method_names( self, type='public' ): return [ meth['name'] for meth in self['methods'][ type ] ] - - def get_pure_virtual_methods( self, type='public' ): + def get_pure_virtual_methods(self, type="public"): r = {} - for meth in self['methods'][ type ]: - if meth['pure_virtual']: r[ meth['name'] ] = meth + for meth in self["methods"][type]: + if meth["pure_virtual"]: + r[meth["name"]] = meth return r - def __init__(self, nameStack, curTemplate): - self['nested_classes'] = [] - self['parent'] = None - self['abstract'] = False + def _lookup_type(self, name): + # TODO: should have indexes for these lookups... and they + # should be more unified + for access in supportedAccessSpecifier: + for e in self["enums"][access]: + if e.get("name") == name: + return { + "enum": self["name"] + "::" + e["name"], + "type": e["name"], + "namespace": e["namespace"], + } + for n in self["nested_classes"]: + if n["name"] == name: + return {"raw_type": self["name"] + "::" + n["name"], "type": n["name"]} + + def __init__(self, nameStack, curTemplate, doxygen, location, defaultAccess): + self["nested_classes"] = [] + self["parent"] = None + self["abstract"] = False + self["final"] = False self._public_enums = {} - self._public_structs = {} self._public_typedefs = {} self._public_forward_declares = [] - self['namespace'] = "" - - debug_print( "Class: %s"%nameStack ) - debug_print( "Template: %s"%curTemplate) - - if (len(nameStack) < 2): - nameStack.insert(1, "")#anonymous struct - global doxygenCommentCache - if len(doxygenCommentCache): - self["doxygen"] = doxygenCommentCache - doxygenCommentCache = "" - - if "::" in "".join(nameStack): - #Re-Join class paths (ex ['class', 'Bar', ':', ':', 'Foo'] -> ['class', 'Bar::Foo'] - try: - new_nameStack = [] - for name in nameStack: - if len(new_nameStack) == 0: - new_nameStack.append(name) - elif name == ":" and new_nameStack[-1].endswith(":"): - new_nameStack[-1] += name - elif new_nameStack[-1].endswith("::"): - new_nameStack[-2] += new_nameStack[-1] + name - del new_nameStack[-1] - else: - new_nameStack.append(name) - trace_print("Convert from namestack\n %s\nto\n%s"%(nameStack, new_nameStack)) - nameStack = new_nameStack - except: pass - - # Handle final specifier - self["final"] = False - try: - final_index = nameStack.index("final") - # Dont trip up the rest of the logic - del nameStack[final_index] - self["final"] = True - trace_print("final") - except: pass - - self["name"] = nameStack[1] - self["line_number"] = detect_lineno(nameStack[0]) - - #Handle template classes - if len(nameStack) > 3 and nameStack[2].startswith("<"): - open_template_count = 0 - param_separator = 0 - found_first = False - i = 0 - for elm in nameStack: - if '<' in elm : - open_template_count += 1 - found_first = True - elif '>' in elm: - open_template_count -= 1 - if found_first and open_template_count == 0: - self["name"] = "".join(nameStack[1:i + 1]) - break; - i += 1 - elif ":" in nameStack: - self['name'] = nameStack[ nameStack.index(':') - 1 ] - - inheritList = [] - - if nameStack.count(':') == 1: - nameStack = nameStack[nameStack.index(":") + 1:] - while len(nameStack): - tmpStack = [] - tmpInheritClass = {"access":"private", "virtual": False} - if "," in nameStack: - tmpStack = nameStack[:nameStack.index(",")] - nameStack = nameStack[nameStack.index(",") + 1:] - else: - tmpStack = nameStack - nameStack = [] - - # Convert template classes to one name in the last index - for i in range(0, len(tmpStack)): - if '<' in tmpStack[i]: - tmpStack2 = tmpStack[:i-1] - tmpStack2.append("".join(tmpStack[i-1:])) - tmpStack = tmpStack2 - break - if len(tmpStack) == 0: - break; - elif len(tmpStack) == 1: - tmpInheritClass["class"] = tmpStack[0] - elif len(tmpStack) == 2: - tmpInheritClass["access"] = tmpStack[0] - tmpInheritClass["class"] = tmpStack[1] - elif len(tmpStack) == 3 and "virtual" in tmpStack: - tmpInheritClass["access"] = tmpStack[1] if tmpStack[1] != "virtual" else tmpStack[0] - tmpInheritClass["class"] = tmpStack[2] - tmpInheritClass["virtual"] = True - else: - warning_print( "Warning: can not parse inheriting class %s"%(" ".join(tmpStack))) - if '>' in tmpStack: pass # allow skip templates for now - else: raise NotImplemented + self["namespace"] = "" + self["using"] = {} - if 'class' in tmpInheritClass: inheritList.append(tmpInheritClass) + debug_print("Class: %s", nameStack) + debug_print("Template: %s", curTemplate) - elif nameStack.count(':') == 2: self['parent'] = self['name']; self['name'] = nameStack[-1] + if len(nameStack) < 2: + nameStack.insert(1, "") # anonymous struct + if doxygen: + self["doxygen"] = doxygen - elif nameStack.count(':') > 2 and nameStack[0] in ("class", "struct"): - tmpStack = nameStack[nameStack.index(":") + 1:] - - superTmpStack = [[]] - for tok in tmpStack: - if tok == ',': - superTmpStack.append([]) - else: - superTmpStack[-1].append(tok) - - for tmpStack in superTmpStack: - tmpInheritClass = {"access":"private"} - - if len(tmpStack) and tmpStack[0] in supportedAccessSpecifier: - tmpInheritClass["access"] = tmpStack[0] - tmpStack = tmpStack[1:] - - inheritNSStack = [] - while len(tmpStack) > 3: - if tmpStack[0] == ':': break; - if tmpStack[1] != ':': break; - if tmpStack[2] != ':': break; - inheritNSStack.append(tmpStack[0]) - tmpStack = tmpStack[3:] - if len(tmpStack) == 1 and tmpStack[0] != ':': - inheritNSStack.append(tmpStack[0]) - tmpInheritClass["class"] = "::".join(inheritNSStack) - inheritList.append(tmpInheritClass) - - self['inherits'] = inheritList + # consume name of class, with any namespaces or templates + n = _parse_cppclass_name(self, nameStack) + + # consume bases + baseStack = nameStack[n:] + if baseStack: + self["inherits"] = _parse_cpp_base(baseStack, defaultAccess) + else: + self["inherits"] = [] + + set_location_info(self, location) if curTemplate: self["template"] = curTemplate - trace_print("Setting template to '%s'"%self["template"]) + trace_print("Setting template to", self["template"]) methodAccessSpecificList = {} propertyAccessSpecificList = {} enumAccessSpecificList = {} - structAccessSpecificList = {} typedefAccessSpecificList = {} forwardAccessSpecificList = {} - + for accessSpecifier in supportedAccessSpecifier: methodAccessSpecificList[accessSpecifier] = [] propertyAccessSpecificList[accessSpecifier] = [] enumAccessSpecificList[accessSpecifier] = [] - structAccessSpecificList[accessSpecifier] = [] typedefAccessSpecificList[accessSpecifier] = [] forwardAccessSpecificList[accessSpecifier] = [] - self['methods'] = methodAccessSpecificList - self['properties'] = propertyAccessSpecificList - self['enums'] = enumAccessSpecificList - self['structs'] = structAccessSpecificList - self['typedefs'] = typedefAccessSpecificList - self['forward_declares'] = forwardAccessSpecificList + self["methods"] = methodAccessSpecificList + self["properties"] = propertyAccessSpecificList + self["enums"] = enumAccessSpecificList + self["typedefs"] = typedefAccessSpecificList + self["forward_declares"] = forwardAccessSpecificList - def show(self): """Convert class to a string""" namespace_prefix = "" - if self["namespace"]: namespace_prefix = self["namespace"] + "::" - rtn = "%s %s"%(self["declaration_method"], namespace_prefix + self["name"]) - if self["final"]: rtn += " final" - if self['abstract']: rtn += ' (abstract)\n' - else: rtn += '\n' + if self["namespace"]: + namespace_prefix = self["namespace"] + "::" + rtn = "%s %s" % (self["declaration_method"], namespace_prefix + self["name"]) + if self["final"]: + rtn += " final" + if self["abstract"]: + rtn += " (abstract)\n" + else: + rtn += "\n" - if 'doxygen' in list(self.keys()): rtn += self["doxygen"] + '\n' - if 'parent' in list(self.keys()) and self['parent']: rtn += 'parent class: ' + self['parent'] + '\n' + if "doxygen" in list(self.keys()): + rtn += self["doxygen"] + "\n" + if "parent" in list(self.keys()) and self["parent"]: + rtn += "parent class: " + self["parent"]["name"] + "\n" if "inherits" in list(self.keys()): rtn += " Inherits: " for inheritClass in self["inherits"]: - if inheritClass["virtual"]: rtn += "virtual " - rtn += "%s %s, "%(inheritClass["access"], inheritClass["class"]) + if inheritClass["virtual"]: + rtn += "virtual " + rtn += "%s %s, " % (inheritClass["access"], inheritClass["class"]) rtn += "\n" rtn += " {\n" for accessSpecifier in supportedAccessSpecifier: - rtn += " %s\n"%(accessSpecifier) - #Enums - if (len(self["enums"][accessSpecifier])): + rtn += " %s\n" % (accessSpecifier) + # Enums + if len(self["enums"][accessSpecifier]): rtn += " \n" for enum in self["enums"][accessSpecifier]: - rtn += " %s\n"%(repr(enum)) - #Properties - if (len(self["properties"][accessSpecifier])): + rtn += " %s\n" % (repr(enum)) + # Properties + if len(self["properties"][accessSpecifier]): rtn += " \n" for property in self["properties"][accessSpecifier]: - rtn += " %s\n"%(repr(property)) - #Methods - if (len(self["methods"][accessSpecifier])): + rtn += " %s\n" % (repr(property)) + # Methods + if len(self["methods"][accessSpecifier]): rtn += " \n" for method in self["methods"][accessSpecifier]: - rtn += "\t\t" + method.show() + '\n' + rtn += "\t\t" + method.show() + "\n" rtn += " }\n" print(rtn) - + def __str__(self): """Convert class to a string""" namespace_prefix = "" - if self["namespace"]: namespace_prefix = self["namespace"] + "::" - rtn = "%s %s"%(self["declaration_method"], namespace_prefix + self["name"]) - if self["final"]: rtn += " final" - if self['abstract']: rtn += ' (abstract)\n' - else: rtn += '\n' + if self["namespace"]: + namespace_prefix = self["namespace"] + "::" + rtn = "%s %s" % (self["declaration_method"], namespace_prefix + self["name"]) + if self["final"]: + rtn += " final" + if self["abstract"]: + rtn += " (abstract)\n" + else: + rtn += "\n" - if 'doxygen' in list(self.keys()): rtn += self["doxygen"] + '\n' - if 'parent' in list(self.keys()) and self['parent']: rtn += 'parent class: ' + self['parent'] + '\n' + if "doxygen" in list(self.keys()): + rtn += self["doxygen"] + "\n" + if "parent" in list(self.keys()) and self["parent"]: + rtn += "parent class: " + self["parent"]["name"] + "\n" if "inherits" in list(self.keys()) and len(self["inherits"]): rtn += "Inherits: " for inheritClass in self["inherits"]: - if inheritClass.get("virtual", False): rtn += "virtual " - rtn += "%s %s, "%(inheritClass["access"], inheritClass["class"]) + if inheritClass.get("virtual", False): + rtn += "virtual " + rtn += "%s %s, " % (inheritClass["access"], inheritClass["class"]) rtn += "\n" rtn += "{\n" for accessSpecifier in supportedAccessSpecifier: - rtn += "%s\n"%(accessSpecifier) - #Enums - if (len(self["enums"][accessSpecifier])): + rtn += "%s\n" % (accessSpecifier) + # Enums + if len(self["enums"][accessSpecifier]): rtn += " // Enums\n" for enum in self["enums"][accessSpecifier]: - rtn += " %s\n"%(repr(enum)) - #Properties - if (len(self["properties"][accessSpecifier])): + rtn += " %s\n" % (repr(enum)) + # Properties + if len(self["properties"][accessSpecifier]): rtn += " // Properties\n" for property in self["properties"][accessSpecifier]: - rtn += " %s\n"%(repr(property)) - #Methods - if (len(self["methods"][accessSpecifier])): + rtn += " %s\n" % (repr(property)) + # Methods + if len(self["methods"][accessSpecifier]): rtn += " // Methods\n" for method in self["methods"][accessSpecifier]: - rtn += " %s\n"%(repr(method)) + rtn += " %s\n" % (repr(method)) rtn += "}\n" return rtn -class CppUnion( CppClass ): - """Takes a name stack and turns it into a union - - Contains the following Keys: - self['name'] - Name of the union - self['doxygen'] - Doxygen comments associated with the union if they exist - self['members'] - List of members the union has - - An example of how this could look is as follows: - #self = - { - 'name': "" - 'members': [] - } +class CppUnion(CppClass): """ - - def __init__(self, nameStack): - CppClass.__init__(self, nameStack, None) - self["name"] = "union " + self["name"] + Dictionary that contains at least the following keys: + + * ``name`` - Name of the union + * ``doxygen`` - Doxygen comments associated with the union if they exist + * ``members`` - List of members of the union + """ + + def __init__(self, nameStack, doxygen, location): + CppClass.__init__(self, nameStack, None, doxygen, location, "public") self["members"] = self["properties"]["public"] - + def transform_to_union_keys(self): - print("union keys: %s"%list(self.keys())) - for key in ['inherits', 'parent', 'abstract', 'namespace', 'typedefs', 'methods']: - del self[key] - + print("union keys: %s" % list(self.keys())) + for key in [ + "inherits", + "parent", + "abstract", + "namespace", + "typedefs", + "methods", + ]: + del self[key] + def show(self): """Convert class to a string""" print(self) - - + def __str__(self): """Convert class to a string""" namespace_prefix = "" - if self["namespace"]: namespace_prefix = self["namespace"] + "::" - rtn = "%s %s"%(self["declaration_method"], namespace_prefix + self["name"]) - if self['abstract']: rtn += ' (abstract)\n' - else: rtn += '\n' + if self["namespace"]: + namespace_prefix = self["namespace"] + "::" + rtn = "%s %s" % (self["declaration_method"], namespace_prefix + self["name"]) + if self["abstract"]: + rtn += " (abstract)\n" + else: + rtn += "\n" - if 'doxygen' in list(self.keys()): rtn += self["doxygen"] + '\n' - if 'parent' in list(self.keys()) and self['parent']: rtn += 'parent class: ' + self['parent'] + '\n' + if "doxygen" in list(self.keys()): + rtn += self["doxygen"] + "\n" + if "parent" in list(self.keys()) and self["parent"]: + rtn += "parent class: " + self["parent"]["name"] + "\n" rtn += "{\n" for member in self["members"]: - rtn += " %s\n"%(repr(member)) + rtn += " %s\n" % (repr(member)) rtn += "}\n" return rtn - -class _CppMethod( dict ): - def _params_helper1( self, stack ): +class _CppMethod(dict): + def _params_helper1(self, stack): # deal with "throw" keyword - if 'throw' in stack: stack = stack[ : stack.index('throw') ] + if "throw" in stack: + stack = stack[: stack.index("throw")] ## remove GCC keyword __attribute__(...) and preserve returns ## cleaned = [] - hit = False; hitOpen = 0; hitClose = 0 + hit = False + hitOpen = 0 + hitClose = 0 for a in stack: - if a == '__attribute__': hit = True + if a == "__attribute__": + hit = True if hit: - if a == '(': hitOpen += 1 - elif a == ')': hitClose += 1 - if a==')' and hitOpen == hitClose: + if a == "(": + hitOpen += 1 + elif a == ")": + hitClose += 1 + if a == ")" and hitOpen == hitClose: hit = False else: - cleaned.append( a ) + cleaned.append(a) stack = cleaned # also deal with attribute((const)) function prefix # # TODO this needs to be better # if len(stack) > 5: - a = ''.join(stack) - if a.startswith('((__const__))'): stack = stack[ 5 : ] - elif a.startswith('__attribute__((__const__))'): stack = stack[ 6 : ] - - stack = stack[stack.index('(') + 1: ] - if not stack: return [] - if len(stack)>=3 and stack[0]==')' and stack[1]==':': # is this always a constructor? - self['constructor'] = True + a = "".join(stack) + if a.startswith("((__const__))"): + stack = stack[5:] + elif a.startswith("__attribute__((__const__))"): + stack = stack[6:] + + stack = stack[stack.index("(") + 1 :] + if not stack: + return [] + if ( + len(stack) >= 3 and stack[0] == ")" and stack[1] == ":" + ): # is this always a constructor? + self["constructor"] = True return [] - stack.reverse(); _end_ = stack.index(')'); stack.reverse() - stack = stack[ : len(stack)-(_end_+1) ] - if '(' not in stack: return stack # safe to return, no defaults that init a class + stack.reverse() + _end_ = stack.index(")") + stack.reverse() + stack = stack[: len(stack) - (_end_ + 1)] + if "(" not in stack: + return stack # safe to return, no defaults that init a class - # transforms ['someclass', '(', '0', '0', '0', ')'] into "someclass(0,0,0)'" - r = []; hit=False - for a in stack: - if a == '(': hit=True - elif a == ')': hit=False - if hit or a == ')': r[-1] = r[-1] + a - else: r.append( a ) - return r + return stack - def _params_helper2( self, params ): + def _params_helper2(self, params): for p in params: - p['method'] = self # save reference in variable to parent method - if '::' in p['type']: - ns = p['type'].split('::')[0] + p["method"] = self # save reference in variable to parent method + p["parent"] = self + if "::" in p["type"]: + ns = p["type"].split("::")[0] if ns not in Resolver.NAMESPACES and ns in Resolver.CLASSES: - p['type'] = self['namespace'] + p['type'] - else: p['namespace'] = self[ 'namespace' ] - -class CppMethod( _CppMethod ): - """Takes a name stack and turns it into a method - - Contains the following Keys: - self['rtnType'] - Return type of the method (ex. "int") - self['name'] - Name of the method (ex. "getSize") - self['doxygen'] - Doxygen comments associated with the method if they exist - self['parameters'] - List of CppVariables + p["type"] = self["namespace"] + p["type"] + else: + p["namespace"] = self["namespace"] + + +class CppMethod(_CppMethod): + """ + Dictionary that contains at least the following keys: + + * ``rtnType`` - Return type of the method (ex. "int") + * ``name`` - Name of the method + * ``doxygen`` - Doxygen comments associated with the method if they exist + * ``parameters`` - List of :class:`.CppVariable` + * ``parent`` - If not None, the class this method belongs to """ + def show(self): - r = ['method name: %s (%s)' %(self['name'],self['debug']) ] - if self['returns']: r.append( 'returns: %s'%self['returns'] ) - if self['parameters']: r.append( 'number arguments: %s' %len(self['parameters'])) - if self['pure_virtual']: r.append( 'pure virtual: %s'%self['pure_virtual'] ) - if self['constructor']: r.append( 'constructor' ) - if self['destructor']: r.append( 'destructor' ) - return '\n\t\t '.join( r ) - - def __init__(self, nameStack, curClass, methinfo, curTemplate): - debug_print( "Method: %s"%nameStack ) - debug_print( "Template: %s"%curTemplate ) - global doxygenCommentCache - if len(doxygenCommentCache): - self["doxygen"] = doxygenCommentCache - doxygenCommentCache = "" + r = ["method name: %s (%s)" % (self["name"], self["debug"])] + if self["returns"]: + r.append("returns: %s" % self["returns"]) + if self["parameters"]: + r.append("number arguments: %s" % len(self["parameters"])) + if self["pure_virtual"]: + r.append("pure virtual: %s" % self["pure_virtual"]) + if self["constructor"]: + r.append("constructor") + if self["destructor"]: + r.append("destructor") + return "\n\t\t ".join(r) + + def __init__(self, nameStack, curClass, methinfo, curTemplate, doxygen, location): + debug_print("Method: %s", nameStack) + debug_print("Template: %s", curTemplate) + + if doxygen: + self["doxygen"] = doxygen + + # Remove leading keywords + for i, word in enumerate(nameStack): + if word not in Resolver.C_KEYWORDS: + nameStack = nameStack[i:] + break + if "operator" in nameStack: - self["rtnType"] = " ".join(nameStack[:nameStack.index('operator')]) - self["name"] = "".join(nameStack[nameStack.index('operator'):nameStack.index('(')]) + rtnType = " ".join(nameStack[: nameStack.index("operator")]) + self["name"] = "".join( + nameStack[nameStack.index("operator") : nameStack.index("(")] + ) else: - self["rtnType"] = " ".join(nameStack[:nameStack.index('(') - 1]) - self["name"] = " ".join(nameStack[nameStack.index('(') - 1:nameStack.index('(')]) - if self["rtnType"].startswith("virtual"): - self["rtnType"] = self["rtnType"][len("virtual"):].strip() - if len(self["rtnType"]) == 0 or self["name"] == curClass: - self["rtnType"] = "void" - - self["rtnType"] = self["rtnType"].replace(' : : ', '::' ) - self["rtnType"] = self["rtnType"].replace(" <","<") - self["rtnType"] = self["rtnType"].replace(" >",">").replace(">>", "> >").replace(">>", "> >") - self["rtnType"] = self["rtnType"].replace(" ,",",") - + rtnType = " ".join(nameStack[: nameStack.index("(") - 1]) + self["name"] = " ".join( + nameStack[nameStack.index("(") - 1 : nameStack.index("(")] + ) + + if len(rtnType) == 0 or self["name"] == curClass: + rtnType = "void" + + self["rtnType"] = ( + rtnType.replace(" :: ", "::") + .replace(" < ", "<") + .replace(" > ", "> ") + .replace(">>", "> >") + .replace(" ,", ",") + ) + + # deal with "noexcept" specifier/operator + self["noexcept"] = None + if "noexcept" in nameStack: + noexcept_idx = nameStack.index("noexcept") + hit = True + cleaned = nameStack[:noexcept_idx] + parentCount = 0 + noexcept = "noexcept" + for a in nameStack[noexcept_idx + 1 :]: + if a == "noexcept": + hit = True + if hit: + if a == "(": + parentCount += 1 + elif a == ")": + parentCount -= 1 + elif parentCount == 0 and a != "noexcept": + hit = False + cleaned.append(a) + continue # noexcept without parenthesis + if a == ")" and parentCount == 0: + hit = False + noexcept += a + else: + cleaned.append(a) + self["noexcept"] = noexcept + nameStack = cleaned + for spec in ["const", "final", "override"]: self[spec] = False for i in reversed(nameStack): @@ -801,225 +1067,289 @@ def __init__(self, nameStack, curClass, methinfo, curTemplate): elif i == ")": break - self.update( methinfo ) - self["line_number"] = detect_lineno(nameStack[0]) + self.update(methinfo) + set_location_info(self, location) - #Filter out initializer lists used in constructors - try: - paren_depth_counter = 0 - for i in range(0, len(nameStack)): - elm = nameStack[i] - if elm == "(": - paren_depth_counter += 1 - if elm == ")": - paren_depth_counter -=1 - if paren_depth_counter == 0 and nameStack[i+1] == ':': - debug_print("Stripping out initializer list") - nameStack = nameStack[:i+1] - break - except: pass - - paramsStack = self._params_helper1( nameStack ) - - debug_print( "curTemplate: %s"%curTemplate) + paramsStack = self._params_helper1(nameStack) + + debug_print("curTemplate: %s", curTemplate) if curTemplate: self["template"] = curTemplate - debug_print( "SET self['template'] to `%s`"%self["template"]) + debug_print("SET self['template'] to `%s`", self["template"]) params = [] - #See if there is a doxygen comment for the variable - doxyVarDesc = {} - + # See if there is a doxygen comment for the variable if "doxygen" in self: - doxyLines = self["doxygen"].split("\n") - lastParamDesc = "" - for doxyLine in doxyLines: - if " @param " in doxyLine or " \param " in doxyLine: - try: - #Strip out the param - doxyLine = doxyLine[doxyLine.find("param ") + 6:] - (var, desc) = doxyLine.split(" ", 1) - doxyVarDesc[var] = desc.strip() - lastParamDesc = var - except: pass - elif " @return " in doxyLine or " \return " in doxyLine: - lastParamDesc = "" - # not handled for now - elif lastParamDesc: - try: - doxyLine = doxyLine.strip() - if " " not in doxyLine: - lastParamDesc = "" - continue - doxyLine = doxyLine[doxyLine.find(" ") + 1:] - doxyVarDesc[lastParamDesc] += " " + doxyLine - except: pass - - #Create the variable now - while (len(paramsStack)): + doxyVarDesc = extract_doxygen_method_params(self["doxygen"]) + else: + doxyVarDesc = {} + + # non-vararg by default + self["vararg"] = False + # Create the variable now + while len(paramsStack): # Find commas that are not nexted in <>'s like template types open_template_count = 0 + open_paren_count = 0 + open_brace_count = 0 param_separator = 0 i = 0 for elm in paramsStack: - if '<' in elm : - open_template_count += 1 - elif '>' in elm: - open_template_count -= 1 - elif elm == ',' and open_template_count == 0: - param_separator = i - break + if elm in "<>(){},": + if elm == ",": + if ( + open_template_count == 0 + and open_paren_count == 0 + and open_brace_count == 0 + ): + param_separator = i + break + elif "<" == elm: + open_template_count += 1 + elif ">" == elm: + open_template_count -= 1 + elif "(" == elm: + open_paren_count += 1 + elif ")" == elm: + open_paren_count -= 1 + elif "{" == elm: + open_brace_count += 1 + elif "}" == elm: + open_brace_count -= 1 i += 1 - + if param_separator: - param = CppVariable(paramsStack[0:param_separator], doxyVarDesc=doxyVarDesc) - if len(list(param.keys())): params.append(param) - paramsStack = paramsStack[param_separator + 1:] + tpstack = paramsStack[0:param_separator] + param = CppVariable( + tpstack, + None, + getattr(tpstack[0], "location", location), + doxyVarDesc=doxyVarDesc, + ) + if len(list(param.keys())): + params.append(param) + paramsStack = paramsStack[param_separator + 1 :] + elif len(paramsStack) and paramsStack[0] == "...": + self["vararg"] = True + paramsStack = paramsStack[1:] else: - param = CppVariable(paramsStack, doxyVarDesc=doxyVarDesc) - if len(list(param.keys())): params.append(param) + param = CppVariable( + paramsStack, + None, + getattr(paramsStack[0], "location", location), + doxyVarDesc=doxyVarDesc, + ) + if len(list(param.keys())): + params.append(param) break + # foo(void) should be zero parameters + if len(params) == 1 and params[0]["type"] == "void": + params = [] self["parameters"] = params - self._params_helper2( params ) # mods params inplace + self._params_helper2(params) # mods params inplace def __str__(self): filter_keys = ("parent", "defined", "operator", "returns_reference") - cpy = dict((k,v) for (k,v) in list(self.items()) if k not in filter_keys) - return "%s"%cpy + cpy = dict((k, v) for (k, v) in list(self.items()) if k not in filter_keys) + return "%s" % cpy + + +_var_keywords = { + n: 0 + for n in "constant constexpr reference pointer static typedefs class fundamental unresolved".split() +} class _CppVariable(dict): - def _name_stack_helper( self, stack ): + def _name_stack_helper(self, stack): stack = list(stack) - if '=' not in stack: # TODO refactor me + if "=" not in stack: # TODO refactor me # check for array[n] and deal with funny array syntax: "int myvar:99" array = [] - while stack and stack[-1].isdigit(): array.append( stack.pop() ) - if array: array.reverse(); self['array'] = int(''.join(array)) - if stack and stack[-1].endswith(':'): stack[-1] = stack[-1][:-1] - - while stack and not stack[-1]: stack.pop() # can be empty + while stack and stack[-1].isdigit(): + array.append(stack.pop()) + if array: + array.reverse() + self["array"] = int("".join(array)) + if stack and stack[-1].endswith(":"): + stack[-1] = stack[-1][:-1] + + while stack and not stack[-1]: + stack.pop() # can be empty return stack def init(self): - #assert self['name'] # allow unnamed variables, methods like this: "void func(void);" + # assert self['name'] # allow unnamed variables, methods like this: "void func(void);" a = [] - self['aliases'] = []; self['parent'] = None; self['typedef'] = None - for key in 'constant reference pointer static typedefs class fundamental unresolved'.split(): - self[ key ] = 0 - for b in self['type'].split(): - if b == '__const__': b = 'const' - a.append( b ) - self['type'] = ' '.join( a ) - - -class CppVariable( _CppVariable ): - """Takes a name stack and turns it into a method - - Contains the following Keys: - self['type'] - Type for the variable (ex. "const string &") - self['name'] - Name of the variable (ex. "numItems") - self['namespace'] - Namespace containing the enum - self['desc'] - Description of the variable if part of a method (optional) - self['doxygen'] - Doxygen comments associated with the method if they exist - self['defaultValue'] - Default value of the variable, this key will only - exist if there is a default value - self['extern'] - True if its an extern, false if not + self["aliases"] = [] + self["parent"] = None + self["typedef"] = None + self.update(_var_keywords) + for b in self["type"].split(): + if b == "__const__": + b = "const" + a.append(b) + self["type"] = " ".join(a) + + +class CppVariable(_CppVariable): + """ + Dictionary that contains at least the following keys: + + * ``type`` - Type for the variable (ex. "const string &") + * ``name`` - Name of the variable (ex. "numItems") + * ``namespace`` - Namespace + * ``desc`` - If a method/function parameter, doxygen description for this parameter (optional) + * ``doxygen`` - If a normal property/variable, doxygen description for this + * ``default`` - Default value of the variable, this key will only + exist if there is a default value + * ``extern`` - True if its an extern, False if not + * ``parent`` - If not None, either the class this is a property of, or the + method this variable is a parameter in + * ``access`` - Anything in supportedAccessSpecifier """ + Vars = [] - def __init__(self, nameStack, **kwargs): - debug_print("trace %s"%nameStack) + + def __init__(self, nameStack, doxygen, location, is_var=True, **kwargs): + debug_print("var trace %s", nameStack) if len(nameStack) and nameStack[0] == "extern": - self['extern'] = True + self["extern"] = True del nameStack[0] else: - self['extern'] = False - + self["extern"] = False + + if "=" in nameStack: + self["type"] = " ".join(nameStack[: nameStack.index("=") - 1]) + self["name"] = nameStack[nameStack.index("=") - 1] + default = " ".join(nameStack[nameStack.index("=") + 1 :]) + nameStack = nameStack[: nameStack.index("=")] + default = self._filter_name(default) + self["default"] = default + # backwards compat; deprecate camelCase in dicts + self["defaultValue"] = default + elif "{" in nameStack and "}" in nameStack: + posBracket = nameStack.index("{") + self["type"] = " ".join(nameStack[: posBracket - 1]) + self["name"] = nameStack[posBracket - 1] + default = " ".join(nameStack[posBracket + 1 : -1]) + nameStack = nameStack[:posBracket] + default = self._filter_name(default) + self["default"] = default + # backwards compat; deprecate camelCase in dicts + self["defaultValue"] = default + _stack_ = nameStack - if "[" in nameStack: #strip off array informatin - arrayStack = nameStack[nameStack.index("["):] - if nameStack.count("[") > 1: + self["array"] = 0 + while "]" in nameStack[-1]: # strip off array information + arrayPos = len(nameStack) - 1 - nameStack[::-1].index("[") + arrayStack = nameStack[arrayPos:] + if self["array"] == 1: debug_print("Multi dimensional array") - debug_print("arrayStack=%s"%arrayStack) - nums = filter(lambda x: x.isdigit(), arrayStack) - # Calculate size by multiplying all dimensions - p = 1 - for n in nums: - p *= int(n) - #Multi dimensional array - self["array_size"] = p + debug_print("arrayStack=%s", arrayStack) + if len(arrayStack) == 3: + n = arrayStack[1] + # Multi dimensional array + if not "multi_dimensional_array_size" in self: + self["multi_dimensional_array_size"] = self["array_size"] + self["multi_dimensional_array_size"] += "x" + n + self["array_size"] = str(int(self["array_size"]) * int(n)) self["multi_dimensional_array"] = 1 - self["multi_dimensional_array_size"] = "x".join(nums) else: debug_print("Array") if len(arrayStack) == 3: - self["array_size"] = arrayStack[1] - nameStack = nameStack[:nameStack.index("[")] + self["array_size"] = arrayStack[1] + nameStack = nameStack[:arrayPos] self["array"] = 1 - else: - self["array"] = 0 - nameStack = self._name_stack_helper( nameStack ) - global doxygenCommentCache - if len(doxygenCommentCache): - self["doxygen"] = doxygenCommentCache - doxygenCommentCache = "" + nameStack = self._name_stack_helper(nameStack) - debug_print( "Variable: %s"%nameStack ) + if doxygen: + self["doxygen"] = doxygen - self["line_number"] = detect_lineno(nameStack[0]) - self["function_pointer"] = 0 + debug_print("Variable: %s", nameStack) - if (len(nameStack) < 2): # +++ - if len(nameStack) == 1: self['type'] = nameStack[0]; self['name'] = '' - else: error_print(_stack_); assert 0 + set_location_info(self, location) + self["function_pointer"] = 0 - elif is_function_pointer_stack(nameStack): #function pointer - self["type"] = " ".join(nameStack[:nameStack.index("(") + 2] + nameStack[nameStack.index(")") :]) - self["name"] = " ".join(nameStack[nameStack.index("(") + 2 : nameStack.index(")")]) + if len(nameStack) < 2: # +++ + if len(nameStack) == 1: + self["type"] = nameStack[0] + self["name"] = "" + else: + error_print("%s", _stack_) + assert 0 + + elif is_function_pointer_stack(nameStack): # function pointer + self["type"] = " ".join( + nameStack[: nameStack.index("(") + 2] + + nameStack[nameStack.index(")") :] + ) + self["name"] = " ".join( + nameStack[nameStack.index("(") + 2 : nameStack.index(")")] + ) self["function_pointer"] = 1 - elif ("=" in nameStack): - self["type"] = " ".join(nameStack[:nameStack.index("=") - 1]) - self["name"] = nameStack[nameStack.index("=") - 1] - self["defaultValue"] = " ".join(nameStack[nameStack.index("=") + 1:]) # deprecate camelCase in dicts - self['default'] = " ".join(nameStack[nameStack.index("=") + 1:]) - - elif is_fundamental(nameStack[-1]) or nameStack[-1] in ['>', '<' , ':', '.']: - #Un named parameter + elif ( + is_fundamental(nameStack[-1]) + or nameStack[-1] in [">", "<", ":", "."] + or (len(nameStack) > 2 and nameStack[-2] == "::") + ): + # Un named parameter self["type"] = " ".join(nameStack) self["name"] = "" - else: # common case + else: # common case self["type"] = " ".join(nameStack[:-1]) self["name"] = nameStack[-1] - self["type"] = self["type"].replace(" :",":") - self["type"] = self["type"].replace(": ",":") - self["type"] = self["type"].replace(" <","<") - self["type"] = self["type"].replace(" >",">").replace(">>", "> >").replace(">>", "> >") - self["type"] = self["type"].replace(" ,",",") - #Optional doxygen description + self["type"] = self._filter_name(self["type"]) + + # Optional doxygen description try: self["desc"] = kwargs["doxyVarDesc"][self["name"]] - except: pass + except: + pass self.init() - CppVariable.Vars.append( self ) # save and resolve later - + if is_var: + CppVariable.Vars.append(self) # save and resolve later + + def _filter_name(self, name): + name = name.replace(" :", ":").replace(": ", ":") + name = name.replace(" < ", "<") + name = name.replace(" > ", "> ").replace(">>", "> >") + name = name.replace(") >", ")>") + name = name.replace(" {", "{").replace(" }", "}") + name = name.replace(" ,", ",") + return name + def __str__(self): - keys_white_list = ['constant','name','reference','type','static','pointer','desc', 'line_number', 'extern'] - cpy = dict((k,v) for (k,v) in list(self.items()) if k in keys_white_list) - if "array_size" in self: cpy["array_size"] = self["array_size"] - return "%s"%cpy + keys_white_list = [ + "constant", + "name", + "reference", + "type", + "static", + "pointer", + "desc", + "line_number", + "extern", + "access", + ] + cpy = dict((k, v) for (k, v) in list(self.items()) if k in keys_white_list) + if "array_size" in self: + cpy["array_size"] = self["array_size"] + return "%s" % cpy + class _CppEnum(dict): - def resolve_enum_values( self, values ): + def resolve_enum_values(self, values): """Evaluates the values list of dictionaries passed in and figures out what the enum value for each enum is editing in place: - - Example: + + Example From: [{'name': 'ORANGE'}, {'name': 'RED'}, {'name': 'GREEN', 'value': '8'}] @@ -1027,833 +1357,1071 @@ def resolve_enum_values( self, values ): {'name': 'RED', 'value': 1}, {'name': 'GREEN', 'value': 8}] """ - t = int; i = 0 - names = [ v['name'] for v in values ] + t = int + i = 0 + names = [v["name"] for v in values] for v in values: - if 'value' in v: - a = v['value'].strip() + if "value" in v: + a = v["value"].strip() # Remove single quotes from single quoted chars (unless part of some expression if len(a) == 3 and a[0] == "'" and a[2] == "'": - a = v['value'] = a[1] - if a.lower().startswith("0x"): + a = v["value"] = a[1] + a = i = ord(a) + elif a.lower().startswith("0x"): try: - i = a = int(a , 16) - except:pass + i = a = int(a, 16) + except: + pass elif a.isdigit(): - i = a = int( a ) + i = a = int(a) elif a in names: for other in values: - if other['name'] == a: - v['value'] = other['value'] + if other["name"] == a: + v["value"] = other["value"] break - elif '"' in a or "'" in a: t = str # only if there are quotes it this a string enum + elif '"' in a or "'" in a: + t = str # only if there are quotes it this a string enum else: try: a = i = ord(a) - except: pass - #Allow access of what is in the file pre-convert if converted - if v['value'] != str(a): - v['raw_value'] = v['value'] - v['value'] = a - else: v['value'] = i + except: + pass + # Allow access of what is in the file pre-convert if converted + if v["value"] != str(a): + v["raw_value"] = v["value"] + v["value"] = a + else: + v["value"] = i try: - v['value'] = v['value'].replace(" < < ", " << ").replace(" >> ", " >> ") - except: pass + v["value"] = v["value"].replace(" < < ", " << ").replace(" >> ", " >> ") + except: + pass i += 1 - return t + self["type"] = t + class CppEnum(_CppEnum): - """Takes a name stack and turns it into an Enum - - Contains the following Keys: - self['name'] - Name of the enum (ex. "ItemState") - self['namespace'] - Namespace containing the enum - self['values'] - List of values where the values are a dictionary of the - form {"name": name of the key (ex. "PARSING_HEADER"), - "value": Specified value of the enum, this key will only exist - if a value for a given enum value was defined - } + """Contains the following keys: + + * ``name`` - Name of the enum (ex. "ItemState") + * ``namespace`` - Namespace containing the enum + * ``isclass`` - True if created via 'enum class' or 'enum struct' + * ``values`` - List of values. The values are a dictionary with + the following key/values: + + - ``name`` - name of the key (ex. "PARSING_HEADER"), + - ``value`` - Specified value of the enum, this key will only exist + if a value for a given enum value was defined """ - def __init__(self, nameStack): - global doxygenCommentCache - if len(doxygenCommentCache): - self["doxygen"] = doxygenCommentCache - doxygenCommentCache = "" - if len(nameStack) == 3 and nameStack[0] == "enum": - debug_print("Created enum as just name/value") - self["name"] = nameStack[1] - self["instances"]=[nameStack[2]] - if len(nameStack) < 4 or "{" not in nameStack or "}" not in nameStack: - #Not enough stuff for an enum - debug_print("Bad enum") - return - valueList = [] - self["line_number"] = detect_lineno(nameStack[0]) - #Figure out what values it has - valueStack = nameStack[nameStack.index('{') + 1: nameStack.index('}')] - while len(valueStack): - tmpStack = [] - if "," in valueStack: - tmpStack = valueStack[:valueStack.index(",")] - valueStack = valueStack[valueStack.index(",") + 1:] - else: - tmpStack = valueStack - valueStack = [] - d = {} - if len(tmpStack) == 1: d["name"] = tmpStack[0] - elif len(tmpStack) >= 3 and tmpStack[1] == "=": - d["name"] = tmpStack[0]; d["value"] = " ".join(tmpStack[2:]) - elif len(tmpStack) == 2 and tmpStack[1] == "=": - debug_print( "WARN-enum: parser missed value for %s"%tmpStack[0] ) - d["name"] = tmpStack[0] - - if d: valueList.append( d ) - - if len(valueList): - self['type'] = self.resolve_enum_values( valueList ) # returns int for standard enum - self["values"] = valueList - else: - warning_print( 'WARN-enum: empty enum %s'%nameStack ) - return - #Figure out if it has a name - preBraceStack = nameStack[:nameStack.index("{")] - postBraceStack = nameStack[nameStack.index("}") + 1:] - self["typedef"] = False - if (len(preBraceStack) == 4 and ":" in nameStack and "typedef" not in nameStack): - # C++11 specify enum type with "enum : ..." syntax - self["name"] = preBraceStack[1] - self["type"] = preBraceStack[3] - elif (len(preBraceStack) == 2 and "typedef" not in nameStack): - # enum "enum ..." syntax - self["name"] = preBraceStack[1] - elif len(postBraceStack) and "typedef" in nameStack: - self["name"] = " ".join(postBraceStack) - self["typedef"] = True - else: warning_print( 'WARN-enum: nameless enum %s'%nameStack ) - #See if there are instances of this - if "typedef" not in nameStack and len(postBraceStack): - self["instances"] = [] - for var in postBraceStack: - if "," in var: - continue - self["instances"].append(var) + + def __init__(self, name, doxygen, location): + if doxygen: + self["doxygen"] = doxygen + if name: + self["name"] = name self["namespace"] = "" + self["typedef"] = False + self["isclass"] = False + self["values"] = [] + set_location_info(self, location) + + +class _CppPreprocessorLiteral(dict): + """Implementation for #pragmas, #defines and #includes, contains the + following keys: + + * ``value`` the value literal of the preprocessor item + * ``line_number`` line number at which the item was found + """ + + def __init__(self, macro, location): + self["value"] = re.split("[\t ]+", macro, 1)[1].strip() + set_location_info(self, location) + + def __str__(self): + return self["value"] -class CppStruct(dict): - Structs = [] - def __init__(self, nameStack): - if len(nameStack) >= 2: self['type'] = nameStack[1] - else: self['type'] = None - self['fields'] = [] - self.Structs.append( self ) - global curLine - self["line_number"] = curLine +class CppExternTemplate(dict): + pass + + +# Implementation is shared between CppPragma, CppDefine, CppInclude but they are +# distinct so that they may diverge if required without interface-breaking +# changes +class CppPragma(_CppPreprocessorLiteral): + pass + + +class CppDefine(_CppPreprocessorLiteral): + pass + + +class CppInclude(_CppPreprocessorLiteral): + pass + C99_NONSTANDARD = { - 'int8' : 'signed char', - 'int16' : 'short int', - 'int32' : 'int', - 'int64' : 'int64_t', # this can be: long int (64bit), or long long int (32bit) - 'uint' : 'unsigned int', - 'uint8' : 'unsigned char', - 'uint16' : 'unsigned short int', - 'uint32' : 'unsigned int', - 'uint64' : 'uint64_t', # depends on host bits + "int8": "signed char", + "int16": "short int", + "int32": "int", + "int64": "int64_t", # this can be: long int (64bit), or long long int (32bit) + "uint": "unsigned int", + "uint8": "unsigned char", + "uint16": "unsigned short int", + "uint32": "unsigned int", + "uint64": "uint64_t", # depends on host bits } -def standardize_fundamental( s ): - if s in C99_NONSTANDARD: return C99_NONSTANDARD[ s ] - else: return s +def standardize_fundamental(s): + if s in C99_NONSTANDARD: + return C99_NONSTANDARD[s] + else: + return s class Resolver(object): - C_FUNDAMENTAL = 'size_t unsigned signed bool char wchar short int float double long void'.split() - C_FUNDAMENTAL += 'struct union enum'.split() + C_FUNDAMENTAL = "size_t unsigned signed bool char wchar short int float double long void".split() + C_FUNDAMENTAL += "struct union enum".split() + C_FUNDAMENTAL = set(C_FUNDAMENTAL) + C_MODIFIERS = "* & const constexpr static mutable".split() + C_MODIFIERS = set(C_MODIFIERS) + + C_KEYWORDS = "extern virtual static explicit inline friend constexpr".split() + C_KEYWORDS = set(C_KEYWORDS) - SubTypedefs = {} # TODO deprecate? NAMESPACES = [] CLASSES = {} - STRUCTS = {} def initextra(self): self.typedefs = {} self.typedefs_order = [] self.classes_order = [] - self.structs = Resolver.STRUCTS - self.structs_order = [] - self.namespaces = Resolver.NAMESPACES # save all namespaces - self.curStruct = None - self.stack = [] # full name stack, good idea to keep both stacks? (simple stack and full stack) - self._classes_brace_level = {} # class name : level - self._structs_brace_level = {} # struct type : level - self._method_body = None - self._forward_decls = [] - self._template_typenames = [] # template - - def current_namespace(self): return self.cur_namespace(True) + self.namespaces = Resolver.NAMESPACES # save all namespaces + self.stack = ( + [] + ) # full name stack, good idea to keep both stacks? (simple stack and full stack) + self._classes_brace_level = {} # class name : level + self._forward_decls = {} # name: namespace + self._template_typenames = [] # template + + def current_namespace(self): + return self.cur_namespace(True) def cur_namespace(self, add_double_colon=False): rtn = "" i = 0 while i < len(self.nameSpaces): rtn += self.nameSpaces[i] - if add_double_colon or i < len(self.nameSpaces) - 1: rtn += "::" - i+=1 + if add_double_colon or i < len(self.nameSpaces) - 1: + rtn += "::" + i += 1 return rtn + def cur_linkage(self): + if len(self.linkage_stack): + return self.linkage_stack[-1] + return "" - def guess_ctypes_type( self, string ): - pointers = string.count('*') - string = string.replace('*','') + def guess_ctypes_type(self, string): + pointers = string.count("*") + string = string.replace("*", "") a = string.split() - if 'unsigned' in a: u = 'u' - else: u = '' - if 'long' in a and 'double' in a: b = 'longdouble' # there is no ctypes.c_ulongdouble (this is a 64bit float?) - elif a.count('long') == 2 and 'int' in a: b = '%sint64' %u - elif a.count('long') == 2: b = '%slonglong' %u - elif 'long' in a: b = '%slong' %u - elif 'double' in a: b = 'double' # no udouble in ctypes - elif 'short' in a: b = '%sshort' %u - elif 'char' in a: b = '%schar' %u - elif 'wchar' in a: b = 'wchar' - elif 'bool' in a: b = 'bool' - elif 'float' in a: b = 'float' - - elif 'int' in a: b = '%sint' %u - elif 'int8' in a: b = 'int8' - elif 'int16' in a: b = 'int16' - elif 'int32' in a: b = 'int32' - elif 'int64' in a: b = 'int64' - - elif 'uint' in a: b = 'uint' - elif 'uint8' in a: b = 'uint8' - elif 'uint16' in a: b = 'uint16' - elif 'uint32' in a: b = 'uint32' - elif 'uint64' in a: b = 'uint64' - - elif 'size_t' in a: b = 'size_t' - elif 'void' in a: b = 'void_p' - - elif string in 'struct union'.split(): b = 'void_p' # what should be done here? don't trust struct, it could be a class, no need to expose via ctypes - else: b = 'void_p' - - if not pointers: return 'ctypes.c_%s' %b + if "unsigned" in a: + u = "u" + else: + u = "" + if "long" in a and "double" in a: + b = "longdouble" # there is no ctypes.c_ulongdouble (this is a 64bit float?) + elif a.count("long") == 2 and "int" in a: + b = "%sint64" % u + elif a.count("long") == 2: + b = "%slonglong" % u + elif "long" in a: + b = "%slong" % u + elif "double" in a: + b = "double" # no udouble in ctypes + elif "short" in a: + b = "%sshort" % u + elif "char" in a: + b = "%schar" % u + elif "wchar" in a: + b = "wchar" + elif "bool" in a: + b = "bool" + elif "float" in a: + b = "float" + + elif "int" in a: + b = "%sint" % u + elif "int8" in a: + b = "int8" + elif "int16" in a: + b = "int16" + elif "int32" in a: + b = "int32" + elif "int64" in a: + b = "int64" + + elif "uint" in a: + b = "uint" + elif "uint8" in a: + b = "uint8" + elif "uint16" in a: + b = "uint16" + elif "uint32" in a: + b = "uint32" + elif "uint64" in a: + b = "uint64" + + elif "size_t" in a: + b = "size_t" + elif "void" in a: + b = "void_p" + + elif string in ("struct", "union"): + b = "void_p" # what should be done here? don't trust struct, it could be a class, no need to expose via ctypes else: - x = '' - for i in range(pointers): x += 'ctypes.POINTER(' - x += 'ctypes.c_%s' %b - x += ')' * pointers + b = "void_p" + + if not pointers: + return "ctypes.c_%s" % b + else: + x = "" + for i in range(pointers): + x += "ctypes.POINTER(" + x += "ctypes.c_%s" % b + x += ")" * pointers return x - def resolve_type( self, string, result ): # recursive - ''' + def _remove_modifiers(self, vtype): + return " ".join(x for x in vtype.split() if x not in self.C_MODIFIERS) + + def _create_raw_type(self, vtype): + lt = vtype.find("<") + if lt != -1: + gt = vtype.rfind(">") + vtype = ( + self._remove_modifiers(vtype[:lt]) + + vtype[lt : gt + 1] + + self._remove_modifiers(vtype[gt + 1 :]) + ) + else: + vtype = self._remove_modifiers(vtype) + + return vtype + + def resolve_type(self, string, result): # recursive + """ keeps track of useful things like: how many pointers, number of typedefs, is fundamental or a class, etc... - ''' + """ ## be careful with templates, what is inside can be a pointer but the overall type is not a pointer ## these come before a template - s = string.split('<')[0] - result[ 'constant' ] += s.split().count('const') - result[ 'static' ] += s.split().count('static') - result[ 'mutable' ] = 'mutable' in s.split() + s = string.split("<")[0].split() + result["constant"] += s.count("const") + result["constexpr"] += s.count("constexpr") + result["static"] += s.count("static") + result["mutable"] = "mutable" in s ## these come after a template - s = string.split('>')[-1] - result[ 'pointer' ] += s.count('*') - result[ 'reference' ] += s.count('&') - - - x = string; alias = False - for a in '* & const static mutable'.split(): x = x.replace(a,'') + s = string.split(">")[-1] + result["pointer"] += s.count("*") + result["reference"] += s.count("&") + + x = string + alias = False + for a in self.C_MODIFIERS: + x = x.replace(a, "") for y in x.split(): - if y not in self.C_FUNDAMENTAL: alias = y; break + if y not in self.C_FUNDAMENTAL: + alias = y + break - #if alias == 'class': + # if alias == 'class': # result['class'] = result['name'] # forward decl of class # result['forward_decl'] = True - if alias == '__extension__': result['fundamental_extension'] = True + if alias == "__extension__": + result["fundamental_extension"] = True elif alias: - result['aliases'].append( alias ) + if alias in result["aliases"]: + # already resolved + return + result["aliases"].append(alias) if alias in C99_NONSTANDARD: - result['type'] = C99_NONSTANDARD[ alias ] - result['typedef'] = alias - result['typedefs'] += 1 + result["type"] = C99_NONSTANDARD[alias] + result["typedef"] = alias + result["typedefs"] += 1 elif alias in self.typedefs: - result['typedefs'] += 1 - result['typedef'] = alias - self.resolve_type( self.typedefs[alias], result ) + result["typedefs"] += 1 + result["typedef"] = alias + self.resolve_type(self.typedefs[alias], result) elif alias in self.classes: - klass = self.classes[alias]; result['fundamental'] = False - result['class'] = klass - result['unresolved'] = False - else: result['unresolved'] = True - else: - result['fundamental'] = True - result['unresolved'] = False + klass = self.classes[alias] + result["fundamental"] = False + result["class"] = klass + result["unresolved"] = False + else: + used = None + + # Search for in parents + if not used: + parent = result["parent"] + while parent: + p_using = parent.get("using") + if p_using: + used = p_using.get(alias) + if used: + break + lookup = getattr(parent, "_lookup_type", None) + if lookup: + used = lookup(alias) + if used: + break + parent = parent["parent"] + + if not used and self.using: + # search for type in all enclosing namespaces + # TODO: would be nice if namespaces were an object? + for ns in _iter_ns_str_reversed(result.get("namespace", "")): + nsalias = ns + alias + used = self.using.get(nsalias) + if used: + break + if used: + for i in ("enum", "type", "namespace", "ctypes_type", "raw_type"): + if i in used: + result[i] = used[i] + result["unresolved"] = False + else: + result["fundamental"] = True + result["unresolved"] = False def finalize_vars(self): - for s in CppStruct.Structs: # vars within structs can be ignored if they do not resolve - for var in s['fields']: var['parent'] = s['type'] - #for c in self.classes.values(): + # for c in self.classes.values(): # for var in c.get_all_properties(): var['parent'] = c['name'] ## RESOLVE ## for var in CppVariable.Vars: - self.resolve_type( var['type'], var ) - #if 'method' in var and var['method']['name'] == '_notifyCurrentCamera': print(var); assert 0 + self.resolve_type(var["type"], var) + # if 'method' in var and var['method']['name'] == '_notifyCurrentCamera': print(var); assert 0 # then find concrete type and best guess ctypes type # - for var in CppVariable.Vars: - if not var['aliases']: #var['fundamental']: - var['ctypes_type'] = self.guess_ctypes_type( var['type'] ) + for var in CppVariable.Vars: + if not var["aliases"]: # var['fundamental']: + var["ctypes_type"] = self.guess_ctypes_type(var["type"]) else: - var['unresolved'] = False # below may test to True - if var['class']: - var['ctypes_type'] = 'ctypes.c_void_p' + var["unresolved"] = False # below may test to True + if var["class"]: + var["ctypes_type"] = "ctypes.c_void_p" else: - assert var['aliases'] - tag = var['aliases'][0] + assert var["aliases"] + tag = var["aliases"][0] klass = None nestedEnum = None nestedStruct = None nestedTypedef = None - if 'method' in var and 'parent' in list(var['method'].keys()): - klass = var['method']['parent'] - if tag in var['method']['parent']._public_enums: - nestedEnum = var['method']['parent']._public_enums[ tag ] - elif tag in var['method']['parent']._public_structs: - nestedStruct = var['method']['parent']._public_structs[ tag ] - elif tag in var['method']['parent']._public_typedefs: - nestedTypedef = var['method']['parent']._public_typedefs[ tag ] + parent = var["parent"] + while parent: + nestedEnum = getattr(parent, "_public_enums", {}).get(tag) + if nestedEnum: + break + nestedTypedef = getattr(parent, "_public_typedefs", {}).get(tag) + if nestedTypedef: + break + parent = parent["parent"] - if '<' in tag: # should also contain '>' - var['template'] = tag # do not resolve templates - var['ctypes_type'] = 'ctypes.c_void_p' - var['unresolved'] = True + if "<" in tag: # should also contain '>' + var["template"] = tag # do not resolve templates + var["ctypes_type"] = "ctypes.c_void_p" + var["unresolved"] = True elif nestedEnum: enum = nestedEnum - if enum['type'] is int: - var['ctypes_type'] = 'ctypes.c_int' - var['raw_type'] = 'int' + etype = enum.get("type") + if etype is int: + var["ctypes_type"] = "ctypes.c_int" + var["raw_type"] = "int" - elif enum['type'] is str: - var['ctypes_type'] = 'ctypes.c_char_p' - var['raw_type'] = 'char*' + elif etype is str: + var["ctypes_type"] = "ctypes.c_char_p" + var["raw_type"] = "char*" - var['enum'] = var['method']['path'] + '::' + enum['name'] - var['fundamental'] = True + if "method" in var: + var["enum"] = var["method"]["path"] + "::" + enum["name"] + else: + var["enum"] = enum["name"] + var["fundamental"] = True elif nestedStruct: - var['ctypes_type'] = 'ctypes.c_void_p' - var['raw_type'] = var['method']['path'] + '::' + nestedStruct['type'] - var['fundamental'] = False + var["ctypes_type"] = "ctypes.c_void_p" + var["raw_type"] = ( + var["method"]["path"] + "::" + nestedStruct["type"] + ) + var["fundamental"] = False elif nestedTypedef: - var['fundamental'] = is_fundamental( nestedTypedef ) - if not var['fundamental']: - var['raw_type'] = var['method']['path'] + '::' + tag + var["fundamental"] = is_fundamental(nestedTypedef) + if not var["fundamental"] and "method" in var: + var["raw_type"] = var["method"]["path"] + "::" + tag else: _tag = tag - if '::' in tag and tag.split('::')[0] in self.namespaces: tag = tag.split('::')[-1] - con = self.concrete_typedef( _tag ) + if "::" in tag and tag.split("::")[0] in self.namespaces: + tag = tag.split("::")[-1] + con = self.concrete_typedef(_tag) if con: - var['concrete_type'] = con - var['ctypes_type'] = self.guess_ctypes_type( var['concrete_type'] ) - - elif tag in self.structs: - trace_print( 'STRUCT', var ) - var['struct'] = tag - var['ctypes_type'] = 'ctypes.c_void_p' - var['raw_type'] = self.structs[tag]['namespace'] + '::' + tag + var["concrete_type"] = con + var["ctypes_type"] = self.guess_ctypes_type( + var["concrete_type"] + ) elif tag in self._forward_decls: - var['forward_declared'] = tag - var['ctypes_type'] = 'ctypes.c_void_p' + var["forward_declared"] = tag + var["namespace"] = self._forward_decls[tag] + var["ctypes_type"] = "ctypes.c_void_p" elif tag in self.global_enums: - enum = self.global_enums[ tag ] - if enum['type'] is int: - var['ctypes_type'] = 'ctypes.c_int' - var['raw_type'] = 'int' - elif enum['type'] is str: - var['ctypes_type'] = 'ctypes.c_char_p' - var['raw_type'] = 'char*' - var['enum'] = enum['namespace'] + enum['name'] - var['fundamental'] = True - - - elif var['parent']: - warning_print( 'WARN unresolved %s'%_tag) - var['ctypes_type'] = 'ctypes.c_void_p' - var['unresolved'] = True - - - elif tag.count('::')==1: - trace_print( 'trying to find nested something in', tag ) - a = tag.split('::')[0] - b = tag.split('::')[-1] - if a in self.classes: # a::b is most likely something nested in a class - klass = self.classes[ a ] + enum = self.global_enums[tag] + enum_type = enum.get("type") + if enum_type is int: + var["ctypes_type"] = "ctypes.c_int" + var["raw_type"] = "int" + elif enum_type is str: + var["ctypes_type"] = "ctypes.c_char_p" + var["raw_type"] = "char*" + var["enum"] = enum["namespace"] + enum["name"] + var["fundamental"] = True + + elif var["parent"] and var["unresolved"]: + warning_print("WARN unresolved %s", _tag) + var["ctypes_type"] = "ctypes.c_void_p" + var["unresolved"] = True + + elif tag.count("::") == 1: + trace_print("trying to find nested something in", tag) + a = tag.split("::")[0] + b = tag.split("::")[-1] + if ( + a in self.classes + ): # a::b is most likely something nested in a class + klass = self.classes[a] if b in klass._public_enums: - trace_print( '...found nested enum', b ) - enum = klass._public_enums[ b ] - if enum['type'] is int: - var['ctypes_type'] = 'ctypes.c_int' - var['raw_type'] = 'int' - elif enum['type'] is str: - var['ctypes_type'] = 'ctypes.c_char_p' - var['raw_type'] = 'char*' + trace_print("...found nested enum", b) + enum = klass._public_enums[b] + etype = enum.get("type") + if etype is int: + var["ctypes_type"] = "ctypes.c_int" + var["raw_type"] = "int" + elif etype is str: + var["ctypes_type"] = "ctypes.c_char_p" + var["raw_type"] = "char*" try: - if 'method' in var: var['enum'] = var['method']['path'] + '::' + enum['name'] - else: # class property - var['unresolved'] = True + if "method" in var: + var["enum"] = ( + var["method"]["path"] + + "::" + + enum["name"] + ) + else: # class property + var["unresolved"] = True except: - var['unresolved'] = True - - var['fundamental'] = True + var["unresolved"] = True + + var["fundamental"] = True - else: var['unresolved'] = True # TODO klass._public_xxx + else: + var["unresolved"] = True # TODO klass._public_xxx - elif a in self.namespaces: # a::b can also be a nested namespace + elif ( + a in self.namespaces + ): # a::b can also be a nested namespace if b in self.global_enums: - enum = self.global_enums[ b ] + enum = self.global_enums[b] trace_print(enum) trace_print(var) assert 0 - elif b in self.global_enums: # falling back, this is a big ugly - enum = self.global_enums[ b ] - assert a in enum['namespace'].split('::') - if enum['type'] is int: - var['ctypes_type'] = 'ctypes.c_int' - var['raw_type'] = 'int' - elif enum['type'] is str: - var['ctypes_type'] = 'ctypes.c_char_p' - var['raw_type'] = 'char*' - var['fundamental'] = True - - else: # boost::gets::crazy - trace_print('NAMESPACES', self.namespaces) - trace_print( a, b ) - trace_print( '---- boost gets crazy ----' ) - var['ctypes_type'] = 'ctypes.c_void_p' - var['unresolved'] = True - - - elif 'namespace' in var and self.concrete_typedef(var['namespace']+tag): - #print( 'TRYING WITH NS', var['namespace'] ) - con = self.concrete_typedef( var['namespace']+tag ) + elif ( + b in self.global_enums + ): # falling back, this is a big ugly + enum = self.global_enums[b] + assert a in enum["namespace"].split("::") + etype = enum.get("type") + if etype is int: + var["ctypes_type"] = "ctypes.c_int" + var["raw_type"] = "int" + elif etype is str: + var["ctypes_type"] = "ctypes.c_char_p" + var["raw_type"] = "char*" + var["fundamental"] = True + + else: # boost::gets::crazy + trace_print("NAMESPACES", self.namespaces) + trace_print(a, b) + trace_print("---- boost gets crazy ----") + var["ctypes_type"] = "ctypes.c_void_p" + var["unresolved"] = True + + elif "namespace" in var and self.concrete_typedef( + var["namespace"] + tag + ): + # print( 'TRYING WITH NS', var['namespace'] ) + con = self.concrete_typedef(var["namespace"] + tag) if con: - var['typedef'] = var['namespace']+tag - var['type'] = con - if 'struct' in con.split(): - var['raw_type'] = var['typedef'] - var['ctypes_type'] = 'ctypes.c_void_p' + var["typedef"] = var["namespace"] + tag + var["type"] = con + if "struct" in con.split(): + var["raw_type"] = var["typedef"] + var["ctypes_type"] = "ctypes.c_void_p" else: - self.resolve_type( var['type'], var ) - var['ctypes_type'] = self.guess_ctypes_type( var['type'] ) - - elif '::' in var: - var['ctypes_type'] = 'ctypes.c_void_p' - var['unresolved'] = True - - elif tag in self.SubTypedefs: # TODO remove SubTypedefs - if 'property_of_class' in var or 'property_of_struct' in var: - trace_print( 'class:', self.SubTypedefs[ tag ], 'tag:', tag ) - var['typedef'] = self.SubTypedefs[ tag ] # class name - var['ctypes_type'] = 'ctypes.c_void_p' - else: - trace_print( "WARN-this should almost never happen!" ) - trace_print( var ); trace_print('-'*80) - var['unresolved'] = True + self.resolve_type(var["type"], var) + var["ctypes_type"] = self.guess_ctypes_type( + var["type"] + ) - elif tag in self._template_typenames: - var['typename'] = tag - var['ctypes_type'] = 'ctypes.c_void_p' - var['unresolved'] = True # TODO, how to deal with templates? + elif "::" in var: + var["ctypes_type"] = "ctypes.c_void_p" + var["unresolved"] = True - elif tag.startswith('_'): # assume starting with underscore is not important for wrapping - warning_print( 'WARN unresolved %s'%_tag) - var['ctypes_type'] = 'ctypes.c_void_p' - var['unresolved'] = True + elif tag in self._template_typenames: + var["typename"] = tag + var["ctypes_type"] = "ctypes.c_void_p" + var["unresolved"] = ( + True # TODO, how to deal with templates? + ) + + elif tag.startswith( + "_" + ): # assume starting with underscore is not important for wrapping + warning_print("WARN unresolved %s", _tag) + var["ctypes_type"] = "ctypes.c_void_p" + var["unresolved"] = True else: - trace_print( 'WARN: unknown type', var ) - assert 'property_of_class' in var or 'property_of_struct' # only allow this case - var['unresolved'] = True - + trace_print("WARN: unknown type", var) + assert ( + "property_of_class" in var or "property_of_struct" + ) # only allow this case + var["unresolved"] = True ## if not resolved and is a method param, not going to wrap these methods ## - if var['unresolved'] and 'method' in var: var['method']['unresolved_parameters'] = True - + if var["unresolved"] and "method" in var: + var["method"]["unresolved_parameters"] = True # create stripped raw_type # - p = '* & const static mutable'.split() # +++ new July7: "mutable" for var in CppVariable.Vars: - if 'raw_type' not in var: - raw = [] - for x in var['type'].split(): - if x not in p: raw.append( x ) - var['raw_type'] = ' '.join( raw ) - - #if 'AutoConstantEntry' in var['raw_type']: print(var); assert 0 - if var['class']: - if '::' not in var['raw_type']: - if not var['class']['parent']: - var['raw_type'] = var['class']['namespace'] + '::' + var['raw_type'] - elif var['class']['parent'] in self.classes: - parent = self.classes[ var['class']['parent'] ] - var['raw_type'] = parent['namespace'] + '::' + var['class']['name'] + '::' + var['raw_type'] + if "raw_type" not in var: + var["raw_type"] = self._create_raw_type(var["type"]) + + # if 'AutoConstantEntry' in var['raw_type']: print(var); assert 0 + if var["class"]: + if "::" not in var["raw_type"]: + if not var["class"]["parent"]: + var["raw_type"] = ( + var["class"]["namespace"] + "::" + var["raw_type"] + ) else: - var['unresolved'] = True - - elif '::' in var['raw_type'] and var['raw_type'].split('::')[0] not in self.namespaces: - var['raw_type'] = var['class']['namespace'] + '::' + var['raw_type'] + parent = var["class"]["parent"] + var["raw_type"] = ( + parent["namespace"] + + "::" + + var["class"]["name"] + + "::" + + var["raw_type"] + ) + + elif ( + "::" in var["raw_type"] + and var["raw_type"].split("::")[0] not in self.namespaces + ): + var["raw_type"] = ( + var["class"]["namespace"] + "::" + var["raw_type"] + ) else: - var['unresolved'] = True - - elif 'forward_declared' in var and 'namespace' in var: - if '::' not in var['raw_type']: - var['raw_type'] = var['namespace'] + var['raw_type'] - elif '::' in var['raw_type'] and var['raw_type'].split('::')[0] in self.namespaces: + var["unresolved"] = True + + elif "forward_declared" in var and "namespace" in var: + if "::" not in var["raw_type"]: + var["raw_type"] = var["namespace"] + var["raw_type"] + elif ( + "::" in var["raw_type"] + and var["raw_type"].split("::")[0] in self.namespaces + ): pass - else: trace_print('-'*80); trace_print(var); raise NotImplemented - + else: + trace_print("-" * 80) + trace_print(var) + raise NotImplementedError ## need full name space for classes in raw type ## - if var['raw_type'].startswith( '::' ): - #print(var) - #print('NAMESPACE', var['class']['namespace']) - #print( 'PARENT NS', var['class']['parent']['namespace'] ) - #assert 0 - var['unresolved'] = True - if 'method' in var: var['method']['unresolved_parameters'] = True - #var['raw_type'] = var['raw_type'][2:] - + if var["raw_type"].startswith("::"): + # print(var) + # print('NAMESPACE', var['class']['namespace']) + # print( 'PARENT NS', var['class']['parent']['namespace'] ) + # assert 0 + var["unresolved"] = True + if "method" in var: + var["method"]["unresolved_parameters"] = True + # var['raw_type'] = var['raw_type'][2:] + # Take care of #defines and #pragmas etc - trace_print("Processing precomp_macro_buf: %s"%self._precomp_macro_buf) - for m in self._precomp_macro_buf: + trace_print("Processing precomp_macro_buf:", self._precomp_macro_buf) + for m, location in self._precomp_macro_buf: macro = m.replace("\\n", "\n") + ml = macro.lower() try: - if macro.lower().startswith("#define"): - trace_print("Adding #define %s"%macro) - self.defines.append(re.split("[\t ]+", macro, 1)[1].strip()) - elif macro.lower().startswith("#pragma"): - trace_print("Adding #pragma %s"%macro) - self.pragmas.append(re.split("[\t ]+", macro, 1)[1].strip()) - elif macro.lower().startswith("#include"): - trace_print("Adding #include %s"%macro) - self.includes.append(re.split("[\t ]+", macro, 1)[1].strip()) + if ml.startswith("#define"): + trace_print("Adding #define", macro) + define = CppDefine(macro, location) + self.defines.append(define["value"]) + self.defines_detail.append(define) + elif ml.startswith("#pragma"): + trace_print("Adding #pragma", macro) + pragma = CppPragma(macro, location) + self.pragmas_detail.append(pragma) + self.pragmas.append(pragma["value"]) + elif ml.startswith("#include"): + trace_print("Adding #include", macro) + include = CppInclude(macro, location) + self.includes.append(include["value"]) + self.includes_detail.append(include) else: - debug_print("Cant detect what to do with precomp macro '%s'"%macro) - except: pass + debug_print("Cant detect what to do with precomp macro '%s'", macro) + except: + pass self._precomp_macro_buf = None - - def concrete_typedef( self, key ): + def concrete_typedef(self, key): if key not in self.typedefs: - #print( 'FAILED typedef', key ) + # print( 'FAILED typedef', key ) return None while key in self.typedefs: prev = key - key = self.typedefs[ key ] - if '<' in key or '>' in key: return prev # stop at template - if key.startswith('std::'): return key # stop at std lib + key = self.typedefs[key] + if "<" in key or ">" in key: + return prev # stop at template + if key.startswith("std::"): + return key # stop at std lib return key -class _CppHeader( Resolver ): +class _CppHeader(Resolver): def finalize(self): self.finalize_vars() # finalize classes and method returns types for cls in list(self.classes.values()): for meth in cls.get_all_methods(): - if meth['pure_virtual']: cls['abstract'] = True - - if not meth['returns_fundamental'] and meth['returns'] in C99_NONSTANDARD: - meth['returns'] = C99_NONSTANDARD[meth['returns']] - meth['returns_fundamental'] = True - - elif not meth['returns_fundamental']: # describe the return type + if meth["pure_virtual"]: + cls["abstract"] = True + + # hack + rtnType = { + "aliases": [], + "parent": cls, + "unresolved": True, + "constant": 0, + "constexpr": 0, + "static": 0, + "pointer": 0, + "reference": 0, + "typedefs": 0, + } + self.resolve_type(meth["rtnType"], rtnType) + if not rtnType["unresolved"]: + if "enum" in rtnType: + meth["rtnType"] = rtnType["enum"] + elif "raw_type" in rtnType: + meth["rtnType"] = rtnType["raw_type"] + + # TODO: all of this needs to die and be replaced by CppVariable + + if ( + not meth["returns_fundamental"] + and meth["returns"] in C99_NONSTANDARD + ): + meth["returns"] = C99_NONSTANDARD[meth["returns"]] + meth["returns_fundamental"] = True + + elif not meth["returns_fundamental"]: # describe the return type con = None - if cls['namespace'] and '::' not in meth['returns']: - con = self.concrete_typedef( cls['namespace'] + '::' + meth['returns'] ) - else: con = self.concrete_typedef( meth['returns'] ) - + if cls["namespace"] and "::" not in meth["returns"]: + con = self.concrete_typedef( + cls["namespace"] + "::" + meth["returns"] + ) + else: + con = self.concrete_typedef(meth["returns"]) if con: - meth['returns_concrete'] = con - meth['returns_fundamental'] = is_fundamental( con ) - - elif meth['returns'] in self.classes: - trace_print( 'meth returns class:', meth['returns'] ) - meth['returns_class'] = True - - elif meth['returns'] in self.SubTypedefs: - meth['returns_class'] = True - meth['returns_nested'] = self.SubTypedefs[ meth['returns'] ] - - elif meth['returns'] in cls._public_enums: - enum = cls._public_enums[ meth['returns'] ] - meth['returns_enum'] = enum['type'] - meth['returns_fundamental'] = True - if enum['type'] == int: meth['returns'] = 'int' - else: meth['returns'] = 'char*' - - elif meth['returns'] in self.global_enums: - enum = self.global_enums[ meth['returns'] ] - meth['returns_enum'] = enum['type'] - meth['returns_fundamental'] = True - if enum['type'] == int: meth['returns'] = 'int' - else: meth['returns'] = 'char*' - - elif meth['returns'].count('::')==1: - trace_print( meth ) - a,b = meth['returns'].split('::') + meth["returns_concrete"] = con + meth["returns_fundamental"] = is_fundamental(con) + + elif meth["returns"] in self.classes: + trace_print("meth returns class:", meth["returns"]) + meth["returns_class"] = True + + elif meth["returns"] in cls._public_enums: + enum = cls._public_enums[meth["returns"]] + meth["returns_enum"] = enum.get("type") + meth["returns_fundamental"] = True + if enum.get("type") == int: + meth["returns"] = "int" + else: + meth["returns"] = "char*" + + elif meth["returns"] in self.global_enums: + enum = self.global_enums[meth["returns"]] + meth["returns_enum"] = enum.get("type") + meth["returns_fundamental"] = True + if enum.get("type") == int: + meth["returns"] = "int" + else: + meth["returns"] = "char*" + + elif meth["returns"].count("::") == 1: + trace_print(meth) + a, b = meth["returns"].split("::") if a in self.namespaces: if b in self.classes: - klass = self.classes[ b ] - meth['returns_class'] = a + '::' + b - elif '<' in b and '>' in b: - warning_print( 'WARN-can not return template: %s'%b ) - meth['returns_unknown'] = True + klass = self.classes[b] + meth["returns_class"] = a + "::" + b + elif "<" in b and ">" in b: + meth["returns_unknown"] = True elif b in self.global_enums: - enum = self.global_enums[ b ] - meth['returns_enum'] = enum['type'] - meth['returns_fundamental'] = True - if enum['type'] == int: meth['returns'] = 'int' - else: meth['returns'] = 'char*' + enum = self.global_enums[b] + meth["returns_enum"] = enum.get("type") + meth["returns_fundamental"] = True + if enum.get("type") == int: + meth["returns"] = "int" + else: + meth["returns"] = "char*" - else: trace_print( a, b); trace_print( meth); meth['returns_unknown'] = True # +++ + else: + trace_print(a, b) + trace_print(meth) + meth["returns_unknown"] = True # +++ elif a in self.classes: - klass = self.classes[ a ] + klass = self.classes[a] if b in klass._public_enums: - trace_print( '...found nested enum', b ) - enum = klass._public_enums[ b ] - meth['returns_enum'] = enum['type'] - meth['returns_fundamental'] = True - if enum['type'] == int: meth['returns'] = 'int' - else: meth['returns'] = 'char*' + trace_print("...found nested enum", b) + enum = klass._public_enums[b] + meth["returns_enum"] = enum.get("type") + meth["returns_fundamental"] = True + if enum.get("type") == int: + meth["returns"] = "int" + else: + meth["returns"] = "char*" elif b in klass._public_forward_declares: - meth['returns_class'] = True + meth["returns_class"] = True elif b in klass._public_typedefs: - typedef = klass._public_typedefs[ b ] - meth['returns_fundamental'] = is_fundamental( typedef ) + typedef = klass._public_typedefs[b] + meth["returns_fundamental"] = is_fundamental(typedef) else: - trace_print( meth ) # should be a nested class, TODO fix me. - meth['returns_unknown'] = True - - elif '::' in meth['returns']: - trace_print('TODO namespace or extra nested return:', meth) - meth['returns_unknown'] = True + trace_print( + meth + ) # should be a nested class, TODO fix me. + meth["returns_unknown"] = True + + elif "::" in meth["returns"]: + trace_print("TODO namespace or extra nested return:", meth) + meth["returns_unknown"] = True else: - trace_print( 'WARN: UNKNOWN RETURN', meth['name'], meth['returns']) - meth['returns_unknown'] = True - - if meth["returns"].startswith(": : "): - meth["returns"] = meth["returns"].replace(": : ", "::") - + trace_print( + "WARN: UNKNOWN RETURN", meth["name"], meth["returns"] + ) + meth["returns_unknown"] = True + + if meth["returns"].startswith(":: "): + meth["returns"] = meth["returns"].replace(":: ", "::") + for cls in list(self.classes.values()): methnames = cls.get_all_method_names() pvm = cls.get_all_pure_virtual_methods() - for d in cls['inherits']: - c = d['class'] - a = d['access'] # do not depend on this to be 'public' - trace_print( 'PARENT CLASS:', c ) - if c not in self.classes: trace_print('WARN: parent class not found') - if c in self.classes and self.classes[c]['abstract']: - p = self.classes[ c ] - for meth in p.get_all_methods(): #p["methods"]["public"]: - trace_print( '\t\tmeth', meth['name'], 'pure virtual', meth['pure_virtual'] ) - if meth['pure_virtual'] and meth['name'] not in methnames: cls['abstract'] = True; break + for d in cls["inherits"]: + c = d["class"] + a = d["access"] # do not depend on this to be 'public' + trace_print("PARENT CLASS:", c) + if c not in self.classes: + trace_print("WARN: parent class not found") + if c in self.classes and self.classes[c]["abstract"]: + p = self.classes[c] + for meth in p.get_all_methods(): # p["methods"]["public"]: + trace_print( + "\t\tmeth", + meth["name"], + "pure virtual", + meth["pure_virtual"], + ) + if meth["pure_virtual"] and meth["name"] not in methnames: + cls["abstract"] = True + break + _method_type_defaults = { + n: False + for n in "defined deleted pure_virtual operator constructor destructor extern template virtual static explicit inline friend returns returns_pointer returns_fundamental returns_class default".split() + } + def parse_method_type(self, stack): + trace_print("meth type info", stack) + info = { + "debug": " ".join(stack) + .replace(" :: ", "::") + .replace(" < ", "<") + .replace(" > ", "> ") + .replace(" >", ">") + .replace(">>", "> >") + .replace(">>", "> >"), + "class": None, + "namespace": self.cur_namespace(add_double_colon=True), + } + info.update(self._method_type_defaults) + header = stack[: stack.index("(")] + header = " ".join(header) + header = header.replace(" :: ", "::") + header = header.replace(" < ", "<") + header = header.replace(" > ", "> ") + header = header.replace("default ", "default") + header = header.strip() - def evaluate_struct_stack(self): - """Create a Struct out of the name stack (but not its parts)""" - #print( 'eval struct stack', self.nameStack ) - #if self.braceDepth != len(self.nameSpaces): return - struct = CppStruct(self.nameStack) - struct["namespace"] = self.cur_namespace() - self.structs[ struct['type'] ] = struct - self.structs_order.append( struct ) - if self.curClass: - struct['parent'] = self.curClass - klass = self.classes[ self.curClass ] - klass['structs'][self.curAccessSpecifier].append( struct ) - if self.curAccessSpecifier == 'public': klass._public_structs[ struct['type'] ] = struct - self.curStruct = struct - self._structs_brace_level[ struct['type'] ] = self.braceDepth - - - def parse_method_type( self, stack ): - trace_print( 'meth type info', stack ) - if stack[0] in ':;' and stack[1] != ':': stack = stack[1:] - info = { - 'debug': ' '.join(stack).replace(' : : ', '::' ).replace(' < ', '<' ).replace(' > ', '> ' ).replace(" >",">").replace(">>", "> >").replace(">>", "> >"), - 'class':None, - 'namespace':self.cur_namespace(add_double_colon=True), - } + if stack[-1] == "{": + info["defined"] = True + self._discard_contents("{", "}") + self.braceHandled = True + elif stack[-1] == ";": + info["defined"] = False + elif stack[-1] == ":": + info["defined"] = True + self._discard_ctor_initializer() + self.braceHandled = True + else: + assert 0 - for tag in 'defined pure_virtual operator constructor destructor extern template virtual static explicit inline friend returns returns_pointer returns_fundamental returns_class'.split(): info[tag]=False - header = stack[ : stack.index('(') ] - header = ' '.join( header ) - header = header.replace(' : : ', '::' ) - header = header.replace(' < ', '<' ) - header = header.replace(' > ', '> ' ) - header = header.strip() + refqual = "" + if len(stack) > 3: + if stack[-1] == ";" and stack[-3] == "=": + if stack[-2] == "0": + info["pure_virtual"] = True + elif stack[-2] == "delete": + info["deleted"] = True - if '{' in stack: - info['defined'] = True - self._method_body = self.braceDepth + 1 - trace_print( 'NEW METHOD WITH BODY', self.braceDepth ) - elif stack[-1] == ';': - info['defined'] = False - self._method_body = None # not a great idea to be clearing here - else: assert 0 + for e in reversed(stack): + if e == ")": + break + elif e == "&": + refqual += "&" - if len(stack) > 3 and stack[-1] == ';' and stack[-2] == '0' and stack[-3] == '=': - info['pure_virtual'] = True + info["ref_qualifiers"] = refqual r = header.split() name = None - if 'operator' in stack: # rare case op overload defined outside of class - op = stack[ stack.index('operator')+1 : stack.index('(') ] - op = ''.join(op) + if "operator" in stack: # rare case op overload defined outside of class + op = stack[stack.index("operator") + 1 : stack.index("(")] + op = "".join(op) if not op: - if " ".join(['operator', '(', ')', '(']) in " ".join(stack): + if " ".join(["operator", "(", ")", "("]) in " ".join(stack): op = "()" else: - trace_print( 'Error parsing operator') + trace_print("Error parsing operator") return None - - info['operator'] = op - name = 'operator' + op - a = stack[ : stack.index('operator') ] + + info["operator"] = op + name = "operator" + op + a = stack[: stack.index("operator")] elif r: name = r[-1] - a = r[ : -1 ] # strip name + a = r[:-1] # strip name - if name is None: return None - #if name.startswith('~'): name = name[1:] + if name is None: + return None + # if name.startswith('~'): name = name[1:] - while a and a[0] == '}': # strip - can have multiple } } + while a and a[0] == "}": # strip - can have multiple } } a = a[1:] - - if '::' in name: - #klass,name = name.split('::') # methods can be defined outside of class - klass = name[ : name.rindex('::') ] - name = name.split('::')[-1] - info['class'] = klass + if "::" in name: + # klass,name = name.split('::') # methods can be defined outside of class + klass = name[: name.rindex("::")] + name = name.split("::")[-1] + info["class"] = klass if klass in self.classes and not self.curClass: - #Class function defined outside the class + # Class function defined outside the class return None # info['name'] = name - #else: info['name'] = name + # else: info['name'] = name - if name.startswith('~'): - info['destructor'] = True + if name.startswith("~"): + info["destructor"] = True + if "default;" in stack: + info["defined"] = True + info["default"] = True name = name[1:] elif not a or (name == self.curClass and len(self.curClass)): - info['constructor'] = True - - info['name'] = name - - for tag in 'extern virtual static explicit inline friend'.split(): - if tag in a: info[ tag ] = True; a.remove( tag ) # inplace - if 'template' in a: - a.remove('template') - b = ' '.join( a ) - if '>' in b: - info['template'] = b[ : b.index('>')+1 ] - info['returns'] = b[ b.index('>')+1 : ] # find return type, could be incorrect... TODO - if '' - if typname not in self._template_typenames: self._template_typenames.append( typname ) - else: info['returns'] = ' '.join( a ) - else: info['returns'] = ' '.join( a ) - info['returns'] = info['returns'].replace(' <', '<').strip() + info["constructor"] = True + if "default;" in stack: + info["defined"] = True + info["default"] = True + + info["name"] = name + + for tag in self.C_KEYWORDS: + if tag in a: + info[tag] = True + a.remove(tag) # inplace + if "template" in a: + a.remove("template") + b = " ".join(a) + if ">" in b: + info["template"] = b[: b.index(">") + 1] + info["returns"] = b[ + b.index(">") + 1 : + ] # find return type, could be incorrect... TODO + if "' + if typname not in self._template_typenames: + self._template_typenames.append(typname) + else: + info["returns"] = " ".join(a) + else: + info["returns"] = " ".join(a) + info["returns"] = info["returns"].replace(" <", "<").strip() ## be careful with templates, do not count pointers inside template - info['returns_pointer'] = info['returns'].split('>')[-1].count('*') - if info['returns_pointer']: info['returns'] = info['returns'].replace('*','').strip() + info["returns_pointer"] = info["returns"].split(">")[-1].count("*") + if info["returns_pointer"]: + info["returns"] = info["returns"].replace("*", "").strip() - info['returns_reference'] = '&' in info['returns'] - if info['returns']: info['returns'] = info['returns'].replace('&','').strip() + info["returns_reference"] = "&" in info["returns"] + if info["returns"]: + info["returns"] = info["returns"].replace("&", "").strip() a = [] - for b in info['returns'].split(): - if b == '__const__': info['returns_const'] = True - elif b == 'const': info['returns_const'] = True - else: a.append( b ) - info['returns'] = ' '.join( a ) + for b in info["returns"].split(): + if b == "__const__": + info["returns_const"] = True + elif b == "const": + info["returns_const"] = True + else: + a.append(b) + info["returns"] = " ".join(a) - info['returns_fundamental'] = is_fundamental( info['returns'] ) + info["returns_fundamental"] = is_fundamental(info["returns"]) return info - def evaluate_method_stack(self): + def _evaluate_method_stack(self): """Create a method out of the name stack""" - if self.curStruct: - trace_print( 'WARN - struct contains methods - skipping' ) - trace_print( self.stack ) - assert 0 - - info = self.parse_method_type( self.stack ) + info = self.parse_method_type(self.stack) if info: - if info[ 'class' ] and info['class'] in self.classes: # case where methods are defined outside of class - newMethod = CppMethod(self.nameStack, info['name'], info, self.curTemplate) - klass = self.classes[ info['class'] ] - klass[ 'methods' ][ 'public' ].append( newMethod ) - newMethod['parent'] = klass - if klass['namespace']: newMethod['path'] = klass['namespace'] + '::' + klass['name'] - else: newMethod['path'] = klass['name'] - - elif self.curClass: # normal case - newMethod = CppMethod(self.nameStack, self.curClass, info, self.curTemplate) + if ( + info["class"] and info["class"] in self.classes + ): # case where methods are defined outside of class + newMethod = CppMethod( + self.nameStack, + info["name"], + info, + self.curTemplate, + self._get_stmt_doxygen(), + self._get_location(self.nameStack), + ) + klass = self.classes[info["class"]] + klass["methods"]["public"].append(newMethod) + newMethod["parent"] = klass + if klass["namespace"]: + newMethod["path"] = klass["namespace"] + "::" + klass["name"] + else: + newMethod["path"] = klass["name"] + + elif self.curClass: # normal case + newMethod = CppMethod( + self.nameStack, + self.curClass, + info, + self.curTemplate, + self._get_stmt_doxygen(), + self._get_location(self.nameStack), + ) klass = self.classes[self.curClass] - klass['methods'][self.curAccessSpecifier].append(newMethod) - newMethod['parent'] = klass - if klass['namespace']: newMethod['path'] = klass['namespace'] + '::' + klass['name'] - else: newMethod['path'] = klass['name'] - else: #non class functions + klass["methods"][self.curAccessSpecifier].append(newMethod) + newMethod["parent"] = klass + if klass["namespace"]: + newMethod["path"] = klass["namespace"] + "::" + klass["name"] + else: + newMethod["path"] = klass["name"] + else: # non class functions debug_print("FREE FUNCTION") - newMethod = CppMethod(self.nameStack, None, info, self.curTemplate) + newMethod = CppMethod( + self.nameStack, + None, + info, + self.curTemplate, + self._get_stmt_doxygen(), + self._get_location(self.nameStack), + ) + newMethod["parent"] = None + newMethod["linkage"] = self.cur_linkage() self.functions.append(newMethod) + + # Reset template once it has been used + self.curTemplate = None + global parseHistory - parseHistory.append({"braceDepth": self.braceDepth, "item_type": "method", "item": newMethod}) + parseHistory.append( + { + "braceDepth": self.braceDepth, + "item_type": "method", + "item": newMethod, + } + ) else: - trace_print( 'free function?', self.nameStack ) + trace_print("free function?", self.nameStack) self.stack = [] + self.stmtTokens = [] + + _function_point_typedef_format = re.compile(r".*?\(.*?\*(.*?)\).*?\(.*?\).*?") - def _parse_typedef( self, stack, namespace='' ): - if not stack or 'typedef' not in stack: return - stack = list( stack ) # copy just to be safe - if stack[-1] == ';': stack.pop() + def _function_point_typedef_parse(self, stack): + idx = stack.index("typedef") + expression = "".join(stack[idx + 1 :]) + m = self._function_point_typedef_format.match(expression) + if m is None: + return {} - while stack and stack[-1].isdigit(): stack.pop() # throw away array size for now + name = m.group(1) + s = " ".join([i for i in stack if i != name]) + r = {"name": name, "raw": s, "type": s} + return r + + def _parse_typedef(self, stack, namespace=""): + if not stack or "typedef" not in stack: + return + stack = list(stack) # copy just to be safe + if stack[-1] == ";": + stack.pop() + + r = self._function_point_typedef_parse(stack) + if len(r) == 3: + return r - idx = stack.index('typedef') + while stack and stack[-1].isdigit(): + stack.pop() # throw away array size for now + + idx = stack.index("typedef") if stack[-1] == "]": try: name = namespace + "".join(stack[-4:]) @@ -1863,196 +2431,299 @@ def _parse_typedef( self, stack, namespace='' ): name = namespace + stack[-1] else: name = namespace + stack[-1] - s = '' - for a in stack[idx+1:-1]: - if a == '{': break - if not s or s[-1] in ':<>' or a in ':<>': s += a # keep compact - else: s += ' ' + a # spacing + s = "" + for a in stack[idx + 1 : -1]: + if a == "{": + break + if not s or s[-1] in ":<>" or a in ":<>": + s += a # keep compact + else: + s += " " + a # spacing - r = {'name':name, 'raw':s, 'type':s} + r = {"name": name, "raw": s, "type": s} if not is_fundamental(s): - if 'struct' in s.split(): pass # TODO is this right? "struct ns::something" - elif '::' not in s: s = namespace + s # only add the current name space if no namespace given - r['type'] = s - if s: return r - - - def evaluate_typedef(self): + if "struct" in s.split(): + pass # TODO is this right? "struct ns::something" + elif "::" not in s: + s = ( + namespace + s + ) # only add the current name space if no namespace given + r["type"] = s + if s: + return r + + def _evaluate_typedef(self): ns = self.cur_namespace(add_double_colon=True) - res = self._parse_typedef( self.stack, ns ) + res = self._parse_typedef(self.stack, ns) if res: - name = res['name'] - self.typedefs[ name ] = res['type'] - if name not in self.typedefs_order: self.typedefs_order.append( name ) - + name = res["name"] + self.typedefs[name] = res["type"] + if name not in self.typedefs_order: + self.typedefs_order.append(name) - def evaluate_property_stack(self): + def _evaluate_property_stack(self, clearStack=True, addToVar=None): """Create a Property out of the name stack""" global parseHistory - assert self.stack[-1] == ';' - debug_print( "trace" ) - if self.nameStack[0] == 'typedef': + debug_print("trace") + if self.nameStack[0] == "typedef": + assert self.stack and self.stack[-1] == ";" if self.curClass: - typedef = self._parse_typedef( self.stack ) - name = typedef['name'] - klass = self.classes[ self.curClass ] - klass[ 'typedefs' ][ self.curAccessSpecifier ].append( name ) - if self.curAccessSpecifier == 'public': klass._public_typedefs[ name ] = typedef['type'] - Resolver.SubTypedefs[ name ] = self.curClass - else: assert 0 - elif self.curStruct or self.curClass: + typedef = self._parse_typedef(self.stack) + name = typedef["name"] + klass = self.classes[self.curClass] + klass["typedefs"][self.curAccessSpecifier].append(name) + if self.curAccessSpecifier == "public": + klass._public_typedefs[name] = typedef["type"] + else: + assert 0 + elif self.curClass: if len(self.nameStack) == 1: - #See if we can de anonymize the type - filteredParseHistory = [h for h in parseHistory if h["braceDepth"] == self.braceDepth] - if len(filteredParseHistory) and filteredParseHistory[-1]["item_type"] == "class": + # See if we can de anonymize the type + filteredParseHistory = [ + h for h in parseHistory if h["braceDepth"] == self.braceDepth + ] + if ( + len(filteredParseHistory) + and filteredParseHistory[-1]["item_type"] == "class" + ): self.nameStack.insert(0, filteredParseHistory[-1]["item"]["name"]) - debug_print("DEANONYMOIZING %s to type '%s'"%(self.nameStack[1], self.nameStack[0])) - if "," in self.nameStack: #Maybe we have a variable list - #Figure out what part is the variable separator but remember templates of function pointer - #First find left most comma outside of a > and ) - leftMostComma = 0; + debug_print( + "DEANONYMOIZING %s to type '%s'", + self.nameStack[1], + self.nameStack[0], + ) + if "," in self.nameStack: # Maybe we have a variable list + # Figure out what part is the variable separator but remember templates of function pointer + # First find left most comma outside of a > and ) + leftMostComma = 0 for i in range(0, len(self.nameStack)): name = self.nameStack[i] - if name in (">", ")"): leftMostComma = 0 - if leftMostComma == 0 and name == ",": leftMostComma = i + if name in (">", ")"): + leftMostComma = 0 + if leftMostComma == 0 and name == ",": + leftMostComma = i # Is it really a list of variables? if leftMostComma != 0: - trace_print("Multiple variables for namestack in %s. Separating processing"%self.nameStack) + trace_print( + "Multiple variables for namestack in", + self.nameStack, + ". Separating processing", + ) orig_nameStack = self.nameStack[:] - orig_stack = self.stack[:] - - type_nameStack = orig_nameStack[:leftMostComma-1] - for name in orig_nameStack[leftMostComma - 1::2]: + + type_nameStack = orig_nameStack[: leftMostComma - 1] + for name in orig_nameStack[leftMostComma - 1 :: 2]: self.nameStack = type_nameStack + [name] - self.stack = orig_stack[:] # Not maintained for mucking, but this path it doesnt matter - self.evaluate_property_stack() + self._evaluate_property_stack( + clearStack=False, addToVar=addToVar + ) return - - newVar = CppVariable(self.nameStack) - newVar['namespace'] = self.current_namespace() - if self.curStruct: - self.curStruct[ 'fields' ].append( newVar ) - newVar['property_of_struct'] = self.curStruct - elif self.curClass: + + newVar = CppVariable( + self.nameStack, + self._get_stmt_doxygen(), + self._get_location(self.nameStack), + ) + newVar["namespace"] = self.current_namespace() + newVar["linkage"] = self.cur_linkage() + if self.curClass: klass = self.classes[self.curClass] klass["properties"][self.curAccessSpecifier].append(newVar) - newVar['property_of_class'] = klass['name'] - parseHistory.append({"braceDepth": self.braceDepth, "item_type": "variable", "item": newVar}) + newVar["property_of_class"] = klass["name"] + newVar["parent"] = klass + parseHistory.append( + {"braceDepth": self.braceDepth, "item_type": "variable", "item": newVar} + ) + if addToVar: + newVar.update(addToVar) else: - debug_print( "Found Global variable" ) - newVar = CppVariable(self.nameStack) + debug_print("Found Global variable") + newVar = CppVariable( + self.nameStack, + self._get_stmt_doxygen(), + self._get_location(self.nameStack), + ) + newVar["namespace"] = self.cur_namespace(False) + newVar["linkage"] = self.cur_linkage() + if addToVar: + newVar.update(addToVar) self.variables.append(newVar) - self.stack = [] # CLEAR STACK + if clearStack: + self.stack = [] # CLEAR STACK + self.stmtTokens = [] - def evaluate_class_stack(self): + def _evaluate_class_stack(self): """Create a Class out of the name stack (but not its parts)""" - #dont support sub classes today - #print( 'eval class stack', self.nameStack ) + # dont support sub classes today + # print( 'eval class stack', self.nameStack ) parent = self.curClass - if self.braceDepth > len( self.nameSpaces) and parent: - trace_print( 'HIT NESTED SUBCLASS' ) + if parent: + debug_print("found nested subclass") self.accessSpecifierStack.append(self.curAccessSpecifier) - elif self.braceDepth != len(self.nameSpaces): - error_print( 'ERROR: WRONG BRACE DEPTH' ) - return - + # When dealing with typedefed structs, get rid of typedef keyword to handle later on if self.nameStack[0] == "typedef": del self.nameStack[0] - if len(self.nameStack) == 1: + + if len(self.nameStack) == 1: + if self.nameStack[0] == "struct": self.anon_struct_counter += 1 # We cant handle more than 1 anonymous struct, so name them uniquely - self.nameStack.append(""%self.anon_struct_counter) - + self.nameStack.append("anon-struct-%d" % self.anon_struct_counter) + elif self.nameStack[0] == "union": + self.anon_union_counter += 1 + # We cant handle more than 1 anonymous union, so name them uniquely + self.nameStack.append("anon-union-%d" % self.anon_union_counter) + elif self.nameStack[0] == "class": + self.anon_class_counter += 1 + # We cant handle more than 1 anonymous class, so name them uniquely + self.nameStack.append("anon-class-%d" % self.anon_class_counter) + if self.nameStack[0] == "class": - self.curAccessSpecifier = 'private' - else:#struct - self.curAccessSpecifier = 'public' - debug_print("curAccessSpecifier changed/defaulted to %s"%self.curAccessSpecifier) + self.curAccessSpecifier = "private" + else: # struct/union + self.curAccessSpecifier = "public" + debug_print( + "curAccessSpecifier changed/defaulted to %s", self.curAccessSpecifier + ) if self.nameStack[0] == "union": - newClass = CppUnion(self.nameStack) - if newClass['name'] == 'union ': - self.anon_union_counter = [self.braceDepth, 2] - else: - self.anon_union_counter = [self.braceDepth, 1] - trace_print( 'NEW UNION', newClass['name'] ) + newClass = CppUnion( + self.nameStack, + self._get_stmt_doxygen(), + self._get_location(self.nameStack), + ) else: - newClass = CppClass(self.nameStack, self.curTemplate) - trace_print( 'NEW CLASS', newClass['name'] ) + newClass = CppClass( + self.nameStack, + self.curTemplate, + self._get_stmt_doxygen(), + self._get_location(self.nameStack), + self.curAccessSpecifier, + ) + self.curTemplate = None newClass["declaration_method"] = self.nameStack[0] - self.classes_order.append( newClass ) # good idea to save ordering - self.stack = [] # fixes if class declared with ';' in closing brace + newClass["linkage"] = self.cur_linkage() + self.classes_order.append(newClass) # good idea to save ordering + self.stack = [] # fixes if class declared with ';' in closing brace + self.stmtTokens = [] + classKey = newClass["name"] + if parent: - newClass["namespace"] = self.classes[ parent ]['namespace'] + '::' + parent - newClass['parent'] = parent - self.classes[ parent ]['nested_classes'].append( newClass ) + newClass["namespace"] = self.classes[parent]["namespace"] + "::" + parent + newClass["parent"] = self.classes[parent] + newClass["access_in_parent"] = self.accessSpecifierStack[-1] + self.classes[parent]["nested_classes"].append(newClass) ## supports nested classes with the same name ## - self.curClass = key = parent+'::'+newClass['name'] - self._classes_brace_level[ key ] = self.braceDepth - - elif newClass['parent']: # nested class defined outside of parent. A::B {...} - parent = newClass['parent'] - newClass["namespace"] = self.classes[ parent ]['namespace'] + '::' + parent - self.classes[ parent ]['nested_classes'].append( newClass ) + self.curClass = key = parent + "::" + classKey + self._classes_brace_level[key] = self.braceDepth + + elif newClass["parent"]: # nested class defined outside of parent. A::B {...} + pcls = newClass["parent"] + parent = pcls["name"] + newClass["namespace"] = pcls["namespace"] + "::" + parent + pcls["nested_classes"].append(newClass) ## supports nested classes with the same name ## - self.curClass = key = parent+'::'+newClass['name'] - self._classes_brace_level[ key ] = self.braceDepth + self.curClass = key = parent + "::" + classKey + self._classes_brace_level[key] = self.braceDepth else: newClass["namespace"] = self.cur_namespace() - key = newClass['name'] - self.curClass = newClass["name"] - self._classes_brace_level[ newClass['name'] ] = self.braceDepth + self.curClass = key = classKey + self._classes_brace_level[classKey] = self.braceDepth if not key.endswith("::") and not key.endswith(" ") and len(key) != 0: if key in self.classes: - trace_print( 'ERROR name collision:', key ) + trace_print("ERROR name collision:", key) self.classes[key].show() - trace_print('-'*80) - newClass.show() - assert key not in self.classes # namespace collision - self.classes[ key ] = newClass + newClass.show() + assert key not in self.classes # namespace collision + self.classes[key] = newClass global parseHistory - parseHistory.append({"braceDepth": self.braceDepth, "item_type": "class", "item": newClass}) - + parseHistory.append( + {"braceDepth": self.braceDepth, "item_type": "class", "item": newClass} + ) def evalute_forward_decl(self): - trace_print( 'FORWARD DECL', self.nameStack ) - assert self.nameStack[0] in ('class', 'struct') + trace_print("FORWARD DECL", self.nameStack) + assert self.nameStack[0] in ("class", "struct") name = self.nameStack[-1] if self.curClass: - klass = self.classes[ self.curClass ] - klass['forward_declares'][self.curAccessSpecifier].append( name ) - if self.curAccessSpecifier == 'public': klass._public_forward_declares.append( name ) - else: self._forward_decls.append( name ) - -class CppHeader( _CppHeader ): - """Parsed C++ class header - - Variables produced: - self.classes - Dictionary of classes found in a given header file where the - key is the name of the class - """ - IGNORE_NAMES = '__extension__'.split() - - def show(self): - for className in list(self.classes.keys()):self.classes[className].show() + klass = self.classes[self.curClass] + klass["forward_declares"][self.curAccessSpecifier].append(name) + if self.curAccessSpecifier == "public": + klass._public_forward_declares.append(name) + else: + self._forward_decls[name] = self.current_namespace() + + +# fmt: off +_namestack_append_tokens = { + "{", + "}", + "[", + "]", + "=", + ",", + "\\", + "DIVIDE", + "|", + "%", + "^", + "!", + "NUMBER", + "FLOAT_NUMBER", + "-", + "+", + "STRING_LITERAL", + "ELLIPSIS", + "DBL_COLON", + "SHIFT_LEFT", +} + +_namestack_pass_tokens = { + "'", + "." # preserve behaviour and eat individual fullstops +} + +_namestack_str_tokens = { + "NAME", + "&", + "*", + "<", + ">", + "CHAR_LITERAL" +} +# fmt: on - def __init__(self, headerFileName, argType="file", **kwargs): + +class CppHeader(_CppHeader): + """Parsed C++ class header""" + + IGNORE_NAMES = "__extension__".split() + + def show(self): + for className in list(self.classes.keys()): + self.classes[className].show() + + def __init__( + self, + headerFileName, + argType="file", + encoding=None, + preprocessed=False, + **kwargs + ): """Create the parsed C++ header file parse tree - + headerFileName - Name of the file to parse OR actual file contents (depends on argType) argType - Indicates how to interpret headerFileName as a file string or file name kwargs - Supports the following keywords """ ## reset global state ## - global doxygenCommentCache - doxygenCommentCache = "" CppVariable.Vars = [] - CppStruct.Structs = [] - if (argType == "file"): + if argType == "file": self.headerFileName = os.path.expandvars(headerFileName) self.mainClass = os.path.split(self.headerFileName)[1][:-2] headerFileStr = "" @@ -2063,112 +2734,115 @@ def __init__(self, headerFileName, argType="file", **kwargs): else: raise Exception("Arg type must be either file or string") self.curClass = "" - + # nested classes have parent::nested, but no extra namespace, - # this keeps the API compatible, TODO proper namespace for everything. + # this keeps the API compatible, TODO proper namespace for everything. Resolver.CLASSES = {} + + #: Dictionary of classes found in the header file. The key is the name + #: of the class, value is :class:`.CppClass` self.classes = Resolver.CLASSES - #Functions that are not part of a class + + #: List of free functions as :class:`.CppMethod` self.functions = [] - + + #: List of #pragma directives found as strings self.pragmas = [] + + #: List of pragmas with location information + self.pragmas_detail = [] + + #: List of #define directives found self.defines = [] + + #: List of #define directives found, with location information + self.defines_detail = [] + + #: List of #include directives found self.includes = [] - self._precomp_macro_buf = [] #for internal purposes, will end up filling out pragmras and defines at the end + #: List of #include directives found with location information + self.includes_detail = [] + + #: Filenames encountered in #line directives while parsing + self.headerFileNames = [] + + self._precomp_macro_buf = ( + [] + ) # for internal purposes, will end up filling out pragmras and defines at the end + + #: List of enums in this header as :class:`.CppEnum` self.enums = [] + + self.extern_templates = [] + + #: List of variables in this header as :class:`.CppVariable` self.variables = [] self.global_enums = {} self.nameStack = [] + + #: Namespaces in this header self.nameSpaces = [] - self.curAccessSpecifier = 'private' # private is default + self.curAccessSpecifier = "private" # private is default self.curTemplate = None self.accessSpecifierStack = [] - self.accessSpecifierScratch = [] - debug_print("curAccessSpecifier changed/defaulted to %s"%self.curAccessSpecifier) + self.linkage_stack = [] + debug_print( + "curAccessSpecifier changed/defaulted to %s", self.curAccessSpecifier + ) self.initextra() # Old namestacks for a given level self.nameStackHistory = [] - self.anon_struct_counter = 0 - self.anon_union_counter = [-1, 0] - self.templateRegistry = [] - - if (len(self.headerFileName)): - fd = open(self.headerFileName) + self.anon_struct_counter = 0 + self.anon_union_counter = 0 + self.anon_class_counter = 0 + + #: Using directives in this header outside of class scope: key is + #: full name for lookup, value is :class:`.CppVariable` + self.using = {} + + if len(self.headerFileName): + fd = io.open(self.headerFileName, "r", encoding=encoding) headerFileStr = "".join(fd.readlines()) - fd.close() - + fd.close() + # Make sure supportedAccessSpecifier are sane for i in range(0, len(supportedAccessSpecifier)): - if " " not in supportedAccessSpecifier[i]: continue - supportedAccessSpecifier[i] = re.sub("[ ]+", " ", supportedAccessSpecifier[i]).strip() - - # Strip out template declarations - templateSectionsToSliceOut = [] - try: - for m in re.finditer("template[\t ]*<[^>]*>", headerFileStr): - start = m.start() - # Search for the final '>' which may or may not be caught in the case of nexted <>'s - for i in range(start, len(headerFileStr)): - if headerFileStr[i] == '<': - firstBracket = i - break - ltgtStackCount = 1 - #Now look for fianl '>' - for i in range(firstBracket + 1, len(headerFileStr)): - if headerFileStr[i] == '<': - ltgtStackCount += 1 - elif headerFileStr[i] == '>': - ltgtStackCount -= 1 - if ltgtStackCount == 0: - end = i - break - templateSectionsToSliceOut.append((start, end)) - - # Now strip out all instances of the template - templateSectionsToSliceOut.reverse() - for tslice in templateSectionsToSliceOut: - # Replace the template symbol with a single symbol - template_symbol="CppHeaderParser_template_%d"%len(self.templateRegistry) - self.templateRegistry.append(headerFileStr[tslice[0]: tslice[1]+1]) - newlines = headerFileStr[tslice[0]: tslice[1]].count("\n") * "\n" #Keep line numbers the same - headerFileStr = headerFileStr[:tslice[0]] + newlines + " " + template_symbol + " " + headerFileStr[tslice[1] + 1:] - except: - pass + if " " not in supportedAccessSpecifier[i]: + continue + supportedAccessSpecifier[i] = re.sub( + "[ ]+", " ", supportedAccessSpecifier[i] + ).strip() + + if not preprocessed: + # Change multi line #defines and expressions to single lines maintaining line nubmers + # Based from http://stackoverflow.com/questions/2424458/regular-expression-to-match-cs-multiline-preprocessor-statements + matches = re.findall(r"(?m)^(?:.*\\\r?\n)+.*$", headerFileStr) + is_define = re.compile(r"[ \t\v]*#[Dd][Ee][Ff][Ii][Nn][Ee]") + for m in matches: + # Keep the newlines so that linecount doesnt break + num_newlines = len([a for a in m if a == "\n"]) + if is_define.match(m): + new_m = m.replace( + "\n", "\\n" + ) + else: + # Just expression taking up multiple lines, make it take 1 line for easier parsing + new_m = m.replace("\\\n", " ") + if num_newlines > 0: + new_m += "\n" * (num_newlines) + headerFileStr = headerFileStr.replace(m, new_m) - # Change multi line #defines and expressions to single lines maintaining line nubmers - # Based from http://stackoverflow.com/questions/2424458/regular-expression-to-match-cs-multiline-preprocessor-statements - matches = re.findall(r'(?m)^(?:.*\\\r?\n)+.*$', headerFileStr) - is_define = re.compile(r'[ \t\v]*#[Dd][Ee][Ff][Ii][Nn][Ee]') - for m in matches: - #Keep the newlines so that linecount doesnt break - num_newlines = len([a for a in m if a=="\n"]) - if is_define.match(m): - new_m = m.replace("\n", "\\n") - else: - # Just expression taking up multiple lines, make it take 1 line for easier parsing - new_m = m.replace("\\\n", " ") - if (num_newlines > 0): - new_m += "\n"*(num_newlines) - headerFileStr = headerFileStr.replace(m, new_m) - - #Filter out Extern "C" statements. These are order dependent - matches = re.findall(re.compile(r'extern[\t ]+"[Cc]"[\t \n\r]*{', re.DOTALL), headerFileStr) - for m in matches: - #Keep the newlines so that linecount doesnt break - num_newlines = len([a for a in m if a=="\n"]) - headerFileStr = headerFileStr.replace(m, "\n" * num_newlines) - headerFileStr = re.sub(r'extern[ ]+"[Cc]"[ ]*', "", headerFileStr) - - #Filter out any ignore symbols that end with "()" to account for #define magic functions + # Filter out any ignore symbols that end with "()" to account for #define magic functions for ignore in ignoreSymbols: - if not ignore.endswith("()"): continue + if not ignore.endswith("()"): + continue while True: locStart = headerFileStr.find(ignore[:-1]) if locStart == -1: - break; + break locEnd = None - #Now walk till we find the last paren and account for sub parens + # Now walk till we find the last paren and account for sub parens parenCount = 1 inQuotes = False for i in range(locStart + len(ignore) - 1, len(headerFileStr)): @@ -2182,395 +2856,952 @@ def __init__(self, headerFileName, argType="file", **kwargs): inQuotes = True if parenCount == 0: locEnd = i + 1 - break; + break else: - if c == '"' and headerFileStr[i-1] != '\\': + if c == '"' and headerFileStr[i - 1] != "\\": inQuotes = False - + if locEnd: - #Strip it out but keep the linecount the same so line numbers are right + # Strip it out but keep the linecount the same so line numbers are right match_str = headerFileStr[locStart:locEnd] - debug_print("Striping out '%s'"%match_str) - num_newlines = len([a for a in match_str if a=="\n"]) - headerFileStr = headerFileStr.replace(headerFileStr[locStart:locEnd], "\n"*num_newlines) - + debug_print("Striping out '%s'", match_str) + num_newlines = len([a for a in match_str if a == "\n"]) + headerFileStr = headerFileStr.replace( + headerFileStr[locStart:locEnd], "\n" * num_newlines + ) + self.braceDepth = 0 - lex.lex() + self.braceReason = [] + self.lastBraceReason = _BRACE_REASON_OTHER + + lex = Lexer(self.headerFileName) lex.input(headerFileStr) - global curLine - global curChar - curLine = 0 - curChar = 0 + self.lex = lex + self.headerFileNames = lex.filenames + + # + # A note on parsing methodology + # + # The idea here is to consume as many tokens as needed to determine + # what the thing is that we're parsing. While some items can be identified + # early, typically the code below consumes until a '{', '}', or ; and + # then looks at the accumulated tokens to figure out what it is. + # + # Unfortunately, the code isn't always particularly consistent (but + # it's slowly getting there!), so take this with a grain of salt. + # + + self._doxygen_cache = None + self.braceHandled = False + tok = None + self.stmtTokens = [] + parenDepth = 0 + try: while True: - tok = lex.token() - if not tok: break - if self.anon_union_counter[0] == self.braceDepth and self.anon_union_counter[1]: - self.anon_union_counter[1] -= 1 - tok.value = TagStr(tok.value, lineno=tok.lineno) - #debug_print("TOK: %s"%tok) - if tok.type == 'NAME' and tok.value in self.IGNORE_NAMES: continue - if tok.type != 'TEMPLATE_NAME': - self.stack.append( tok.value ) - curLine = tok.lineno - curChar = tok.lexpos - if (tok.type in ('PRECOMP_MACRO', 'PRECOMP_MACRO_CONT')): - debug_print("PRECOMP: %s"%tok) - self._precomp_macro_buf.append(tok.value) + tok = lex.token(eof_ok=True) + if not tok: + break + tok.value = TagStr(tok.value, location=tok.location) + + debug_print("TOK: %s", tok) + if tok.type == "NAME": + if tok.value in self.IGNORE_NAMES: + continue + elif tok.value == "template": + self._doxygen_cache = self.lex.get_doxygen() + self._parse_template() + continue + elif tok.value == "alignas": + self._doxygen_cache = self.lex.get_doxygen() + self._parse_attribute_specifier_seq(tok) + continue + elif tok.value == "__attribute__": + self._doxygen_cache = self.lex.get_doxygen() + self._parse_gcc_attribute() + continue + elif not self.stack and tok.value == "static_assert": + self._next_token_must_be("(") + self._discard_contents("(", ")") + continue + + elif tok.type == "DBL_LBRACKET": + self._doxygen_cache = self.lex.get_doxygen() + self._parse_attribute_specifier_seq(tok) + continue + + # TODO: get rid of stack, move to stmtTokens + self.stack.append(tok.value) + self.stmtTokens.append(tok) + + nslen = len(self.nameStack) + + if tok.type in ("PRECOMP_MACRO", "PRECOMP_MACRO_CONT"): + debug_print("PRECOMP: %s", tok) + self._precomp_macro_buf.append((tok.value, tok.location)) self.stack = [] + self.stmtTokens = [] self.nameStack = [] continue - if tok.type == 'TEMPLATE_NAME': - try: - templateId = int(tok.value.replace("CppHeaderParser_template_","")) - self.curTemplate = self.templateRegistry[templateId] - except: pass - if (tok.type == 'OPEN_BRACE'): - if len(self.nameStack) >= 2 and is_namespace(self.nameStack): # namespace {} with no name used in boost, this sets default? - if self.nameStack[1] == "__IGNORED_NAMESPACE__CppHeaderParser__":#Used in filtering extern "C" - self.nameStack[1] = "" - self.nameSpaces.append(self.nameStack[1]) - ns = self.cur_namespace(); self.stack = [] - if ns not in self.namespaces: self.namespaces.append( ns ) + + if parenDepth == 0 and tok.type == "{": + if self.nameStack[0] in ( + "class", + "struct", + "union", + "namespace", + "enum", + "extern", + "typedef", + ) or (is_method_namestack(self.stack) or (not self.curClass)): + self.lastBraceReason = _BRACE_REASON_OTHER + else: + # Case : type variable {init}; + self.lastBraceReason = _BRACE_REASON_VARIABLE + self.braceDepth += 1 + self.braceReason.append(self.lastBraceReason) + self.nameStack.append(tok.value) + continue + if len(self.nameStack) >= 2 and is_namespace( + self.nameStack + ): # namespace {} with no name used in boost, this sets default? + self.nameSpaces.append("".join(self.nameStack[1:])) + ns = self.cur_namespace() + self.stack = [] + self.stmtTokens = [] + if ns not in self.namespaces: + self.namespaces.append(ns) + self.lastBraceReason = _BRACE_REASON_NS # Detect special condition of macro magic before class declaration so we # can filter it out - if 'class' in self.nameStack and self.nameStack[0] != 'class': + elif "class" in self.nameStack and self.nameStack[0] != "class": classLocationNS = self.nameStack.index("class") classLocationS = self.stack.index("class") - if "(" not in self.nameStack[classLocationNS:]: - debug_print("keyword 'class' found in unexpected location in nameStack, must be following #define magic. Process that before moving on") + if ( + "(" not in self.nameStack[classLocationNS:] + and self.nameStack[classLocationNS - 1] != "enum" + ): + debug_print( + "keyword 'class' found in unexpected location in nameStack, must be following #define magic. Process that before moving on" + ) origNameStack = self.nameStack origStack = self.stack - #Process first part of stack which is probably #define macro magic and may cause issues + # Process first part of stack which is probably #define macro magic and may cause issues self.nameStack = self.nameStack[:classLocationNS] self.stack = self.stack[:classLocationS] try: - self.evaluate_stack() + self._evaluate_stack() except: debug_print("Error processing #define magic... Oh well") - #Process rest of stack + # Process rest of stack self.nameStack = origNameStack[classLocationNS:] self.stack = origStack[classLocationS:] - - - if len(self.nameStack) and not is_enum_namestack(self.nameStack): - self.evaluate_stack() - else: - self.nameStack.append(tok.value) - if self.stack and self.stack[0] == 'class': self.stack = [] - self.braceDepth += 1 - - elif (tok.type == 'CLOSE_BRACE'): + + # If set to True, indicates that the callee consumed + # all of the tokens between { and } + self.braceHandled = False + if self.nameStack: + self._evaluate_stack() + if self.stack and self.stack[0] == "class": + self.stack = [] + self.stmtTokens = [] + if not self.braceHandled: + self.braceDepth += 1 + self.braceReason.append(self.lastBraceReason) + + elif parenDepth == 0 and tok.type == "}": if self.braceDepth == 0: continue - if (self.braceDepth == len(self.nameSpaces)): - tmp = self.nameSpaces.pop() - self.stack = [] # clear stack when namespace ends? - if len(self.nameStack) and is_enum_namestack(self.nameStack): + reason = self.braceReason.pop() + if reason == _BRACE_REASON_NS: + self.nameSpaces.pop() + self.stack = [] # clear stack when namespace ends? + self.stmtTokens = [] + elif reason == _BRACE_REASON_EXTERN: + self.linkage_stack.pop() + self.stack = [] # clear stack when linkage ends? + self.stmtTokens = [] + # Case : type variable {init}; + elif reason == _BRACE_REASON_VARIABLE: self.nameStack.append(tok.value) - elif self.braceDepth < 10: - self.evaluate_stack() + continue else: - self.nameStack = [] + self._evaluate_stack() self.braceDepth -= 1 - #self.stack = []; print 'BRACE DEPTH', self.braceDepth, 'NS', len(self.nameSpaces) - if self.curClass: debug_print( 'CURBD %s'%self._classes_brace_level[ self.curClass ] ) - if (self.braceDepth == 0) or (self.curClass and self._classes_brace_level[self.curClass]==self.braceDepth): - trace_print( 'END OF CLASS DEF' ) + # if self.curClass: + # debug_print( + # "CURBD %s", self._classes_brace_level[self.curClass] + # ) + + if (self.braceDepth == 0) or ( + self.curClass + and self._classes_brace_level[self.curClass] == self.braceDepth + ): + trace_print("END OF CLASS DEF") if self.accessSpecifierStack: self.curAccessSpecifier = self.accessSpecifierStack[-1] - self.accessSpecifierStack = self.accessSpecifierStack[:-1] - if self.curClass and self.classes[ self.curClass ]['parent']: self.curClass = self.classes[ self.curClass ]['parent'] - else: self.curClass = ""; #self.curStruct = None + self.accessSpecifierStack = self.accessSpecifierStack[:-1] + if self.curClass and self.classes[self.curClass]["parent"]: + thisClass = self.classes[self.curClass] + self.curClass = self.curClass[ + : -(len(thisClass["name"]) + 2) + ] + + # Detect anonymous union members + if ( + self.curClass + and thisClass["declaration_method"] == "union" + and thisClass["name"].startswith("<") + and self.lex.token_if(";") + ): + debug_print("Creating anonymous union") + # Force the processing of an anonymous union + self.nameStack = [""] + self.stack = self.nameStack + [";"] + debug_print("pre eval anon stack") + self._evaluate_stack(";") + debug_print("post eval anon stack") + self.stack = [] + self.nameStack = [] + self.stmtTokens = [] + else: + self.curClass = "" self.stack = [] - - #if self.curStruct: self.curStruct = None - if self.braceDepth == 0 or (self.curStruct and self._structs_brace_level[self.curStruct['type']]==self.braceDepth): - trace_print( 'END OF STRUCT DEF' ) - self.curStruct = None - - if self._method_body and (self.braceDepth + 1) <= self._method_body: - self._method_body = None; self.stack = []; self.nameStack = []; trace_print( 'FORCE CLEAR METHBODY' ) - - if (tok.type == 'OPEN_PAREN'): - self.nameStack.append(tok.value) - elif (tok.type == 'CLOSE_PAREN'): - self.nameStack.append(tok.value) - elif (tok.type == 'OPEN_SQUARE_BRACKET'): - self.nameStack.append(tok.value) - elif (tok.type == 'CLOSE_SQUARE_BRACKET'): - self.nameStack.append(tok.value) - elif (tok.type == 'TAB'): pass - elif (tok.type == 'EQUALS'): - self.nameStack.append(tok.value) - elif (tok.type == 'COMMA'): - self.nameStack.append(tok.value) - elif (tok.type == 'BACKSLASH'): - self.nameStack.append(tok.value) - elif (tok.type == 'DIVIDE'): - self.nameStack.append(tok.value) - elif (tok.type == 'PIPE'): + self.stmtTokens = [] + elif tok.type in _namestack_append_tokens: self.nameStack.append(tok.value) - elif (tok.type == 'PERCENT'): - self.nameStack.append(tok.value) - elif (tok.type == 'CARET'): - self.nameStack.append(tok.value) - elif (tok.type == 'EXCLAMATION'): - self.nameStack.append(tok.value) - elif (tok.type == 'SQUOTE'): pass - elif (tok.type == 'NUMBER' or tok.type == 'FLOAT_NUMBER'): - self.nameStack.append(tok.value) - elif (tok.type == 'MINUS'): - self.nameStack.append(tok.value) - elif (tok.type == 'PLUS'): - self.nameStack.append(tok.value) - elif (tok.type == 'STRING_LITERAL'): - self.nameStack.append(tok.value) - elif (tok.type == 'NAME' or tok.type == 'AMPERSTAND' or tok.type == 'ASTERISK' or tok.type == 'CHAR_LITERAL'): + nameStackAppended = True + elif tok.type in _namestack_pass_tokens: + pass + elif tok.type in _namestack_str_tokens: if tok.value in ignoreSymbols: - debug_print("Ignore symbol %s"%tok.value) - elif (tok.value == 'class'): + debug_print("Ignore symbol %s", tok.value) + elif tok.value == "class": self.nameStack.append(tok.value) - elif tok.value in supportedAccessSpecifier: - if len(self.nameStack) and self.nameStack[0] in ("class", "struct", "union"): - self.nameStack.append(tok.value) - elif self.braceDepth == len(self.nameSpaces) + 1 or self.braceDepth == (len(self.nameSpaces) + len(self.curClass.split("::"))): - self.curAccessSpecifier = tok.value; - self.accessSpecifierScratch.append(tok.value) - debug_print("curAccessSpecifier updated to %s"%self.curAccessSpecifier) - self.stack = [] else: self.nameStack.append(tok.value) - if self.anon_union_counter[0] == self.braceDepth: - self.anon_union_counter = [-1, 0] - elif (tok.type == 'COLON'): - #Dont want colon to be first in stack - if len(self.nameStack) == 0: - self.accessSpecifierScratch = [] - continue - - # Handle situation where access specifiers can be multi words such as "public slots" - jns = " ".join(self.accessSpecifierScratch + self.nameStack) - if jns in supportedAccessSpecifier: - self.curAccessSpecifier = jns; - debug_print("curAccessSpecifier updated to %s"%self.curAccessSpecifier) + elif tok.type == ":": + if self.nameStack and self.nameStack[0] in supportedAccessSpecifier: + specifier = " ".join(self.nameStack) + if specifier in supportedAccessSpecifier: + self.curAccessSpecifier = specifier + else: + self.curAccessSpecifier = self.nameStack[0] + debug_print( + "curAccessSpecifier updated to %s", self.curAccessSpecifier + ) + self.nameStack = [] self.stack = [] + self.stmtTokens = [] + elif is_method_namestack(self.stack): + debug_print("trace") + self._evaluate_method_stack() self.nameStack = [] + self.stack = [] + self.stmtTokens = [] else: self.nameStack.append(tok.value) - self.accessSpecifierScratch = [] - - elif (tok.type == 'SEMI_COLON'): - if self.anon_union_counter[0] == self.braceDepth and self.anon_union_counter[1]: - debug_print("Creating anonymous union") - #Force the processing of an anonymous union - saved_namestack = self.nameStack[:] - saved_stack = self.stack[:] - self.nameStack = [""] - self.stack = self.nameStack + [";"] - self.nameStack = self.nameStack[0:1] - debug_print("pre eval anon stack") - self.evaluate_stack( tok.type ) - debug_print("post eval anon stack") - self.nameStack = saved_namestack - self.stack = saved_stack - self.anon_union_counter = [-1, 0]; - - - if (self.braceDepth < 10): self.evaluate_stack( tok.type ) + + elif tok.type == ";": + self._evaluate_stack(tok.type) self.stack = [] self.nameStack = [] + self.stmtTokens = [] + elif tok.type == "(": + parenDepth += 1 + self.nameStack.append(tok.value) + nameStackAppended = True + elif tok.type == ")": + self.nameStack.append(tok.value) + nameStackAppended = True + if parenDepth != 0: + parenDepth -= 1 + + newNsLen = len(self.nameStack) + if nslen != newNsLen and newNsLen == 1: + if not self._doxygen_cache: + self._doxygen_cache = self.lex.get_doxygen() + + except Exception as e: + if debug: + raise + context = "" + if isinstance(e, CppParseError): + context = ": " + str(e) + if e.tok: + tok = e.tok + + if tok: + filename, lineno = tok.location + msg = ( + "Not able to parse %s on line %d evaluating '%s'%s\nError around: %s" + % (filename, lineno, tok.value, context, " ".join(self.nameStack)) + ) + else: + msg = "Error parsing %s%s\nError around: %s" % ( + self.headerFileName, + context, + " ".join(self.nameStack), + ) - except: - if (debug): raise - raise CppParseError("Not able to parse %s on line %d evaluating \"%s\"\nError around: %s" - % (self.headerFileName, tok.lineno, tok.value, " ".join(self.nameStack))) + raise_exc( + CppParseError(msg), + e, + ) self.finalize() global parseHistory parseHistory = [] # Delete some temporary variables - for key in ["_precomp_macro_buf", "nameStack", "nameSpaces", "curAccessSpecifier", "accessSpecifierStack", - "accessSpecifierScratch", "nameStackHistory", "anon_struct_counter", "anon_union_counter", - "_classes_brace_level", "_forward_decls", "stack", "mainClass", "curStruct", "_template_typenames", - "_method_body", "braceDepth", "_structs_brace_level", "typedefs_order", "curTemplate", "templateRegistry"]: + for key in [ + "_precomp_macro_buf", + "_doxygen_cache", + "braceHandled", + "lex", + "nameStack", + "nameSpaces", + "curAccessSpecifier", + "accessSpecifierStack", + "nameStackHistory", + "anon_struct_counter", + "anon_union_counter", + "anon_class_counter", + "_classes_brace_level", + "_forward_decls", + "stack", + "mainClass", + "_template_typenames", + "braceDepth", + "stmtTokens", + "typedefs_order", + "curTemplate", + ]: del self.__dict__[key] - - def evaluate_stack(self, token=None): + def _get_location(self, stack): + if stack: + location = getattr(stack[0], "location", None) + if location is not None: + return location + + return self.lex.current_location() + + def _get_stmt_doxygen(self): + # retrieves the doxygen comment associated with an accumulated + # statement (since doxygen comments have to be retrieved immediately) + doxygen, self._doxygen_cache = self._doxygen_cache, "" + if not doxygen: + doxygen = self.lex.get_doxygen() + return doxygen + + def _parse_error(self, tokens, expected): + if not tokens: + # common case after a failed token_if + errtok = self.lex.token() + else: + errtok = tokens[-1] + if expected: + expected = ", expected '" + expected + "'" + + msg = "unexpected '%s'%s" % (errtok.value, expected) + + # TODO: better error message + return CppParseError(msg, errtok) + + def _next_token_must_be(self, *tokenTypes): + tok = self.lex.token() + if tok.type not in tokenTypes: + raise self._parse_error((tok,), "' or '".join(tokenTypes)) + return tok + + _end_balanced_tokens = {">", "}", "]", ")", "DBL_RBRACKET"} + _balanced_token_map = { + "<": ">", + "{": "}", + "(": ")", + "[": "]", + "DBL_LBRACKET": "DBL_RBRACKET", + } + + def _consume_balanced_tokens(self, *init_tokens): + _balanced_token_map = self._balanced_token_map + + consumed = list(init_tokens) + match_stack = deque((_balanced_token_map[tok.type] for tok in consumed)) + get_token = self.lex.token + + while True: + tok = get_token() + consumed.append(tok) + + if tok.type in self._end_balanced_tokens: + expected = match_stack.pop() + if tok.type != expected: + # hack: ambiguous right-shift issues here, really + # should be looking at the context + if tok.type == ">": + tok = self.lex.token_if(">") + if tok: + consumed.append(tok) + match_stack.append(expected) + continue + + raise self._parse_error(consumed, expected) + if len(match_stack) == 0: + return consumed + + continue + + next_end = _balanced_token_map.get(tok.type) + if next_end: + match_stack.append(next_end) + + def _discard_contents(self, start_type, end_type): + # use this instead of consume_balanced_tokens because + # we don't care at all about the internals + level = 1 + get_token = self.lex.token + while True: + tok = get_token() + if tok.type == start_type: + level += 1 + elif tok.type == end_type: + level -= 1 + if level == 0: + break + + def _discard_ctor_initializer(self): + """ + ctor_initializer: ":" mem_initializer_list + + mem_initializer_list: mem_initializer ["..."] + | mem_initializer "," mem_initializer_list ["..."] + + mem_initializer: mem_initializer_id "(" [expression_list] ")" + | mem_initializer_id braced_init_list + + mem_initializer_id: class_or_decltype + | IDENTIFIER + """ + debug_print("discarding ctor intializer") + # all of this is discarded.. the challenge is to determine + # when the initializer ends and the function starts + while True: + tok = self.lex.token() + if tok.type == "DBL_COLON": + tok = self.lex.token() + + if tok.type == "decltype": + tok = self._next_token_must_be("(") + self._consume_balanced_tokens(tok) + tok = self.lex.token() + + # each initializer is either foo() or foo{}, so look for that + while True: + if tok.type not in ("{", "("): + tok = self.lex.token() + continue + + if tok.type == "{": + self._discard_contents("{", "}") + elif tok.type == "(": + self._discard_contents("(", ")") + + tok = self.lex.token() + break + + # at the end + if tok.type == "ELLIPSIS": + tok = self.lex.token() + + if tok.type == ",": + continue + elif tok.type == "{": + # reached the function + self._discard_contents("{", "}") + return + else: + raise self._parse_error((tok,), ",' or '{") + + def _evaluate_stack(self, token=None): """Evaluates the current name stack""" - global doxygenCommentCache - - self.nameStack = filter_out_attribute_keyword(self.nameStack) - self.stack = filter_out_attribute_keyword(self.stack) + nameStackCopy = self.nameStack[:] - - debug_print( "Evaluating stack %s\n BraceDepth: %s (called from %d)" %(self.nameStack,self.braceDepth, inspect.currentframe().f_back.f_lineno)) - - #Handle special case of overloading operator () + + debug_print( + "Evaluating stack %s\n BraceDepth: %s (called from %s)", + self.nameStack, + self.braceDepth, + debug_caller_lineno, + ) + + # Handle special case of overloading operator () if "operator()(" in "".join(self.nameStack): operator_index = self.nameStack.index("operator") self.nameStack.pop(operator_index + 2) self.nameStack.pop(operator_index + 1) self.nameStack[operator_index] = "operator()" - - if (len(self.curClass)): - debug_print( "%s (%s) "%(self.curClass, self.curAccessSpecifier)) + + if len(self.curClass): + debug_print("%s (%s) ", self.curClass, self.curAccessSpecifier) else: - debug_print( " (%s) "%self.curAccessSpecifier) + debug_print(" (%s) ", self.curAccessSpecifier) - #Filter special case of array with casting in it + # Filter special case of array with casting in it try: bracePos = self.nameStack.index("[") parenPos = self.nameStack.index("(") if bracePos == parenPos - 1: endParen = self.nameStack.index(")") - self.nameStack = self.nameStack[:bracePos + 1] + self.nameStack[endParen + 1:] - debug_print("Filtered namestack to=%s"%self.nameStack) - except: pass - - #if 'typedef' in self.nameStack: self.evaluate_typedef() # allows nested typedefs, probably a bad idea - if (not self.curClass and 'typedef' in self.nameStack and - (('struct' not in self.nameStack and 'union' not in self.nameStack) or self.stack[-1] == ";") and - not is_enum_namestack(self.nameStack)): - trace_print('STACK', self.stack) - self.evaluate_typedef() + self.nameStack = ( + self.nameStack[: bracePos + 1] + self.nameStack[endParen + 1 :] + ) + debug_print("Filtered namestack to=%s", self.nameStack) + except: + pass + + # if 'typedef' in self.nameStack: self._evaluate_typedef() # allows nested typedefs, probably a bad idea + if ( + not self.curClass + and "typedef" in self.nameStack + and ( + ( + "struct" not in self.nameStack + and "union" not in self.nameStack + and "enum" not in self.nameStack + ) + or self.stack[-1] == ";" + ) + ): + debug_print("trace") + trace_print("typedef", self.stack) + self._evaluate_typedef() return - - elif (len(self.nameStack) == 0): - debug_print( "trace" ) - debug_print( "(Empty Stack)" ) + + elif len(self.nameStack) == 0: + debug_print("trace (Empty Stack)") return - elif (self.nameStack[0] == "namespace"): - #Taken care of outside of here + elif self.nameStack[0] == "namespace": + # Taken care of outside of here pass - elif len(self.nameStack) == 2 and self.nameStack[0] == "friend":#friend class declaration + elif len(self.nameStack) == 2 and self.nameStack[0] == "extern": + debug_print("trace extern") + self.linkage_stack.append(self.nameStack[1].strip('"')) + self.stack = [] + self.stmtTokens = [] + self.lastBraceReason = _BRACE_REASON_EXTERN + elif ( + len(self.nameStack) == 2 and self.nameStack[0] == "friend" + ): # friend class declaration pass - elif len(self.nameStack) >= 2 and self.nameStack[0] == 'using' and self.nameStack[1] == 'namespace': pass # TODO + elif len(self.nameStack) >= 2 and self.nameStack[0] == "using": + if self.nameStack[1] == "namespace": + pass + else: + if len(self.nameStack) > 3 and self.nameStack[2] == "=": + # using foo = ns::bar + # -> type alias: same behavior in all scopes + alias = self.nameStack[1] + ns, stack = _split_namespace(self.nameStack[3:]) + atype = CppVariable( + stack, + self._get_stmt_doxygen(), + self._get_location(stack), + is_var=False, + ) + + # namespace refers to the embedded type + atype["namespace"] = ns + atype["using_type"] = "typealias" + atype["typealias"] = alias + else: + # using foo::bar + # -> in global scope this is bringing in something + # from a different namespace + # -> in class scope this is bringing in a member + # from a base class + ns, stack = _split_namespace(self.nameStack[1:]) + atype = CppVariable( + stack, + self._get_stmt_doxygen(), + self._get_location(stack), + is_var=False, + ) + alias = atype["type"] + atype["using_type"] = "declaration" + if self.curClass: + atype["baseclass"] = ns + else: + atype["namespace"] = ns + + atype["template"] = self.curTemplate + self.curTemplate = None + + if atype["type"].startswith("typename "): + atype["raw_type"] = "typename " + ns + atype["type"][9:] + else: + atype["raw_type"] = ns + atype["type"] + atype["access"] = self.curAccessSpecifier + if self.curClass: + klass = self.classes[self.curClass] + klass["using"][alias] = atype + else: + # lookup is done + alias = self.current_namespace() + alias + self.using[alias] = atype + elif is_method_namestack(self.stack) and "(" in self.nameStack: + debug_print("trace") + self._evaluate_method_stack() elif is_enum_namestack(self.nameStack): - debug_print( "trace" ) - self.evaluate_enum_stack() - - elif self._method_body and (self.braceDepth + 1) > self._method_body: trace_print( 'INSIDE METHOD DEF' ) - elif is_method_namestack(self.stack) and not self.curStruct and '(' in self.nameStack: - debug_print( "trace" ) - if self.braceDepth > 0: - if "{" in self.stack and self.stack[0] != '{' and self.stack[-1] == ';' and self.braceDepth == 1: - #Special case of a method defined outside a class that has a body - pass - else: - self.evaluate_method_stack() - else: - #Free function - self.evaluate_method_stack() - elif (len(self.nameStack) == 1 and len(self.nameStackHistory) > self.braceDepth - and (self.nameStackHistory[self.braceDepth][0][0:2] == ["typedef", "struct"] or - self.nameStackHistory[self.braceDepth][0][0:2] == ["typedef", "union"])): + debug_print("trace") + self._parse_enum() + self.stack = [] + self.stmtTokens = [] + elif ( + len(self.nameStack) == 1 + and len(self.nameStackHistory) > self.braceDepth + and ( + self.nameStackHistory[self.braceDepth][0][0:2] == ["typedef", "struct"] + or self.nameStackHistory[self.braceDepth][0][0:2] + == ["typedef", "union"] + ) + ): # Look for the name of a typedef struct: struct typedef {...] StructName; or unions to get renamed debug_print("found the naming of a union") type_name_to_rename = self.nameStackHistory[self.braceDepth][1] new_name = self.nameStack[0] type_to_rename = self.classes[type_name_to_rename] type_to_rename["name"] = self.nameStack[0] - #Now re install it in its new location + # Now re install it in its new location self.classes[new_name] = type_to_rename if new_name != type_name_to_rename: - del self.classes[type_name_to_rename] - elif is_property_namestack(self.nameStack) and self.stack[-1] == ';': - debug_print( "trace" ) - if self.nameStack[0] in ('class', 'struct') and len(self.stack) == 3: self.evalute_forward_decl() - elif len(self.nameStack) >= 2 and (self.nameStack[0]=='friend' and self.nameStack[1]=='class'): pass - else: self.evaluate_property_stack() # catches class props and structs in a namespace - - elif self.nameStack[0] in ("class", "struct", "union") or self.nameStack[0] == 'typedef' and self.nameStack[1] in ('struct', 'union'): - #Parsing a union can reuse much of the class parsing - debug_print( "trace" ) - self.evaluate_class_stack() + del self.classes[type_name_to_rename] + elif is_property_namestack(self.nameStack) and self.stack[-1] == ";": + debug_print("trace") + if self.nameStack[0] in ("class", "struct") and len(self.stack) == 3: + self.evalute_forward_decl() + elif len(self.nameStack) >= 2 and ( + self.nameStack[0] == "friend" and self.nameStack[1] == "class" + ): + pass + else: + self._evaluate_property_stack() # catches class props and structs in a namespace + + elif ( + self.nameStack[0] in ("class", "struct", "union") + or self.nameStack[0] == "typedef" + and self.nameStack[1] in ("struct", "union") + ): + # Parsing a union can reuse much of the class parsing + debug_print("trace") + self._evaluate_class_stack() elif not self.curClass: - debug_print( "trace" ) - if is_enum_namestack(self.nameStack): self.evaluate_enum_stack() - elif self.curStruct and self.stack[-1] == ';': self.evaluate_property_stack() # this catches fields of global structs - self.nameStack = [] - doxygenCommentCache = "" - elif (self.braceDepth < 1): - debug_print( "trace" ) - #Ignore global stuff for now - debug_print( "Global stuff: %s"%self.nameStack ) - self.nameStack = [] - doxygenCommentCache = "" - elif (self.braceDepth > len(self.nameSpaces) + 1): - debug_print( "trace" ) - self.nameStack = [] - doxygenCommentCache = "" + debug_print("trace") + elif self.braceDepth < 1: + debug_print("trace") + # Ignore global stuff for now + debug_print("Global stuff: %s" % self.nameStack) + elif self.braceDepth > len(self.nameSpaces) + 1: + debug_print("trace") + else: + debug_print("Discarded statement %s", self.nameStack) try: self.nameStackHistory[self.braceDepth] = (nameStackCopy, self.curClass) except: self.nameStackHistory.append((nameStackCopy, self.curClass)) - self.nameStack = [] # its a little confusing to have some if/else above return and others not, and then clearning the nameStack down here - doxygenCommentCache = "" + + # its a little confusing to have some if/else above return and others not, and then clearning the nameStack down here + self.nameStack = [] + self._doxygen_cache = None self.curTemplate = None - - - def evaluate_enum_stack(self): - """Create an Enum out of the name stack""" - debug_print( "evaluating enum" ) - newEnum = CppEnum(self.nameStack) - if len(list(newEnum.keys())): - if len(self.curClass): - newEnum["namespace"] = self.cur_namespace(False) - klass = self.classes[self.curClass] - klass["enums"][self.curAccessSpecifier].append(newEnum) - if self.curAccessSpecifier == 'public' and 'name' in newEnum: klass._public_enums[ newEnum['name'] ] = newEnum + + def _parse_template(self): + # check for 'extern template' + extern_template = False + if len(self.stmtTokens) == 1 and self.stmtTokens[0].value == "extern": + extern_template = True + tok = self._next_token_must_be("NAME") + if not tok.value == "class": + raise self._parse_error((tok,), "class") + + tok = self._next_token_must_be("NAME") + if tok.value == "__attribute__": + self._parse_gcc_attribute() + tok = self._next_token_must_be("NAME") + + extern_template_name = tok.value + + tok = self._next_token_must_be("<") + consumed = self._consume_balanced_tokens(tok) + tmpl = " ".join(tok.value for tok in consumed) + tmpl = ( + tmpl.replace(" :: ", "::") + .replace(" <", "<") + .replace("< ", "<") + .replace(" >", ">") + .replace("> ", ">") + .replace(" , ", ", ") + .replace(" = ", "=") + ) + + if extern_template: + self.extern_templates.append( + CppExternTemplate( + name=extern_template_name, + params=tmpl, + namespace=self.cur_namespace(), + ) + ) + self.stack = [] + self.nameStack = [] + self.stmtTokens = [] + else: + self.curTemplate = "template" + tmpl + + def _parse_gcc_attribute(self): + tok1 = self._next_token_must_be("(") + tok2 = self._next_token_must_be("(") + self._consume_balanced_tokens(tok1, tok2) + + _attribute_specifier_seq_start_types = ("DBL_LBRACKET", "NAME") + _attribute_specifier_seq_start_values = ("[[", "alignas") + + def _parse_attribute_specifier_seq(self, tok): + # TODO: retain the attributes and do something with them + # attrs = [] + + while True: + if tok.type == "DBL_LBRACKET": + tokens = self._consume_balanced_tokens(tok) + # attrs.append(Attribute(tokens)) + elif tok.type == "NAME" and tok.value == "alignas": + next_tok = self._next_token_must_be("(") + tokens = self._consume_balanced_tokens(next_tok) + # attrs.append(AlignasAttribute(tokens)) + else: + self.lex.return_token(tok) + break + + # multiple attributes can be specified + tok = self.lex.token_if(*self._attribute_specifier_seq_start_types) + if tok is None: + break + + # return attrs + + def _parse_enum(self): + """ + opaque_enum_declaration: enum_key [attribute_specifier_seq] IDENTIFIER [enum_base] ";" + + enum_specifier: enum_head "{" [enumerator_list] "}" + | enum_head "{" enumerator_list "," "}" + + enum_head: enum_key [attribute_specifier_seq] [IDENTIFIER] [enum_base] + | enum_key [attribute_specifier_seq] nested_name_specifier IDENTIFIER [enum_base] + + enum_key: "enum" + | "enum" "class" + | "enum" "struct" + + enum_base: ":" type_specifier_seq + """ + debug_print("parsing enum") + + is_typedef = False + self.lex.return_tokens(self.stmtTokens) + + doxygen = self._get_stmt_doxygen() + + tok = self.lex.token() + if tok.value == "typedef": + is_typedef = True + tok = self.lex.token() + + if tok.value != "enum": + raise self._parse_error((tok,), "enum") + + location = tok.location + + is_class = False + nametok = self.lex.token() + if nametok.value in ("class", "struct"): + is_class = True + nametok = self.lex.token() + + if nametok.value == "__attribute__": + self._parse_gcc_attribute() + nametok = self.lex.token() + + if nametok.value in self._attribute_specifier_seq_start_values: + self._parse_attribute_specifier_seq(nametok) + nametok = self.lex.token() + + # TODO: nested_name_specifier + name = "" + if nametok.type == "NAME": + name = nametok.value + debug_print("enum name is '%s'", name) + tok = self.lex.token() + else: + debug_print("anonymous enum") + tok = nametok + + base = [] + if tok.type == ":": + while True: + tok = self.lex.token() + if tok.type in ("{", ";"): + break + base.append(tok.value) + + newEnum = CppEnum(name, doxygen, location) + if is_typedef: + newEnum["typedef"] = True + if is_class: + newEnum["isclass"] = True + if base: + newEnum["type"] = "".join(base) + + instancesData = [] + + if tok.type == "{": + self.braceHandled = True + self._parse_enumerator_list(newEnum["values"]) + newEnum.resolve_enum_values(newEnum["values"]) + tok = self.lex.token() + + if tok.value == "__attribute__": + self._parse_gcc_attribute() + tok = self.lex.token() + + if tok.type == "NAME": + if newEnum["typedef"]: + newEnum["name"] = tok.value + self._next_token_must_be(";") else: - newEnum["namespace"] = self.cur_namespace(True) - self.enums.append(newEnum) - if 'name' in newEnum and newEnum['name']: self.global_enums[ newEnum['name'] ] = newEnum - - #This enum has instances, turn them into properties - if "instances" in newEnum: - instanceType = "enum" - if "name" in newEnum: - instanceType = newEnum["name"] - for instance in newEnum["instances"]: - self.nameStack = [instanceType, instance] - self.evaluate_property_stack() - del newEnum["instances"] - - def strip_parent_keys(self): + # this is an instance of the enum + instancesData.append(tok.value) + while True: + tok = self.lex.token() + if tok.type == ";": + break + instancesData.append(tok.value) + elif tok.type != ";": + raise self._parse_error((tok,), ";") + + self._install_enum(newEnum, instancesData) + + def _install_enum(self, newEnum, instancesData): + if len(self.curClass): + newEnum["namespace"] = self.cur_namespace(False) + newEnum["linkage"] = self.cur_linkage() + klass = self.classes[self.curClass] + klass["enums"][self.curAccessSpecifier].append(newEnum) + if self.curAccessSpecifier == "public" and "name" in newEnum: + klass._public_enums[newEnum["name"]] = newEnum + else: + newEnum["namespace"] = self.cur_namespace(True) + newEnum["linkage"] = self.cur_linkage() + self.enums.append(newEnum) + if "name" in newEnum and newEnum["name"]: + self.global_enums[newEnum["name"]] = newEnum + + # This enum has instances, turn them into properties + if instancesData: + instances = list(_split_by_comma(instancesData)) + instanceType = "enum" + if "name" in newEnum: + instanceType = newEnum["name"] + addToVar = {"enum_type": newEnum} + for instance in instances: + self.nameStack = [instanceType] + instance + self._evaluate_property_stack(clearStack=False, addToVar=addToVar) + + def _parse_enumerator_list(self, values): + """ + enumerator_list: enumerator_definition + | enumerator_list "," enumerator_definition + + enumerator_definition: enumerator + | enumerator "=" constant_expression + + enumerator: IDENTIFIER + """ + while True: + name_tok = self._next_token_must_be("}", "NAME") + if name_tok.value == "}": + return + + value = {"name": name_tok.value} + doxygen = self.lex.get_doxygen() + if doxygen: + value["doxygen"] = doxygen + values.append(value) + + debug_print("enumerator value '%s'", value["name"]) + + tok = self._next_token_must_be("}", ",", "=", "DBL_LBRACKET") + if tok.type == "DBL_LBRACKET": + self._parse_attribute_specifier_seq(tok) + tok = self._next_token_must_be("}", ",", "=") + + if tok.type == "}": + return + elif tok.type == ",": + continue + elif tok.type == "=": + v = [] + while True: + tok = self.lex.token() + if tok.type == "}": + value["value"] = " ".join(v) + return + elif tok.type == ",": + value["value"] = " ".join(v) + break + elif tok.type in self._balanced_token_map: + v.extend(t.value for t in self._consume_balanced_tokens(tok)) + else: + v.append(tok.value) + + def _strip_parent_keys(self): """Strip all parent (and method) keys to prevent loops""" obj_queue = [self] while len(obj_queue): obj = obj_queue.pop() - trace_print("pop %s type %s"%(obj, type(obj))) + trace_print("pop", obj, "type", type(obj)) try: if "parent" in obj.keys(): del obj["parent"] - trace_print("Stripped parent from %s"%obj.keys()) - except: pass + trace_print("Stripped parent from", obj.keys()) + except: + pass try: if "method" in obj.keys(): del obj["method"] - trace_print("Stripped method from %s"%obj.keys()) - except: pass + trace_print("Stripped method from", obj.keys()) + except: + pass # Figure out what sub types are one of ours try: - if not hasattr(obj, 'keys'): + if not hasattr(obj, "keys"): obj = obj.__dict__ for k in obj.keys(): - trace_print("-Try key %s"%(k)) - trace_print("-type %s"%(type(obj[k]))) - if k in ["nameStackHistory", "parent", "_public_typedefs"]: continue + trace_print("-Try key", k) + trace_print("-type", type(obj[k])) + if k in ["nameStackHistory", "parent", "_public_typedefs"]: + continue if type(obj[k]) == list: for i in obj[k]: - trace_print("push l %s"%i) + trace_print("push l", i) obj_queue.append(i) - elif type(obj[k]) == dict: + elif type(obj[k]) == dict: if len(obj): - trace_print("push d %s"%obj[k]) + trace_print("push d", obj[k]) obj_queue.append(obj[k]) elif type(obj[k]) == type(type(0)): if type(obj[k]) == int: @@ -2583,39 +3814,57 @@ def strip_parent_keys(self): except: trace_print("Exception") - def toJSON(self, indent=4): + def toJSON(self, indent=4, separators=None): """Converts a parsed structure to JSON""" import json - self.strip_parent_keys() + + self._strip_parent_keys() + + def clean_dict(markers, keys=[]): + if id(markers) in keys: + return None + elif isinstance(markers, dict): + keys_ = keys + [id(markers)] + return { + key: clean_dict(markers[key], keys_) + for key, value in markers.items() + } + elif type(markers) in [list, set, tuple]: + return type(markers)(clean_dict(m, keys) for m in markers) + return markers + try: del self.__dict__["classes_order"] - except: pass - return json.dumps(self.__dict__, indent=indent) + except: + pass + d = self.__dict__ + d["classes"] = clean_dict(d["classes"]) + return json.dumps(d, indent=indent, separators=separators, default="") def __repr__(self): rtn = { - "classes": self.classes, - "functions": self.functions, - "enums": self.enums, - "variables": self.variables, + "classes": self.classes, + "functions": self.functions, + "enums": self.enums, + "variables": self.variables, } return repr(rtn) def __str__(self): rtn = "" for className in list(self.classes.keys()): - rtn += "%s\n"%self.classes[className] + rtn += "%s\n" % self.classes[className] if self.functions: rtn += "// functions\n" for f in self.functions: - rtn += "%s\n"%f + rtn += "%s\n" % f if self.variables: rtn += "// variables\n" for f in self.variables: - rtn += "%s\n"%f + rtn += "%s\n" % f if self.enums: rtn += "// enums\n" for f in self.enums: - rtn += "%s\n"%f + rtn += "%s\n" % f return rtn diff --git a/CppHeaderParser/Makefile b/CppHeaderParser/Makefile deleted file mode 100644 index e3fce3e..0000000 --- a/CppHeaderParser/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -all: package - -package: - @zip CppHeaderParser-`grep __version__ CppHeaderParser.py | sed 's/.*"\([^"]*\)"/\1/'`.zip CppHeaderParser.html CppHeaderParser.py \ No newline at end of file diff --git a/CppHeaderParser/__init__.py b/CppHeaderParser/__init__.py index 024da04..facdf9b 100644 --- a/CppHeaderParser/__init__.py +++ b/CppHeaderParser/__init__.py @@ -2,5 +2,6 @@ # Author: Jashua Cloutier (contact via sourceforge username:senexcanis) from .CppHeaderParser import * +from .CppHeaderParser import __version__ -#__all__ = ['CppHeaderParser'] +# __all__ = ['CppHeaderParser'] diff --git a/CppHeaderParser/doc/CppHeaderParser.html b/CppHeaderParser/doc/CppHeaderParser.html deleted file mode 100644 index 8301bdb..0000000 --- a/CppHeaderParser/doc/CppHeaderParser.html +++ /dev/null @@ -1,1463 +0,0 @@ - - -Codestin Search App - - - - - -
 
- 
CppHeaderParser (version 2.7.4)
index
/home/senex/workspace/cppheaderparser/CppHeaderParser/CppHeaderParser.py
-

Parse C++ header files and generate a data structure
-representing the class

-

- - - - - -
 
-Modules
       
inspect
-ply.lex
-
os
-re
-
sys
-

- - - - - -
 
-Classes
       
-
_CppEnum(__builtin__.dict) -
-
-
CppEnum -
-
-
_CppHeader(Resolver) -
-
-
CppHeader -
-
-
_CppMethod(__builtin__.dict) -
-
-
CppMethod -
-
-
_CppVariable(__builtin__.dict) -
-
-
CppVariable -
-
-
__builtin__.dict(__builtin__.object) -
-
-
CppClass -
-
-
CppUnion -
-
-
CppStruct -
-
-
__builtin__.object -
-
-
Resolver -
-
-
__builtin__.str(__builtin__.basestring) -
-
-
TagStr -
-
-
exceptions.Exception(exceptions.BaseException) -
-
-
CppParseError -
-
-
-

- - - - - - - -
 
-class CppClass(__builtin__.dict)
   Takes a name stack and turns it into a class

-Contains the following Keys:
-self['name'] - Name of the class
-self['doxygen'] - Doxygen comments associated with the class if they exist
-self['inherits'] - List of Classes that this one inherits where the values
-    are of the form {"access": Anything in supportedAccessSpecifier
-                              "class": Name of the class
-self['methods'] - Dictionary where keys are from supportedAccessSpecifier
-    and values are a lists of CppMethod's
-self['properties'] - Dictionary where keys are from supportedAccessSpecifier
-    and values are lists of CppVariable's 
-self['enums'] - Dictionary where keys are from supportedAccessSpecifier and
-    values are lists of CppEnum's
-self['structs'] - Dictionary where keys are from supportedAccessSpecifier and
-    values are lists of nested Struct's

-An example of how this could look is as follows:
-#self =
-{
-    'name': ""
-    'inherits':[]
-    'methods':
-    {
-        'public':[],
-        'protected':[], 
-        'private':[]
-    }, 
-    'properties':
-    {
-        'public':[],
-        'protected':[], 
-        'private':[]
-    },
-    'enums':
-    {
-        'public':[],
-        'protected':[], 
-        'private':[]
-    }
-}
 
 
Method resolution order:
-
CppClass
-
__builtin__.dict
-
__builtin__.object
-
-
-Methods defined here:
-
__init__(self, nameStack, curTemplate)
- -
__str__(self)
Convert class to a string
- -
get_all_method_names(self)
- -
get_all_methods(self)
- -
get_all_pure_virtual_methods(self)
- -
get_method_names(self, type='public')
- -
get_pure_virtual_methods(self, type='public')
- -
show(self)
Convert class to a string
- -
-Data descriptors defined here:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-
-Methods inherited from __builtin__.dict:
-
__cmp__(...)
x.__cmp__(y) <==> cmp(x,y)
- -
__contains__(...)
D.__contains__(k) -> True if D has a key k, else False
- -
__delitem__(...)
x.__delitem__(y) <==> del x[y]
- -
__eq__(...)
x.__eq__(y) <==> x==y
- -
__ge__(...)
x.__ge__(y) <==> x>=y
- -
__getattribute__(...)
x.__getattribute__('name') <==> x.name
- -
__getitem__(...)
x.__getitem__(y) <==> x[y]
- -
__gt__(...)
x.__gt__(y) <==> x>y
- -
__iter__(...)
x.__iter__() <==> iter(x)
- -
__le__(...)
x.__le__(y) <==> x<=y
- -
__len__(...)
x.__len__() <==> len(x)
- -
__lt__(...)
x.__lt__(y) <==> x<y
- -
__ne__(...)
x.__ne__(y) <==> x!=y
- -
__repr__(...)
x.__repr__() <==> repr(x)
- -
__setitem__(...)
x.__setitem__(i, y) <==> x[i]=y
- -
__sizeof__(...)
D.__sizeof__() -> size of D in memory, in bytes
- -
clear(...)
D.clear() -> None.  Remove all items from D.
- -
copy(...)
D.copy() -> a shallow copy of D
- -
fromkeys(...)
dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.
-v defaults to None.
- -
get(...)
D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
- -
has_key(...)
D.has_key(k) -> True if D has a key k, else False
- -
items(...)
D.items() -> list of D's (key, value) pairs, as 2-tuples
- -
iteritems(...)
D.iteritems() -> an iterator over the (key, value) items of D
- -
iterkeys(...)
D.iterkeys() -> an iterator over the keys of D
- -
itervalues(...)
D.itervalues() -> an iterator over the values of D
- -
keys(...)
D.keys() -> list of D's keys
- -
pop(...)
D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
-If key is not found, d is returned if given, otherwise KeyError is raised
- -
popitem(...)
D.popitem() -> (k, v), remove and return some (key, value) pair as a
-2-tuple; but raise KeyError if D is empty.
- -
setdefault(...)
D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
- -
update(...)
D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
-If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
-If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
-In either case, this is followed by: for k in F: D[k] = F[k]
- -
values(...)
D.values() -> list of D's values
- -
viewitems(...)
D.viewitems() -> a set-like object providing a view on D's items
- -
viewkeys(...)
D.viewkeys() -> a set-like object providing a view on D's keys
- -
viewvalues(...)
D.viewvalues() -> an object providing a view on D's values
- -
-Data and other attributes inherited from __builtin__.dict:
-
__hash__ = None
- -
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T
- -

- - - - - - - -
 
-class CppEnum(_CppEnum)
   Takes a name stack and turns it into an Enum

-Contains the following Keys:
-self['name'] - Name of the enum (ex. "ItemState")
-self['namespace'] - Namespace containing the enum
-self['values'] - List of values where the values are a dictionary of the
-    form {"name": name of the key (ex. "PARSING_HEADER"),
-              "value": Specified value of the enum, this key will only exist
-                if a value for a given enum value was defined
-            }
 
 
Method resolution order:
-
CppEnum
-
_CppEnum
-
__builtin__.dict
-
__builtin__.object
-
-
-Methods defined here:
-
__init__(self, nameStack)
- -
-Methods inherited from _CppEnum:
-
resolve_enum_values(self, values)
Evaluates the values list of dictionaries passed in and figures out what the enum value
-for each enum is editing in place:

-Example:
-From: [{'name': 'ORANGE'},
-       {'name': 'RED'},
-       {'name': 'GREEN', 'value': '8'}]
-To:   [{'name': 'ORANGE', 'value': 0},
-       {'name': 'RED', 'value': 1},
-       {'name': 'GREEN', 'value': 8}]
- -
-Data descriptors inherited from _CppEnum:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-
-Methods inherited from __builtin__.dict:
-
__cmp__(...)
x.__cmp__(y) <==> cmp(x,y)
- -
__contains__(...)
D.__contains__(k) -> True if D has a key k, else False
- -
__delitem__(...)
x.__delitem__(y) <==> del x[y]
- -
__eq__(...)
x.__eq__(y) <==> x==y
- -
__ge__(...)
x.__ge__(y) <==> x>=y
- -
__getattribute__(...)
x.__getattribute__('name') <==> x.name
- -
__getitem__(...)
x.__getitem__(y) <==> x[y]
- -
__gt__(...)
x.__gt__(y) <==> x>y
- -
__iter__(...)
x.__iter__() <==> iter(x)
- -
__le__(...)
x.__le__(y) <==> x<=y
- -
__len__(...)
x.__len__() <==> len(x)
- -
__lt__(...)
x.__lt__(y) <==> x<y
- -
__ne__(...)
x.__ne__(y) <==> x!=y
- -
__repr__(...)
x.__repr__() <==> repr(x)
- -
__setitem__(...)
x.__setitem__(i, y) <==> x[i]=y
- -
__sizeof__(...)
D.__sizeof__() -> size of D in memory, in bytes
- -
clear(...)
D.clear() -> None.  Remove all items from D.
- -
copy(...)
D.copy() -> a shallow copy of D
- -
fromkeys(...)
dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.
-v defaults to None.
- -
get(...)
D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
- -
has_key(...)
D.has_key(k) -> True if D has a key k, else False
- -
items(...)
D.items() -> list of D's (key, value) pairs, as 2-tuples
- -
iteritems(...)
D.iteritems() -> an iterator over the (key, value) items of D
- -
iterkeys(...)
D.iterkeys() -> an iterator over the keys of D
- -
itervalues(...)
D.itervalues() -> an iterator over the values of D
- -
keys(...)
D.keys() -> list of D's keys
- -
pop(...)
D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
-If key is not found, d is returned if given, otherwise KeyError is raised
- -
popitem(...)
D.popitem() -> (k, v), remove and return some (key, value) pair as a
-2-tuple; but raise KeyError if D is empty.
- -
setdefault(...)
D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
- -
update(...)
D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
-If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
-If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
-In either case, this is followed by: for k in F: D[k] = F[k]
- -
values(...)
D.values() -> list of D's values
- -
viewitems(...)
D.viewitems() -> a set-like object providing a view on D's items
- -
viewkeys(...)
D.viewkeys() -> a set-like object providing a view on D's keys
- -
viewvalues(...)
D.viewvalues() -> an object providing a view on D's values
- -
-Data and other attributes inherited from __builtin__.dict:
-
__hash__ = None
- -
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T
- -

- - - - - - - -
 
-class CppHeader(_CppHeader)
   Parsed C++ class header

-Variables produced:
-self.classes - Dictionary of classes found in a given header file where the
-    key is the name of the class
 
 
Method resolution order:
-
CppHeader
-
_CppHeader
-
Resolver
-
__builtin__.object
-
-
-Methods defined here:
-
__init__(self, headerFileName, argType='file', **kwargs)
Create the parsed C++ header file parse tree

-headerFileName - Name of the file to parse OR actual file contents (depends on argType)
-argType - Indicates how to interpret headerFileName as a file string or file name
-kwargs - Supports the following keywords
- -
__repr__(self)
- -
__str__(self)
- -
evaluate_enum_stack(self)
Create an Enum out of the name stack
- -
evaluate_stack(self, token=None)
Evaluates the current name stack
- -
show(self)
- -
strip_parent_keys(self)
Strip all parent (and method) keys to prevent loops
- -
toJSON(self, indent=4)
Converts a parsed structure to JSON
- -
-Data and other attributes defined here:
-
IGNORE_NAMES = ['__extension__']
- -
-Methods inherited from _CppHeader:
-
evaluate_class_stack(self)
Create a Class out of the name stack (but not its parts)
- -
evaluate_method_stack(self)
Create a method out of the name stack
- -
evaluate_property_stack(self)
Create a Property out of the name stack
- -
evaluate_struct_stack(self)
Create a Struct out of the name stack (but not its parts)
- -
evaluate_typedef(self)
- -
evalute_forward_decl(self)
- -
finalize(self)
- -
parse_method_type(self, stack)
- -
-Methods inherited from Resolver:
-
concrete_typedef(self, key)
- -
cur_namespace(self, add_double_colon=False)
- -
current_namespace(self)
- -
finalize_vars(self)
- -
guess_ctypes_type(self, string)
- -
initextra(self)
- -
resolve_type(self, string, result)
keeps track of useful things like: how many pointers, number of typedefs, is fundamental or a class, etc...
- -
-Data descriptors inherited from Resolver:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-
-Data and other attributes inherited from Resolver:
-
CLASSES = {}
- -
C_FUNDAMENTAL = ['size_t', 'unsigned', 'signed', 'bool', 'char', 'wchar', 'short', 'int', 'float', 'double', 'long', 'void', 'struct', 'union', 'enum']
- -
NAMESPACES = []
- -
STRUCTS = {}
- -
SubTypedefs = {}
- -

- - - - - - - -
 
-class CppMethod(_CppMethod)
   Takes a name stack and turns it into a method

-Contains the following Keys:
-self['rtnType'] - Return type of the method (ex. "int")
-self['name'] - Name of the method (ex. "getSize")
-self['doxygen'] - Doxygen comments associated with the method if they exist
-self['parameters'] - List of CppVariables
 
 
Method resolution order:
-
CppMethod
-
_CppMethod
-
__builtin__.dict
-
__builtin__.object
-
-
-Methods defined here:
-
__init__(self, nameStack, curClass, methinfo, curTemplate)
- -
__str__(self)
- -
show(self)
- -
-Data descriptors inherited from _CppMethod:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-
-Methods inherited from __builtin__.dict:
-
__cmp__(...)
x.__cmp__(y) <==> cmp(x,y)
- -
__contains__(...)
D.__contains__(k) -> True if D has a key k, else False
- -
__delitem__(...)
x.__delitem__(y) <==> del x[y]
- -
__eq__(...)
x.__eq__(y) <==> x==y
- -
__ge__(...)
x.__ge__(y) <==> x>=y
- -
__getattribute__(...)
x.__getattribute__('name') <==> x.name
- -
__getitem__(...)
x.__getitem__(y) <==> x[y]
- -
__gt__(...)
x.__gt__(y) <==> x>y
- -
__iter__(...)
x.__iter__() <==> iter(x)
- -
__le__(...)
x.__le__(y) <==> x<=y
- -
__len__(...)
x.__len__() <==> len(x)
- -
__lt__(...)
x.__lt__(y) <==> x<y
- -
__ne__(...)
x.__ne__(y) <==> x!=y
- -
__repr__(...)
x.__repr__() <==> repr(x)
- -
__setitem__(...)
x.__setitem__(i, y) <==> x[i]=y
- -
__sizeof__(...)
D.__sizeof__() -> size of D in memory, in bytes
- -
clear(...)
D.clear() -> None.  Remove all items from D.
- -
copy(...)
D.copy() -> a shallow copy of D
- -
fromkeys(...)
dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.
-v defaults to None.
- -
get(...)
D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
- -
has_key(...)
D.has_key(k) -> True if D has a key k, else False
- -
items(...)
D.items() -> list of D's (key, value) pairs, as 2-tuples
- -
iteritems(...)
D.iteritems() -> an iterator over the (key, value) items of D
- -
iterkeys(...)
D.iterkeys() -> an iterator over the keys of D
- -
itervalues(...)
D.itervalues() -> an iterator over the values of D
- -
keys(...)
D.keys() -> list of D's keys
- -
pop(...)
D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
-If key is not found, d is returned if given, otherwise KeyError is raised
- -
popitem(...)
D.popitem() -> (k, v), remove and return some (key, value) pair as a
-2-tuple; but raise KeyError if D is empty.
- -
setdefault(...)
D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
- -
update(...)
D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
-If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
-If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
-In either case, this is followed by: for k in F: D[k] = F[k]
- -
values(...)
D.values() -> list of D's values
- -
viewitems(...)
D.viewitems() -> a set-like object providing a view on D's items
- -
viewkeys(...)
D.viewkeys() -> a set-like object providing a view on D's keys
- -
viewvalues(...)
D.viewvalues() -> an object providing a view on D's values
- -
-Data and other attributes inherited from __builtin__.dict:
-
__hash__ = None
- -
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T
- -

- - - - - -
 
-class CppParseError(exceptions.Exception)
    
Method resolution order:
-
CppParseError
-
exceptions.Exception
-
exceptions.BaseException
-
__builtin__.object
-
-
-Data descriptors defined here:
-
__weakref__
-
list of weak references to the object (if defined)
-
-
-Methods inherited from exceptions.Exception:
-
__init__(...)
x.__init__(...) initializes x; see help(type(x)) for signature
- -
-Data and other attributes inherited from exceptions.Exception:
-
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T
- -
-Methods inherited from exceptions.BaseException:
-
__delattr__(...)
x.__delattr__('name') <==> del x.name
- -
__getattribute__(...)
x.__getattribute__('name') <==> x.name
- -
__getitem__(...)
x.__getitem__(y) <==> x[y]
- -
__getslice__(...)
x.__getslice__(i, j) <==> x[i:j]

-Use of negative indices is not supported.
- -
__reduce__(...)
- -
__repr__(...)
x.__repr__() <==> repr(x)
- -
__setattr__(...)
x.__setattr__('name', value) <==> x.name = value
- -
__setstate__(...)
- -
__str__(...)
x.__str__() <==> str(x)
- -
__unicode__(...)
- -
-Data descriptors inherited from exceptions.BaseException:
-
__dict__
-
-
args
-
-
message
-
-

- - - - - -
 
-class CppStruct(__builtin__.dict)
    
Method resolution order:
-
CppStruct
-
__builtin__.dict
-
__builtin__.object
-
-
-Methods defined here:
-
__init__(self, nameStack)
- -
-Data descriptors defined here:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-
-Data and other attributes defined here:
-
Structs = []
- -
-Methods inherited from __builtin__.dict:
-
__cmp__(...)
x.__cmp__(y) <==> cmp(x,y)
- -
__contains__(...)
D.__contains__(k) -> True if D has a key k, else False
- -
__delitem__(...)
x.__delitem__(y) <==> del x[y]
- -
__eq__(...)
x.__eq__(y) <==> x==y
- -
__ge__(...)
x.__ge__(y) <==> x>=y
- -
__getattribute__(...)
x.__getattribute__('name') <==> x.name
- -
__getitem__(...)
x.__getitem__(y) <==> x[y]
- -
__gt__(...)
x.__gt__(y) <==> x>y
- -
__iter__(...)
x.__iter__() <==> iter(x)
- -
__le__(...)
x.__le__(y) <==> x<=y
- -
__len__(...)
x.__len__() <==> len(x)
- -
__lt__(...)
x.__lt__(y) <==> x<y
- -
__ne__(...)
x.__ne__(y) <==> x!=y
- -
__repr__(...)
x.__repr__() <==> repr(x)
- -
__setitem__(...)
x.__setitem__(i, y) <==> x[i]=y
- -
__sizeof__(...)
D.__sizeof__() -> size of D in memory, in bytes
- -
clear(...)
D.clear() -> None.  Remove all items from D.
- -
copy(...)
D.copy() -> a shallow copy of D
- -
fromkeys(...)
dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.
-v defaults to None.
- -
get(...)
D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
- -
has_key(...)
D.has_key(k) -> True if D has a key k, else False
- -
items(...)
D.items() -> list of D's (key, value) pairs, as 2-tuples
- -
iteritems(...)
D.iteritems() -> an iterator over the (key, value) items of D
- -
iterkeys(...)
D.iterkeys() -> an iterator over the keys of D
- -
itervalues(...)
D.itervalues() -> an iterator over the values of D
- -
keys(...)
D.keys() -> list of D's keys
- -
pop(...)
D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
-If key is not found, d is returned if given, otherwise KeyError is raised
- -
popitem(...)
D.popitem() -> (k, v), remove and return some (key, value) pair as a
-2-tuple; but raise KeyError if D is empty.
- -
setdefault(...)
D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
- -
update(...)
D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
-If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
-If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
-In either case, this is followed by: for k in F: D[k] = F[k]
- -
values(...)
D.values() -> list of D's values
- -
viewitems(...)
D.viewitems() -> a set-like object providing a view on D's items
- -
viewkeys(...)
D.viewkeys() -> a set-like object providing a view on D's keys
- -
viewvalues(...)
D.viewvalues() -> an object providing a view on D's values
- -
-Data and other attributes inherited from __builtin__.dict:
-
__hash__ = None
- -
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T
- -

- - - - - - - -
 
-class CppUnion(CppClass)
   Takes a name stack and turns it into a union

-Contains the following Keys:
-self['name'] - Name of the union
-self['doxygen'] - Doxygen comments associated with the union if they exist
-self['members'] - List of members the union has 

-An example of how this could look is as follows:
-#self =
-{
-    'name': ""
-    'members': []
-}
 
 
Method resolution order:
-
CppUnion
-
CppClass
-
__builtin__.dict
-
__builtin__.object
-
-
-Methods defined here:
-
__init__(self, nameStack)
- -
__str__(self)
Convert class to a string
- -
show(self)
Convert class to a string
- -
transform_to_union_keys(self)
- -
-Methods inherited from CppClass:
-
get_all_method_names(self)
- -
get_all_methods(self)
- -
get_all_pure_virtual_methods(self)
- -
get_method_names(self, type='public')
- -
get_pure_virtual_methods(self, type='public')
- -
-Data descriptors inherited from CppClass:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-
-Methods inherited from __builtin__.dict:
-
__cmp__(...)
x.__cmp__(y) <==> cmp(x,y)
- -
__contains__(...)
D.__contains__(k) -> True if D has a key k, else False
- -
__delitem__(...)
x.__delitem__(y) <==> del x[y]
- -
__eq__(...)
x.__eq__(y) <==> x==y
- -
__ge__(...)
x.__ge__(y) <==> x>=y
- -
__getattribute__(...)
x.__getattribute__('name') <==> x.name
- -
__getitem__(...)
x.__getitem__(y) <==> x[y]
- -
__gt__(...)
x.__gt__(y) <==> x>y
- -
__iter__(...)
x.__iter__() <==> iter(x)
- -
__le__(...)
x.__le__(y) <==> x<=y
- -
__len__(...)
x.__len__() <==> len(x)
- -
__lt__(...)
x.__lt__(y) <==> x<y
- -
__ne__(...)
x.__ne__(y) <==> x!=y
- -
__repr__(...)
x.__repr__() <==> repr(x)
- -
__setitem__(...)
x.__setitem__(i, y) <==> x[i]=y
- -
__sizeof__(...)
D.__sizeof__() -> size of D in memory, in bytes
- -
clear(...)
D.clear() -> None.  Remove all items from D.
- -
copy(...)
D.copy() -> a shallow copy of D
- -
fromkeys(...)
dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.
-v defaults to None.
- -
get(...)
D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
- -
has_key(...)
D.has_key(k) -> True if D has a key k, else False
- -
items(...)
D.items() -> list of D's (key, value) pairs, as 2-tuples
- -
iteritems(...)
D.iteritems() -> an iterator over the (key, value) items of D
- -
iterkeys(...)
D.iterkeys() -> an iterator over the keys of D
- -
itervalues(...)
D.itervalues() -> an iterator over the values of D
- -
keys(...)
D.keys() -> list of D's keys
- -
pop(...)
D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
-If key is not found, d is returned if given, otherwise KeyError is raised
- -
popitem(...)
D.popitem() -> (k, v), remove and return some (key, value) pair as a
-2-tuple; but raise KeyError if D is empty.
- -
setdefault(...)
D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
- -
update(...)
D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
-If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
-If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
-In either case, this is followed by: for k in F: D[k] = F[k]
- -
values(...)
D.values() -> list of D's values
- -
viewitems(...)
D.viewitems() -> a set-like object providing a view on D's items
- -
viewkeys(...)
D.viewkeys() -> a set-like object providing a view on D's keys
- -
viewvalues(...)
D.viewvalues() -> an object providing a view on D's values
- -
-Data and other attributes inherited from __builtin__.dict:
-
__hash__ = None
- -
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T
- -

- - - - - - - -
 
-class CppVariable(_CppVariable)
   Takes a name stack and turns it into a method

-Contains the following Keys:
-self['type'] - Type for the variable (ex. "const string &")
-self['name'] - Name of the variable (ex. "numItems")
-self['namespace'] - Namespace containing the enum
-self['desc'] - Description of the variable if part of a method (optional)
-self['doxygen'] - Doxygen comments associated with the method if they exist
-self['defaultValue'] - Default value of the variable, this key will only
-    exist if there is a default value
-self['extern'] - True if its an extern, false if not
 
 
Method resolution order:
-
CppVariable
-
_CppVariable
-
__builtin__.dict
-
__builtin__.object
-
-
-Methods defined here:
-
__init__(self, nameStack, **kwargs)
- -
__str__(self)
- -
-Data and other attributes defined here:
-
Vars = []
- -
-Methods inherited from _CppVariable:
-
init(self)
- -
-Data descriptors inherited from _CppVariable:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-
-Methods inherited from __builtin__.dict:
-
__cmp__(...)
x.__cmp__(y) <==> cmp(x,y)
- -
__contains__(...)
D.__contains__(k) -> True if D has a key k, else False
- -
__delitem__(...)
x.__delitem__(y) <==> del x[y]
- -
__eq__(...)
x.__eq__(y) <==> x==y
- -
__ge__(...)
x.__ge__(y) <==> x>=y
- -
__getattribute__(...)
x.__getattribute__('name') <==> x.name
- -
__getitem__(...)
x.__getitem__(y) <==> x[y]
- -
__gt__(...)
x.__gt__(y) <==> x>y
- -
__iter__(...)
x.__iter__() <==> iter(x)
- -
__le__(...)
x.__le__(y) <==> x<=y
- -
__len__(...)
x.__len__() <==> len(x)
- -
__lt__(...)
x.__lt__(y) <==> x<y
- -
__ne__(...)
x.__ne__(y) <==> x!=y
- -
__repr__(...)
x.__repr__() <==> repr(x)
- -
__setitem__(...)
x.__setitem__(i, y) <==> x[i]=y
- -
__sizeof__(...)
D.__sizeof__() -> size of D in memory, in bytes
- -
clear(...)
D.clear() -> None.  Remove all items from D.
- -
copy(...)
D.copy() -> a shallow copy of D
- -
fromkeys(...)
dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.
-v defaults to None.
- -
get(...)
D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
- -
has_key(...)
D.has_key(k) -> True if D has a key k, else False
- -
items(...)
D.items() -> list of D's (key, value) pairs, as 2-tuples
- -
iteritems(...)
D.iteritems() -> an iterator over the (key, value) items of D
- -
iterkeys(...)
D.iterkeys() -> an iterator over the keys of D
- -
itervalues(...)
D.itervalues() -> an iterator over the values of D
- -
keys(...)
D.keys() -> list of D's keys
- -
pop(...)
D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
-If key is not found, d is returned if given, otherwise KeyError is raised
- -
popitem(...)
D.popitem() -> (k, v), remove and return some (key, value) pair as a
-2-tuple; but raise KeyError if D is empty.
- -
setdefault(...)
D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
- -
update(...)
D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
-If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
-If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
-In either case, this is followed by: for k in F: D[k] = F[k]
- -
values(...)
D.values() -> list of D's values
- -
viewitems(...)
D.viewitems() -> a set-like object providing a view on D's items
- -
viewkeys(...)
D.viewkeys() -> a set-like object providing a view on D's keys
- -
viewvalues(...)
D.viewvalues() -> an object providing a view on D's values
- -
-Data and other attributes inherited from __builtin__.dict:
-
__hash__ = None
- -
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T
- -

- - - - - -
 
-class Resolver(__builtin__.object)
    Methods defined here:
-
concrete_typedef(self, key)
- -
cur_namespace(self, add_double_colon=False)
- -
current_namespace(self)
- -
finalize_vars(self)
- -
guess_ctypes_type(self, string)
- -
initextra(self)
- -
resolve_type(self, string, result)
keeps track of useful things like: how many pointers, number of typedefs, is fundamental or a class, etc...
- -
-Data descriptors defined here:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-
-Data and other attributes defined here:
-
CLASSES = {}
- -
C_FUNDAMENTAL = ['size_t', 'unsigned', 'signed', 'bool', 'char', 'wchar', 'short', 'int', 'float', 'double', 'long', 'void', 'struct', 'union', 'enum']
- -
NAMESPACES = []
- -
STRUCTS = {}
- -
SubTypedefs = {}
- -

- - - - - - - -
 
-class TagStr(__builtin__.str)
   Wrapper for a string that allows us to store the line number associated with it
 
 
Method resolution order:
-
TagStr
-
__builtin__.str
-
__builtin__.basestring
-
__builtin__.object
-
-
-Methods defined here:
-
__del__(self)
- -
lineno(self)
- -
-Static methods defined here:
-
__new__(cls, *args, **kw)
- -
-Data descriptors defined here:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
-Data and other attributes defined here:
-
lineno_reg = {}
- -
-Methods inherited from __builtin__.str:
-
__add__(...)
x.__add__(y) <==> x+y
- -
__contains__(...)
x.__contains__(y) <==> y in x
- -
__eq__(...)
x.__eq__(y) <==> x==y
- -
__format__(...)
S.__format__(format_spec) -> string

-Return a formatted version of S as described by format_spec.
- -
__ge__(...)
x.__ge__(y) <==> x>=y
- -
__getattribute__(...)
x.__getattribute__('name') <==> x.name
- -
__getitem__(...)
x.__getitem__(y) <==> x[y]
- -
__getnewargs__(...)
- -
__getslice__(...)
x.__getslice__(i, j) <==> x[i:j]

-Use of negative indices is not supported.
- -
__gt__(...)
x.__gt__(y) <==> x>y
- -
__hash__(...)
x.__hash__() <==> hash(x)
- -
__le__(...)
x.__le__(y) <==> x<=y
- -
__len__(...)
x.__len__() <==> len(x)
- -
__lt__(...)
x.__lt__(y) <==> x<y
- -
__mod__(...)
x.__mod__(y) <==> x%y
- -
__mul__(...)
x.__mul__(n) <==> x*n
- -
__ne__(...)
x.__ne__(y) <==> x!=y
- -
__repr__(...)
x.__repr__() <==> repr(x)
- -
__rmod__(...)
x.__rmod__(y) <==> y%x
- -
__rmul__(...)
x.__rmul__(n) <==> n*x
- -
__sizeof__(...)
S.__sizeof__() -> size of S in memory, in bytes
- -
__str__(...)
x.__str__() <==> str(x)
- -
capitalize(...)
S.capitalize() -> string

-Return a copy of the string S with only its first character
-capitalized.
- -
center(...)
S.center(width[, fillchar]) -> string

-Return S centered in a string of length width. Padding is
-done using the specified fill character (default is a space)
- -
count(...)
S.count(sub[, start[, end]]) -> int

-Return the number of non-overlapping occurrences of substring sub in
-string S[start:end].  Optional arguments start and end are interpreted
-as in slice notation.
- -
decode(...)
S.decode([encoding[,errors]]) -> object

-Decodes S using the codec registered for encoding. encoding defaults
-to the default encoding. errors may be given to set a different error
-handling scheme. Default is 'strict' meaning that encoding errors raise
-a UnicodeDecodeError. Other possible values are 'ignore' and 'replace'
-as well as any other name registered with codecs.register_error that is
-able to handle UnicodeDecodeErrors.
- -
encode(...)
S.encode([encoding[,errors]]) -> object

-Encodes S using the codec registered for encoding. encoding defaults
-to the default encoding. errors may be given to set a different error
-handling scheme. Default is 'strict' meaning that encoding errors raise
-a UnicodeEncodeError. Other possible values are 'ignore', 'replace' and
-'xmlcharrefreplace' as well as any other name registered with
-codecs.register_error that is able to handle UnicodeEncodeErrors.
- -
endswith(...)
S.endswith(suffix[, start[, end]]) -> bool

-Return True if S ends with the specified suffix, False otherwise.
-With optional start, test S beginning at that position.
-With optional end, stop comparing S at that position.
-suffix can also be a tuple of strings to try.
- -
expandtabs(...)
S.expandtabs([tabsize]) -> string

-Return a copy of S where all tab characters are expanded using spaces.
-If tabsize is not given, a tab size of 8 characters is assumed.
- -
find(...)
S.find(sub [,start [,end]]) -> int

-Return the lowest index in S where substring sub is found,
-such that sub is contained within S[start:end].  Optional
-arguments start and end are interpreted as in slice notation.

-Return -1 on failure.
- -
format(...)
S.format(*args, **kwargs) -> string

-Return a formatted version of S, using substitutions from args and kwargs.
-The substitutions are identified by braces ('{' and '}').
- -
index(...)
S.index(sub [,start [,end]]) -> int

-Like S.find() but raise ValueError when the substring is not found.
- -
isalnum(...)
S.isalnum() -> bool

-Return True if all characters in S are alphanumeric
-and there is at least one character in S, False otherwise.
- -
isalpha(...)
S.isalpha() -> bool

-Return True if all characters in S are alphabetic
-and there is at least one character in S, False otherwise.
- -
isdigit(...)
S.isdigit() -> bool

-Return True if all characters in S are digits
-and there is at least one character in S, False otherwise.
- -
islower(...)
S.islower() -> bool

-Return True if all cased characters in S are lowercase and there is
-at least one cased character in S, False otherwise.
- -
isspace(...)
S.isspace() -> bool

-Return True if all characters in S are whitespace
-and there is at least one character in S, False otherwise.
- -
istitle(...)
S.istitle() -> bool

-Return True if S is a titlecased string and there is at least one
-character in S, i.e. uppercase characters may only follow uncased
-characters and lowercase characters only cased ones. Return False
-otherwise.
- -
isupper(...)
S.isupper() -> bool

-Return True if all cased characters in S are uppercase and there is
-at least one cased character in S, False otherwise.
- -
join(...)
S.join(iterable) -> string

-Return a string which is the concatenation of the strings in the
-iterable.  The separator between elements is S.
- -
ljust(...)
S.ljust(width[, fillchar]) -> string

-Return S left-justified in a string of length width. Padding is
-done using the specified fill character (default is a space).
- -
lower(...)
S.lower() -> string

-Return a copy of the string S converted to lowercase.
- -
lstrip(...)
S.lstrip([chars]) -> string or unicode

-Return a copy of the string S with leading whitespace removed.
-If chars is given and not None, remove characters in chars instead.
-If chars is unicode, S will be converted to unicode before stripping
- -
partition(...)
S.partition(sep) -> (head, sep, tail)

-Search for the separator sep in S, and return the part before it,
-the separator itself, and the part after it.  If the separator is not
-found, return S and two empty strings.
- -
replace(...)
S.replace(old, new[, count]) -> string

-Return a copy of string S with all occurrences of substring
-old replaced by new.  If the optional argument count is
-given, only the first count occurrences are replaced.
- -
rfind(...)
S.rfind(sub [,start [,end]]) -> int

-Return the highest index in S where substring sub is found,
-such that sub is contained within S[start:end].  Optional
-arguments start and end are interpreted as in slice notation.

-Return -1 on failure.
- -
rindex(...)
S.rindex(sub [,start [,end]]) -> int

-Like S.rfind() but raise ValueError when the substring is not found.
- -
rjust(...)
S.rjust(width[, fillchar]) -> string

-Return S right-justified in a string of length width. Padding is
-done using the specified fill character (default is a space)
- -
rpartition(...)
S.rpartition(sep) -> (head, sep, tail)

-Search for the separator sep in S, starting at the end of S, and return
-the part before it, the separator itself, and the part after it.  If the
-separator is not found, return two empty strings and S.
- -
rsplit(...)
S.rsplit([sep [,maxsplit]]) -> list of strings

-Return a list of the words in the string S, using sep as the
-delimiter string, starting at the end of the string and working
-to the front.  If maxsplit is given, at most maxsplit splits are
-done. If sep is not specified or is None, any whitespace string
-is a separator.
- -
rstrip(...)
S.rstrip([chars]) -> string or unicode

-Return a copy of the string S with trailing whitespace removed.
-If chars is given and not None, remove characters in chars instead.
-If chars is unicode, S will be converted to unicode before stripping
- -
split(...)
S.split([sep [,maxsplit]]) -> list of strings

-Return a list of the words in the string S, using sep as the
-delimiter string.  If maxsplit is given, at most maxsplit
-splits are done. If sep is not specified or is None, any
-whitespace string is a separator and empty strings are removed
-from the result.
- -
splitlines(...)
S.splitlines(keepends=False) -> list of strings

-Return a list of the lines in S, breaking at line boundaries.
-Line breaks are not included in the resulting list unless keepends
-is given and true.
- -
startswith(...)
S.startswith(prefix[, start[, end]]) -> bool

-Return True if S starts with the specified prefix, False otherwise.
-With optional start, test S beginning at that position.
-With optional end, stop comparing S at that position.
-prefix can also be a tuple of strings to try.
- -
strip(...)
S.strip([chars]) -> string or unicode

-Return a copy of the string S with leading and trailing
-whitespace removed.
-If chars is given and not None, remove characters in chars instead.
-If chars is unicode, S will be converted to unicode before stripping
- -
swapcase(...)
S.swapcase() -> string

-Return a copy of the string S with uppercase characters
-converted to lowercase and vice versa.
- -
title(...)
S.title() -> string

-Return a titlecased version of S, i.e. words start with uppercase
-characters, all remaining cased characters have lowercase.
- -
translate(...)
S.translate(table [,deletechars]) -> string

-Return a copy of the string S, where all characters occurring
-in the optional argument deletechars are removed, and the
-remaining characters have been mapped through the given
-translation table, which must be a string of length 256 or None.
-If the table argument is None, no translation is applied and
-the operation simply removes the characters in deletechars.
- -
upper(...)
S.upper() -> string

-Return a copy of the string S converted to uppercase.
- -
zfill(...)
S.zfill(width) -> string

-Pad a numeric string S with zeros on the left, to fill a field
-of the specified width.  The string S is never truncated.
- -

- - - - - -
 
-Functions
       
debug_print(arg)
-
detect_lineno(s)
Detect the line number for a given token string
-
error_print(arg)
-
filter_out_attribute_keyword(stack)
Strips __attribute__ and its parenthetical expression from the stack
-
is_enum_namestack(nameStack)
Determines if a namestack is an enum namestack
-
is_function_pointer_stack(stack)
Count how many non-nested paranthesis are in the stack.  Useful for determining if a stack is a function pointer
-
is_fundamental(s)
-
is_method_namestack(stack)
-
is_namespace(nameStack)
Determines if a namespace is being specified
-
is_property_namestack(nameStack)
-
lineno()
Returns the current line number in our program.
-
standardize_fundamental(s)
-
t_COMMENT_MULTILINE(t)
/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/
-
t_COMMENT_SINGLELINE(t)
\/\/.*\n
-
t_NEWLINE(t)
\n+
-
t_error(v)
-
trace_print(*arg)
-
warning_print(arg)
-

- - - - - -
 
-Data
       C99_NONSTANDARD = {'int16': 'short int', 'int32': 'int', 'int64': 'int64_t', 'int8': 'signed char', 'uint': 'unsigned int', 'uint16': 'unsigned short int', 'uint32': 'unsigned int', 'uint64': 'uint64_t', 'uint8': 'unsigned char'}
-__version__ = '2.7.4'
-debug = 0
-debug_trace = 0
-doxygenCommentCache = ''
-ignoreSymbols = ['Q_OBJECT']
-parseHistory = []
-print_errors = 1
-print_warnings = 1
-supportedAccessSpecifier = ['public', 'protected', 'private']
-t_AMPERSTAND = '&'
-t_ASTERISK = r'\*'
-t_BACKSLASH = r'\\'
-t_CARET = r'\^'
-t_CHAR_LITERAL = "'.'"
-t_CLOSE_BRACE = '}'
-t_CLOSE_PAREN = r'\)'
-t_CLOSE_SQUARE_BRACKET = r'\]'
-t_COLON = ':'
-t_COMMA = ','
-t_DIVIDE = '/(?!/)'
-t_EQUALS = '='
-t_EXCLAMATION = '!'
-t_FLOAT_NUMBER = r'[-+]?[0-9]*\.[0-9]+([eE][-+]?[0-9]+)?'
-t_MINUS = r'\-'
-t_NAME = '[<>A-Za-z_~][A-Za-z0-9_]*'
-t_NUMBER = '[0-9][0-9XxA-Fa-f]*'
-t_OPEN_BRACE = '{'
-t_OPEN_PAREN = r'\('
-t_OPEN_SQUARE_BRACKET = r'\['
-t_PERCENT = '%'
-t_PIPE = r'\|'
-t_PLUS = r'\+'
-t_PRECOMP_MACRO = r'\#.*'
-t_PRECOMP_MACRO_CONT = r'.*\\\n'
-t_SEMI_COLON = ';'
-t_SQUOTE = "'"
-t_STRING_LITERAL = r'"([^"\\]|\\.)*"'
-t_TAB = r'\t'
-t_TEMPLATE_NAME = 'CppHeaderParser_template_[0-9]+'
-t_ignore = ' \r.?@\x0c'
-tokens = ['NUMBER', 'FLOAT_NUMBER', 'TEMPLATE_NAME', 'NAME', 'OPEN_PAREN', 'CLOSE_PAREN', 'OPEN_BRACE', 'CLOSE_BRACE', 'OPEN_SQUARE_BRACKET', 'CLOSE_SQUARE_BRACKET', 'COLON', 'SEMI_COLON', 'COMMA', 'TAB', 'BACKSLASH', 'PIPE', 'PERCENT', 'EXCLAMATION', 'CARET', 'COMMENT_SINGLELINE', ...]
-version = '2.7.4'
- \ No newline at end of file diff --git a/CppHeaderParser/doxygen.py b/CppHeaderParser/doxygen.py new file mode 100644 index 0000000..cac2b35 --- /dev/null +++ b/CppHeaderParser/doxygen.py @@ -0,0 +1,32 @@ +def extract_doxygen_method_params(doxystr): + """ + Given a doxygen string for a method, extract parameter descriptions + """ + doxyVarDesc = {} + doxyLines = doxystr.split("\n") + lastParamDesc = "" + for doxyLine in doxyLines: + if " @param " in doxyLine or " \\param " in doxyLine: + try: + # Strip out the param + doxyLine = doxyLine[doxyLine.find("param ") + 6 :] + (var, desc) = doxyLine.split(" ", 1) + doxyVarDesc[var] = desc.strip() + lastParamDesc = var + except: + pass + elif " @return " in doxyLine or " \return " in doxyLine: + lastParamDesc = "" + # not handled for now + elif lastParamDesc: + try: + doxyLine = doxyLine.strip() + if " " not in doxyLine: + lastParamDesc = "" + continue + doxyLine = doxyLine[doxyLine.find(" ") + 1 :] + doxyVarDesc[lastParamDesc] += " " + doxyLine + except: + pass + + return doxyVarDesc diff --git a/CppHeaderParser/lexer.py b/CppHeaderParser/lexer.py new file mode 100644 index 0000000..b63501f --- /dev/null +++ b/CppHeaderParser/lexer.py @@ -0,0 +1,232 @@ +from collections import deque +import ply.lex as lex +import re + +_line_re = re.compile(r'^#line (\d+) "(.*)"') + + +class Lexer(object): + tokens = [ + "NUMBER", + "FLOAT_NUMBER", + "NAME", + "COMMENT_SINGLELINE", + "COMMENT_MULTILINE", + "PRECOMP_MACRO", + "PRECOMP_MACRO_CONT", + "DIVIDE", + "CHAR_LITERAL", + "STRING_LITERAL", + "NEWLINE", + "ELLIPSIS", + "DBL_LBRACKET", + "DBL_RBRACKET", + "DBL_COLON", + "SHIFT_LEFT", + ] + + literals = [ + "<", + ">", + "(", + ")", + "{", + "}", + "[", + "]", + ";", + ":", + ",", + "\\", + "|", + "%", + "^", + "!", + "*", + "-", + "+", + "&", + "=", + "'", + ".", + ] + + t_ignore = " \t\r?@\f" + t_NUMBER = r"[0-9][0-9XxA-Fa-f]*" + t_FLOAT_NUMBER = r"[-+]?[0-9]*\.[0-9]+([eE][-+]?[0-9]+)?" + t_NAME = r"[A-Za-z_~][A-Za-z0-9_]*" + + def t_PRECOMP_MACRO(self, t): + r"\#.*" + m = _line_re.match(t.value) + if m: + filename = m.group(2) + if filename not in self._filenames_set: + self.filenames.append(filename) + self._filenames_set.add(filename) + self.filename = filename + + self.line_offset = 1 + self.lex.lineno - int(m.group(1)) + + else: + return t + + t_PRECOMP_MACRO_CONT = r".*\\\n" + + def t_COMMENT_SINGLELINE(self, t): + r"\/\/.*\n?" + if t.value.startswith("///") or t.value.startswith("//!"): + self.comments.append(t.value.lstrip("\t ").rstrip("\n")) + t.lexer.lineno += t.value.count("\n") + return t + + t_DIVIDE = r"/(?!/)" + t_CHAR_LITERAL = "'.'" + t_ELLIPSIS = r"\.\.\." + t_DBL_LBRACKET = r"\[\[" + t_DBL_RBRACKET = r"\]\]" + t_DBL_COLON = r"::" + t_SHIFT_LEFT = r"<<" + # SHIFT_RIGHT introduces ambiguity + + # found at http://wordaligned.org/articles/string-literals-and-regular-expressions + # TODO: This does not work with the string "bla \" bla" + t_STRING_LITERAL = r'"([^"\\]|\\.)*"' + + # Found at http://ostermiller.org/findcomment.html + def t_COMMENT_MULTILINE(self, t): + r"/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/\n?" + if t.value.startswith("/**") or t.value.startswith("/*!"): + # not sure why, but get double new lines + v = t.value.replace("\n\n", "\n") + # strip prefixing whitespace + v = re.sub("\n[\\s]+\\*", "\n*", v) + self.comments = v.splitlines() + t.lexer.lineno += t.value.count("\n") + return t + + def t_NEWLINE(self, t): + r"\n+" + t.lexer.lineno += len(t.value) + del self.comments[:] + return t + + def t_error(self, v): + print("Lex error: ", v) + + def __init__(self, filename): + self.lex = lex.lex(module=self) + self.input = self.lex.input + + # For tracking current file/line position + self.filename = filename + self.line_offset = 0 + + self.filenames = [] + self._filenames_set = set() + + if self.filename: + self.filenames.append(filename) + self._filenames_set.add(filename) + + # Doxygen comments + self.comments = [] + + self.lookahead = deque() + + def current_location(self): + if self.lookahead: + return self.lookahead[0].location + return self.filename, self.lex.lineno - self.line_offset + + def get_doxygen(self): + """ + This should be called after the first element of something has + been consumed. + + It will lookahead for comments that come after the item, if prior + comments don't exist. + """ + + # Assumption: This function is either called at the beginning of a + # statement or at the end of a statement + + if self.comments: + comments = self.comments + else: + comments = [] + # only look for comments until a newline (including lookahead) + for tok in self.lookahead: + if tok.type == "NEWLINE": + return "" + + while True: + tok = self.lex.token() + comments.extend(self.comments) + + if tok is None: + break + + tok.location = (self.filename, tok.lineno - self.line_offset) + ttype = tok.type + if ttype == "NEWLINE": + self.lookahead.append(tok) + break + + if ttype not in self._discard_types: + self.lookahead.append(tok) + + if ttype == "NAME": + break + + del self.comments[:] + + comments = "\n".join(comments) + del self.comments[:] + return comments + + _discard_types = {"NEWLINE", "COMMENT_SINGLELINE", "COMMENT_MULTILINE"} + + def token(self, eof_ok=False): + tok = None + while self.lookahead: + tok = self.lookahead.popleft() + if tok.type not in self._discard_types: + return tok + + while True: + tok = self.lex.token() + if tok is None: + if not eof_ok: + raise EOFError("unexpected end of file") + break + + if tok.type not in self._discard_types: + tok.location = (self.filename, tok.lineno - self.line_offset) + break + + return tok + + def token_if(self, *types): + tok = self.token(eof_ok=True) + if tok is None: + return None + if tok.type not in types: + # put it back on the left in case it was retrieved + # from the lookahead buffer + self.lookahead.appendleft(tok) + return None + return tok + + def return_token(self, tok): + self.lookahead.appendleft(tok) + + def return_tokens(self, toks): + self.lookahead.extendleft(reversed(toks)) + + +if __name__ == "__main__": + try: + lex.runmain(lexer=Lexer(None)) + except EOFError: + pass diff --git a/CppHeaderParser/test/gen_test.py b/CppHeaderParser/test/gen_test.py deleted file mode 100644 index 4ba96a9..0000000 --- a/CppHeaderParser/test/gen_test.py +++ /dev/null @@ -1,153 +0,0 @@ -import sys -sys.path = [".."] + sys.path -import CppHeaderParser - -testScript = "" -testCaseClasses = [] - -def main(): - #init testScript with boiler plate code - global testScript - global testCaseClasses - testScript = """\ -import unittest -from test import test_support -import sys -sys.path = [".."] + sys.path -import CppHeaderParser - -""" - cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - for className, classInstance in cppHeader.classes.items(): - gen_test_cases_for_class(className, classInstance) - - testScript += """\ - - -def test_main(): - test_support.run_unittest( - %s) - -if __name__ == '__main__': - test_main() - -"""%",\n ".join(testCaseClasses) - - print testScript - -def gen_test_cases_for_class(className, classInstance): - for methAccessor in classInstance["methods"].keys(): - idx = 0 - for method in classInstance["methods"][methAccessor]: - gen_test_case_for_method(className, classInstance, methAccessor, idx, method); - idx += 1 - - for propAccessor in classInstance["properties"].keys(): - idx = 0 - for property in classInstance["properties"][propAccessor]: - gen_test_case_for_property(className, classInstance, propAccessor, idx, property); - idx += 1 - - for enumAccessor in classInstance["enums"].keys(): - idx = 0 - for enum in classInstance["enums"][enumAccessor]: - gen_test_case_for_enum(className, classInstance, enumAccessor, idx, enum); - idx += 1 - -def gen_test_case_for_method(className, classInstance, methAccessor, methIndex, method): - global testScript - global testCaseClasses - testCaseClassName = "%s_%s_TestCase"%(className, method["name"]) - testCaseClasses.append(testCaseClassName) - testScript += """\ - - -class %s(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - -"""%testCaseClassName - methString = """self.cppHeader.classes["%s"]["methods"]["%s"][%d]"""%( - className, methAccessor, methIndex) - for key in ["name", "rtnType", "parameters", "doxygen"]: - if key in method.keys(): - gen_test_equals(key, methString + '["%s"]'%key, method[key]) - else: - gen_test_key_not_exist(key, methString) - - - -def gen_test_case_for_property(className, classInstance, propAccessor, propIndex, property): - global testScript - global testCaseClasses - testCaseClassName = "%s_%s_TestCase"%(className, property["name"]) - testCaseClasses.append(testCaseClassName) - testScript += """\ - - -class %s(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - -"""%testCaseClassName - propString = """self.cppHeader.classes["%s"]["properties"]["%s"][%d]"""%( - className, propAccessor, propIndex) - for key in ["name", "type", "doxygen"]: - if key in property.keys(): - gen_test_equals(key, propString + '["%s"]'%key, property[key]) - else: - gen_test_key_not_exist(key, propString) - - - - -def gen_test_case_for_enum(className, classInstance, enumAccessor, enumIndex, enum): - global testScript - global testCaseClasses - testCaseClassName = "%s_%s_TestCase"%(className, enum["name"]) - testCaseClasses.append(testCaseClassName) - testScript += """\ - - -class %s(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - -"""%testCaseClassName - enumString = """self.cppHeader.classes["%s"]["enums"]["%s"][%d]"""%( - className, enumAccessor, enumIndex) - for key in ["name", "namespace", "doxygen", "values"]: - if key in enum.keys(): - gen_test_equals(key, enumString + '["%s"]'%key, enum[key]) - else: - gen_test_key_not_exist(key, enumString) - - - -def gen_test_equals(name, v1, v2): - global testScript - testScript += """\ - def test_%s(self): - self.assertEqual( - %s, - %s) - -"""%(name.lower(), v1, repr(v2)) - -def gen_test_key_not_exist(key, testObj): - global testScript - testScript += """\ - def test_%s(self): - self.assertTrue( - "%s" - not in %s.keys()) - -"""%(key.lower(), key, testObj) - -if __name__ == "__main__": - main() - - diff --git a/CppHeaderParser/test/test_CppHeaderParser.py b/CppHeaderParser/test/test_CppHeaderParser.py deleted file mode 100644 index f5ba080..0000000 --- a/CppHeaderParser/test/test_CppHeaderParser.py +++ /dev/null @@ -1,1766 +0,0 @@ -# -*- coding: utf-8 -*- -import unittest -import sys -if sys.version_info[0] == 2: - sys.path = [".."] + sys.path - import CppHeaderParser as CppHeaderParser -else: - sys.path = ["..", "../python3-libs"] + sys.path - import CppHeaderParser3 as CppHeaderParser - -def filter_pameters(p): - "Reduce a list of dictionaries to the desired keys for function parameter testing" - rtn = [] - for d in p: - rtn.append({'name': d['name'], 'desc': d['desc'], 'type': d['type']}) - return rtn - -def filter_dict_keys(d, keys): - "Filter a dictonary to a specified set of keys" - rtn = {} - for k in keys: - rtn[k] = d.get(k, None) - return rtn - -class SampleClass_SampleClass_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["methods"]["public"][0]["name"], - 'SampleClass') - - def test_rtntype(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["methods"]["public"][0]["rtnType"], - 'void') - - def test_parameters(self): - self.assertEqual( - filter_pameters(self.cppHeader.classes["SampleClass"]["methods"]["public"][0]["parameters"]), - []) - - def test_doxygen(self): - self.assertTrue( - "doxygen" - not in self.cppHeader.classes["SampleClass"]["methods"]["public"][0].keys()) - - - -class SampleClass_meth1_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["methods"]["public"][1]["name"], - 'meth1') - - def test_rtntype(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["methods"]["public"][1]["rtnType"], - 'string') - - def test_parameters(self): - self.assertEqual( - filter_pameters(self.cppHeader.classes["SampleClass"]["methods"]["public"][1]["parameters"]), - []) - - def test_doxygen(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["methods"]["public"][1]["doxygen"], - '/*!\n* Method 1\n*/') - - - -class SampleClass_meth2_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["methods"]["public"][2]["name"], - 'meth2') - - def test_rtntype(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["methods"]["public"][2]["rtnType"], - 'int') - - def test_parameters(self): - self.assertEqual( - filter_pameters(self.cppHeader.classes["SampleClass"]["methods"]["public"][2]["parameters"]), - [{'type': 'int', 'name': 'v1', 'desc': 'Variable 1'}]) - - def test_doxygen(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["methods"]["public"][2]["doxygen"], - '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///') - - - -class SampleClass_meth3_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["methods"]["public"][3]["name"], - 'meth3') - - def test_rtntype(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["methods"]["public"][3]["rtnType"], - 'void') - - def test_parameters(self): - self.assertEqual( - filter_pameters(self.cppHeader.classes["SampleClass"]["methods"]["public"][3]["parameters"]), - [{'type': 'const string &', 'name': 'v1', 'desc': 'Variable 1 with a really long wrapping description'}, {'type': 'vector &', 'name': 'v2', 'desc': 'Variable 2'}]) - - def test_doxygen(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["methods"]["public"][3]["doxygen"], - '/**\n* Method 3 description\n*\n* \\param v1 Variable 1 with a really long\n* wrapping description\n* \\param v2 Variable 2\n*/') - - - -class SampleClass_meth4_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["methods"]["public"][4]["name"], - 'meth4') - - def test_rtntype(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["methods"]["public"][4]["rtnType"], - 'unsigned int') - - def test_parameters(self): - self.assertEqual( - filter_pameters(self.cppHeader.classes["SampleClass"]["methods"]["public"][4]["parameters"]), - []) - - def test_doxygen(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["methods"]["public"][4]["doxygen"], - '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/') - - - -class SampleClass_meth5_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["methods"]["private"][0]["name"], - 'meth5') - - def test_rtntype(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["methods"]["private"][0]["rtnType"], - 'void *') - - def test_parameters(self): - self.assertEqual( - filter_pameters(self.cppHeader.classes["SampleClass"]["methods"]["private"][0]["parameters"]), - []) - - def test_doxygen(self): - self.assertTrue( - "doxygen" - not in self.cppHeader.classes["SampleClass"]["methods"]["private"][0].keys()) - - - -class SampleClass_prop1_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["properties"]["private"][0]["name"], - 'prop1') - - def test_type(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["properties"]["private"][0]["type"], - 'string') - - def test_doxygen(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["properties"]["private"][0]["doxygen"], - '/// prop1 description') - - - -class SampleClass_prop5_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["properties"]["private"][1]["name"], - 'prop5') - - def test_type(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["properties"]["private"][1]["type"], - 'int') - - def test_doxygen(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["properties"]["private"][1]["doxygen"], - '//! prop5 description') - - - -class SampleClass_Elephant_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["enums"]["public"][0]["name"], - 'Elephant') - - def test_namespace(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["enums"]["public"][0]["namespace"], - '') - - def test_doxygen(self): - self.assertTrue( - "doxygen" - not in self.cppHeader.classes["SampleClass"]["enums"]["public"][0].keys()) - - def test_values(self): - self.assertEqual( - self.cppHeader.classes["SampleClass"]["enums"]["public"][0]["values"], - [{'name': 'EL_ONE', 'value': 1}, {'name': 'EL_TWO', 'value': 2}, {'name': 'EL_NINE', 'value': 9}, {'name': 'EL_TEN', 'value': 10}]) - - - -class AlphaClass_AlphaClass_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["AlphaClass"]["methods"]["public"][0]["name"], - 'AlphaClass') - - def test_rtntype(self): - self.assertEqual( - self.cppHeader.classes["AlphaClass"]["methods"]["public"][0]["rtnType"], - 'void') - - def test_parameters(self): - self.assertEqual( - filter_pameters(self.cppHeader.classes["AlphaClass"]["methods"]["public"][0]["parameters"]), - []) - - def test_doxygen(self): - self.assertTrue( - "doxygen" - not in self.cppHeader.classes["AlphaClass"]["methods"]["public"][0].keys()) - - - -class AlphaClass_alphaMethod_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["AlphaClass"]["methods"]["public"][1]["name"], - 'alphaMethod') - - def test_rtntype(self): - self.assertEqual( - self.cppHeader.classes["AlphaClass"]["methods"]["public"][1]["rtnType"], - 'void') - - def test_parameters(self): - self.assertEqual( - filter_pameters(self.cppHeader.classes["AlphaClass"]["methods"]["public"][1]["parameters"]), - []) - - def test_doxygen(self): - self.assertTrue( - "doxygen" - not in self.cppHeader.classes["AlphaClass"]["methods"]["public"][1].keys()) - - - -class AlphaClass_alphaString_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["AlphaClass"]["properties"]["public"][0]["name"], - 'alphaString') - - def test_type(self): - self.assertEqual( - self.cppHeader.classes["AlphaClass"]["properties"]["public"][0]["type"], - 'string') - - def test_doxygen(self): - self.assertTrue( - "doxygen" - not in self.cppHeader.classes["AlphaClass"]["properties"]["public"][0].keys()) - - - -class AlphaClass_Zebra_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["AlphaClass"]["enums"]["protected"][0]["name"], - 'Zebra') - - def test_namespace(self): - self.assertEqual( - self.cppHeader.classes["AlphaClass"]["enums"]["protected"][0]["namespace"], - 'Alpha') - - def test_doxygen(self): - self.assertTrue( - "doxygen" - not in self.cppHeader.classes["AlphaClass"]["enums"]["protected"][0].keys()) - - def test_values(self): - self.assertEqual( - self.cppHeader.classes["AlphaClass"]["enums"]["protected"][0]["values"], - [{'name': 'Z_A', 'value': 0}, - {'name': 'Z_B', 'raw_value': '0x2B', 'value': 43}, - {'name': 'Z_C', 'raw_value': 'j', 'value': 106}, - {'name': 'Z_D', 'value': 107}]) - - - -class OmegaClass_OmegaClass_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["OmegaClass"]["methods"]["public"][0]["name"], - 'OmegaClass') - - def test_rtntype(self): - self.assertEqual( - self.cppHeader.classes["OmegaClass"]["methods"]["public"][0]["rtnType"], - 'void') - - def test_parameters(self): - self.assertEqual( - filter_pameters(self.cppHeader.classes["OmegaClass"]["methods"]["public"][0]["parameters"]), - []) - - def test_doxygen(self): - self.assertTrue( - "doxygen" - not in self.cppHeader.classes["OmegaClass"]["methods"]["public"][0].keys()) - - - -class OmegaClass_omegaString_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["OmegaClass"]["properties"]["public"][0]["name"], - 'omegaString') - - def test_type(self): - self.assertEqual( - self.cppHeader.classes["OmegaClass"]["properties"]["public"][0]["type"], - 'string') - - def test_doxygen(self): - self.assertTrue( - "doxygen" - not in self.cppHeader.classes["OmegaClass"]["properties"]["public"][0].keys()) - - - -class OmegaClass_Rino_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["OmegaClass"]["enums"]["protected"][0]["name"], - 'Rino') - - def test_namespace(self): - self.assertEqual( - self.cppHeader.classes["OmegaClass"]["enums"]["protected"][0]["namespace"], - 'Alpha::Omega') - - def test_doxygen(self): - self.assertEqual( - self.cppHeader.classes["OmegaClass"]["enums"]["protected"][0]["doxygen"], - '///\n/// @brief Rino Numbers, not that that means anything\n///') - - def test_values(self): - self.assertEqual( - self.cppHeader.classes["OmegaClass"]["enums"]["protected"][0]["values"], - [{'name': 'RI_ZERO', 'value': 0}, {'name': 'RI_ONE', 'value': 1}, {'name': 'RI_TWO', 'value': 2}]) - - -class Bug3488053_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_public(self): - self.assertEqual(len(self.cppHeader.classes["Bug_3488053::Bug_3488053_Nested"]["properties"]["public"]), 1) - - def test_private(self): - self.assertEqual(len(self.cppHeader.classes["Bug_3488053::Bug_3488053_Nested"]["properties"]["private"]), 0) - - def test_protected(self): - self.assertEqual(len(self.cppHeader.classes["Bug_3488053::Bug_3488053_Nested"]["properties"]["protected"]), 0) - - -class Bug3488360_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_BloodOrange_inherits(self): - self.assertEqual(self.cppHeader.classes["BloodOrange"]["inherits"], []) - - def test_Bananna_inherits(self): - self.assertEqual(self.cppHeader.classes["Bananna"]["inherits"], [{'access': 'public', 'class': 'Citrus::BloodOrange', 'virtual': False}]) - - def test_ExcellentCake_inherits(self): - self.assertEqual(self.cppHeader.classes["ExcellentCake"]["inherits"], - [{'access': 'private', 'class': 'Citrus::BloodOrange', 'virtual': False}, - {'access': 'private', 'class': 'Convoluted::Nested::Mixin', 'virtual': False}]) - -class Bug3487551_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_method_rtn_type(self): - self.assertEqual(self.cppHeader.classes["Bug_3487551"]["methods"]["public"][0]["rtnType"], "int") - - -class SampleStruct_meth_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["SampleStruct"]["methods"]["public"][0]["name"], - 'meth') - - def test_rtntype(self): - self.assertEqual( - self.cppHeader.classes["SampleStruct"]["methods"]["public"][0]["rtnType"], - 'unsigned int') - - def test_parameters(self): - self.assertEqual( - self.cppHeader.classes["SampleStruct"]["methods"]["public"][0]["parameters"], - []) - - def test_doxygen(self): - self.assertTrue( - "doxygen" - not in self.cppHeader.classes["SampleStruct"]["methods"]["public"][0].keys()) - - - -class SampleStruct_prop_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual( - self.cppHeader.classes["SampleStruct"]["properties"]["private"][0]["name"], - 'prop') - - def test_type(self): - self.assertEqual( - self.cppHeader.classes["SampleStruct"]["properties"]["private"][0]["type"], - 'int') - - def test_doxygen(self): - self.assertTrue( - "doxygen" - not in self.cppHeader.classes["SampleStruct"]["properties"]["private"][0].keys()) - - -class Bird_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_items_array(self): - self.assertEqual(self.cppHeader.classes["Bird"]["properties"]["private"][0]["array"], 1) - - def test_otherItems_array(self): - self.assertEqual(self.cppHeader.classes["Bird"]["properties"]["private"][1]["array"], 1) - - def test_oneItem_array(self): - self.assertEqual(self.cppHeader.classes["Bird"]["properties"]["private"][2]["array"], 0) - - def test_items_array_size(self): - self.assertEqual(self.cppHeader.classes["Bird"]["properties"]["private"][0]["array_size"], "MAX_ITEM") - - def test_otherItems_array_size(self): - self.assertEqual(self.cppHeader.classes["Bird"]["properties"]["private"][1]["array_size"], "7") - - -class Monkey_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_public_methods(self): - self.assertEqual(len(self.cppHeader.classes["Monkey"]["methods"]["public"]), 0) - - def test_num_private_methods(self): - self.assertEqual(len(self.cppHeader.classes["Monkey"]["methods"]["private"]), 1) - - def test_num_protected_methods(self): - self.assertEqual(len(self.cppHeader.classes["Monkey"]["methods"]["protected"]), 0) - - - -class Chicken_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_public_methods(self): - self.assertEqual(len(self.cppHeader.classes["Chicken"]["methods"]["public"]), 0) - - def test_num_private_methods(self): - self.assertEqual(len(self.cppHeader.classes["Chicken"]["methods"]["private"]), 1) - - def test_num_protected_methods(self): - self.assertEqual(len(self.cppHeader.classes["Chicken"]["methods"]["protected"]), 0) - - def test_template(self): - self.assertEqual(self.cppHeader.classes["Chicken"]["methods"]["private"][0]['template'], "template ") - - - -class Lizzard_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_normal_constructor(self): - cmp_values = {'inline': False, 'name': 'Lizzard', 'parameters': [], 'friend': False, - 'explicit': False, 'constructor': True, 'namespace': '', 'destructor': False, - 'pure_virtual': False, 'returns': '', 'static': False, 'virtual': False, - 'template': False, 'rtnType': 'void', 'extern': False, 'path': 'Lizzard', - 'returns_pointer': 0, 'class': None} - self.assertEqual(filter_dict_keys(self.cppHeader.classes["Lizzard"]["methods"]["private"][0], cmp_values.keys()), - cmp_values) - - def test_explicit_constructor(self): - cmp_values = {'inline': False, 'name': 'Lizzard', 'friend': False, - 'explicit': True, 'constructor': True, 'namespace': '', 'destructor': False, - 'pure_virtual': False, 'returns': '', 'static': False, 'virtual': False, - 'template': False, 'rtnType': 'void', 'extern': False, 'path': 'Lizzard', - 'returns_pointer': 0, 'class': None} - self.assertEqual(filter_dict_keys(self.cppHeader.classes["Lizzard"]["methods"]["private"][1], cmp_values.keys()), - cmp_values) - - - -class Owl_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_public_methods(self): - self.assertEqual(len(self.cppHeader.classes["Owl"]["methods"]["public"]), 0) - - def test_num_private_methods(self): - self.assertEqual(len(self.cppHeader.classes["Owl"]["methods"]["private"]), 1) - - def test_num_protected_methods(self): - self.assertEqual(len(self.cppHeader.classes["Owl"]["methods"]["protected"]), 0) - - -class Grape_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_public_properties(self): - self.assertEqual(len(self.cppHeader.classes["GrapeClass"]["properties"]["public"]), 0) - - def test_num_private_properties(self): - self.assertEqual(len(self.cppHeader.classes["GrapeClass"]["properties"]["private"]), 1) - - def test_num_protected_properties(self): - self.assertEqual(len(self.cppHeader.classes["GrapeClass"]["properties"]["protected"]), 0) - - def test_num_public_methods(self): - self.assertEqual(len(self.cppHeader.classes["GrapeClass"]["methods"]["public"]), 0) - - def test_num_private_methods(self): - self.assertEqual(len(self.cppHeader.classes["GrapeClass"]["methods"]["private"]), 1) - - def test_num_protected_methods(self): - self.assertEqual(len(self.cppHeader.classes["GrapeClass"]["methods"]["protected"]), 0) - - -class AnonHolderClass_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_property(self): - cmp_values = {'constant': 0, 'name': 'a', 'reference': 0, 'type': '', 'static': 0, 'pointer': 0} - self.assertEqual(filter_dict_keys(self.cppHeader.classes["AnonHolderClass"]["properties"]["public"][0], cmp_values.keys()), cmp_values) - - -class CowClass_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_class_declaration_method(self): - self.assertEqual(self.cppHeader.classes["CowClass"]["declaration_method"], "class") - - def test_struct_declaration_method(self): - self.assertEqual(self.cppHeader.classes["CowStruct"]["declaration_method"], "struct") - - -class Mango_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_virtual_inherits(self): - self.assertEqual(self.cppHeader.classes["MangoClass"]["inherits"][0]["virtual"], True) - - - -class Eagle_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_property(self): - cmp_values = {'constant': 0, 'name': 'a', 'reference': 0, 'array_size': 'MAX_LEN', 'type': 'int', 'static': 0, 'pointer': 0} - self.assertEqual(filter_dict_keys(self.cppHeader.classes["EagleClass"]["properties"]["private"][0], cmp_values.keys()), cmp_values) - - -class Frog_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_private_properties(self): - self.assertEqual(len(self.cppHeader.classes["FrogClass"]["properties"]["private"]), 3) - - - -class Cat_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_private_properties(self): - self.assertEqual(len(self.cppHeader.classes["CatClass"]["properties"]["private"]), 0) - - -class Fish_TestCase(unittest.TestCase): - - def setUp(self): - #Just make sure it doesnt crash - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - -class Panda_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_property_CONST_A(self): - cmp_values = {'typedef': None, 'unresolved': False, 'constant': 1, 'name': 'CONST_A', - 'parent': None, 'pointer': 0, 'namespace': '', 'raw_type': 'int', 'class': 0, - 'property_of_class': 'PandaClass', 'static': 1, 'fundamental': True, - 'mutable': False, 'typedefs': 0, 'array': 0, 'type': 'static const int', - 'reference': 0, 'aliases': []} - self.assertEqual(filter_dict_keys(self.cppHeader.classes["PandaClass"]["properties"]["private"][0], cmp_values.keys()), cmp_values) - - def test_property_CONST_B(self): - cmp_values = {'typedef': None, 'unresolved': False, 'constant': 1, 'name': 'CONST_B', - 'parent': None, 'pointer': 0, 'namespace': '', 'raw_type': 'int', 'class': 0, - 'property_of_class': 'PandaClass', 'static': 1, 'fundamental': True, - 'mutable': False, 'typedefs': 0, 'array': 0, 'type': 'static const int', - 'reference': 0, 'aliases': []} - self.assertEqual(filter_dict_keys(self.cppHeader.classes["PandaClass"]["properties"]["private"][1], cmp_values.keys()), cmp_values) - - -class Potato_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_private_properties_potato(self): - self.assertEqual(len(self.cppHeader.classes["PotatoClass"]["properties"]["private"]), 1) - - def test_num_public_properties_potato_fwdstruct(self): - self.assertEqual(len(self.cppHeader.classes["PotatoClass::FwdStruct"]["properties"]["public"]), 1) - - -class Hog_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_private_properties_potato(self): - self.assertEqual(len(self.cppHeader.classes["HogClass"]["properties"]["private"]), 1) - - def test_property(self): - cmp_values = {'constant': 0, 'name': 'u', 'reference': 0, 'type': 'union HogUnion', 'static': 0, 'pointer': 0} - self.assertEqual(filter_dict_keys(self.cppHeader.classes["HogClass"]["properties"]["private"][0], cmp_values.keys()), cmp_values) - - def test_union(self): - cmp_values = {"name": "union HogUnion", "parent": "HogClass", "declaration_method": "union"} - self.assertEqual(filter_dict_keys(self.cppHeader.classes["HogClass::union HogUnion"], cmp_values.keys()), cmp_values) - - def test_union_member_a(self): - cmp_values = {'constant': 0, 'name': 'a', 'reference': 0, 'type': 'int', 'static': 0, 'pointer': 0} - self.assertEqual(filter_dict_keys(self.cppHeader.classes["HogClass::union HogUnion"]["members"][0], cmp_values.keys()), cmp_values) - - def test_union_member_b(self): - cmp_values = {'constant': 0, 'name': 'b', 'reference': 0, 'type': 'float', 'static': 0, 'pointer': 0} - self.assertEqual(filter_dict_keys(self.cppHeader.classes["HogClass::union HogUnion"]["members"][1], cmp_values.keys()), cmp_values) - -# Bug 3497158 -class CherryClass_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_public_properties(self): - self.assertEqual(len(self.cppHeader.classes["CherryClass::NestStruct"]["properties"]["public"]), 1) - - def test_num_public_methods(self): - self.assertEqual(len(self.cppHeader.classes["CherryClass::NestStruct"]["methods"]["public"]), 1) - -# Bug 3517308 -class GarlicClass_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_public_properties(self): - self.assertEqual(len(self.cppHeader.classes["GarlicClass"]["properties"]["public"]), 0) - - def test_num_public_methods(self): - self.assertEqual(len(self.cppHeader.classes["GarlicClass"]["methods"]["public"]), 3) - -# Bug 3514728 -class CarrotClass_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_private_properties(self): - self.assertEqual(len(self.cppHeader.classes["CarrotClass"]["properties"]["private"]), 1) - - def test_num_private_methods(self): - self.assertEqual(len(self.cppHeader.classes["CarrotClass"]["methods"]["private"]), 1) - - def test_method_params(self): - self.assertEqual( - filter_pameters(self.cppHeader.classes["CarrotClass"]["methods"]["private"][0]["parameters"]), - []) - - def test_class_template(self): - self.assertEqual(self.cppHeader.classes["CarrotClass"]["template"], "template") - - -# Bug 3517289 -class CarrotClass_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_private_methods(self): - self.assertEqual(len(self.cppHeader.classes["ExternClass"]["methods"]["private"]), 1) - - -# Bug 3514671 -class OliveStruct_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_public_properties(self): - self.assertEqual(len(self.cppHeader.classes["OliveStruct"]["properties"]["public"]), 4) - - def test_var_a(self): - self.assertEqual(self.cppHeader.classes["OliveStruct"]["properties"]["public"][0]["name"], "a") - - -# Bug 3515330 -class Rooster_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_public_properties(self): - self.assertEqual(len(self.cppHeader.classes["RoosterOuterClass"]["properties"]["public"]), 1) - - def test_num_private_properties(self): - self.assertEqual(len(self.cppHeader.classes["RoosterOuterClass"]["properties"]["private"]), 1) - - def test_num_sub1_public_properties(self): - self.assertEqual(len(self.cppHeader.classes["RoosterOuterClass::RoosterSubClass1"]["properties"]["public"]), 1) - - def test_num_sub1_private_properties(self): - self.assertEqual(len(self.cppHeader.classes["RoosterOuterClass::RoosterSubClass1"]["properties"]["private"]), 1) - - def test_num_sub2_public_properties(self): - self.assertEqual(len(self.cppHeader.classes["RoosterOuterClass::RoosterSubClass2"]["properties"]["public"]), 1) - - def test_num_sub2_private_properties(self): - self.assertEqual(len(self.cppHeader.classes["RoosterOuterClass::RoosterSubClass2"]["properties"]["private"]), 1) - - -# Bug 3514672 -class OperatorClass_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_op_0(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][0]["name"], 'operator=') - - def test_op_1(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][1]["name"], 'operator-=') - - def test_op_2(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][2]["name"], 'operator+=') - - def test_op_3(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][3]["name"], 'operator[]') - - def test_op_4(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][4]["name"], 'operator==') - - def test_op_5(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][5]["name"], 'operator+') - - def test_op_6(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][6]["name"], 'operator-') - - def test_op_7(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][7]["name"], 'operator*') - - def test_op_8(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][8]["name"], 'operator\\') - - def test_op_9(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][9]["name"], 'operator%') - - def test_op_10(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][10]["name"], 'operator^') - - def test_op_11(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][11]["name"], 'operator|') - - def test_op_12(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][12]["name"], 'operator&') - - def test_op_13(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][13]["name"], 'operator~') - - def test_op_14(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][14]["name"], 'operator<<') - - def test_op_15(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][15]["name"], 'operator>>') - - def test_op_16(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][16]["name"], 'operator!=') - - def test_op_17(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][17]["name"], 'operator<') - - def test_op_18(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][18]["name"], 'operator>') - - def test_op_19(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][19]["name"], 'operator>=') - - def test_op_20(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][20]["name"], 'operator<=') - - def test_op_21(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][21]["name"], 'operator!') - - def test_op_22(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][22]["name"], 'operator&&') - - def test_op_23(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][23]["name"], 'operator||') - - def test_op_24(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][24]["name"], 'operator+=') - - def test_op_25(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][25]["name"], 'operator-=') - - def test_op_26(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][26]["name"], 'operator*=') - - def test_op_27(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][27]["name"], 'operator\\=') - - def test_op_28(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][28]["name"], 'operator%=') - - def test_op_29(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][29]["name"], 'operator&=') - - def test_op_30(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][30]["name"], 'operator|=') - - def test_op_31(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][31]["name"], 'operator^=') - - def test_op_32(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][32]["name"], 'operator<<=') - - def test_op_33(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][33]["name"], 'operator>>=') - - def test_op_34(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][34]["name"], 'operator++') - - def test_op_35(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][35]["name"], 'operator--') - - def test_op_36(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][36]["name"], 'operator()') - - def test_op_37(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][37]["name"], 'operator->') - - def test_op_38(self): - self.assertEqual(self.cppHeader.classes["OperatorClass"]["methods"]["public"][38]["name"], 'operator,') - - -# Feature Request 3519502 & 3523010 -class CrowClass_TestCase(unittest.TestCase): - - def setUp(self): - self.savedSupportedAccessSpecifier = CppHeaderParser.supportedAccessSpecifier - CppHeaderParser.supportedAccessSpecifier.append("public slots ")#intentionally add expra spaces to make sure they get cleaned up - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_public_methods(self): - self.assertEqual(len(self.cppHeader.classes["CrowClass"]["methods"]["public"]), 1) - - def test_rtntype_public_slot_method(self): - self.assertEqual(self.cppHeader.classes["CrowClass"]["methods"]["public slots"][0]["rtnType"], 'void') - - def test_num_public_slot_methods(self): - self.assertEqual(len(self.cppHeader.classes["CrowClass"]["methods"]["public slots"]), 1) - - def tearDown(self): - CppHeaderParser.supportedAccessSpecifier = self.savedSupportedAccessSpecifier - - -# Bug 3497170 -class DriverFuncs_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name_0(self): - self.assertEqual(self.cppHeader.classes["DriverFuncs"]["properties"]["public"][0]["name"], "init") - - def test_type_0(self): - self.assertEqual(self.cppHeader.classes["DriverFuncs"]["properties"]["public"][0]["type"], "void * ( * ) ( )") - - def test_function_pointer_field_0(self): - self.assertEqual(self.cppHeader.classes["DriverFuncs"]["properties"]["public"][0]["function_pointer"], 1) - - def test_name_1(self): - self.assertEqual(self.cppHeader.classes["DriverFuncs"]["properties"]["public"][1]["name"], "write") - - def test_type_1(self): - self.assertEqual(self.cppHeader.classes["DriverFuncs"]["properties"]["public"][1]["type"], "void ( * ) ( void * buf, int buflen )") - - def test_function_pointer_field_1(self): - self.assertEqual(self.cppHeader.classes["DriverFuncs"]["properties"]["public"][1]["function_pointer"], 1) - - -# Bug 3519178 -class Snail_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_rtn_type(self): - self.assertEqual(self.cppHeader.classes["Snail2Class"]["methods"]["public"][0]["rtnType"], "SnailNamespace::SnailClass") - - def test_param_name(self): - self.assertEqual(self.cppHeader.classes["Snail2Class"]["methods"]["public"][0]["parameters"][0]["name"], "") - - def test_param_name(self): - self.assertEqual(self.cppHeader.classes["Snail2Class"]["methods"]["public"][0]["parameters"][0]["type"], "tr1::shared_ptr >") - -# Feature Request 3523198 -class Quale_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_rtn_type(self): - self.assertEqual(self.cppHeader.classes["QualeClass"]["methods"]["private"][0]["rtnType"], "void") - - -# Feature Request 3523235 -class Rock_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_const_0(self): - self.assertEqual(self.cppHeader.classes["RockClass"]["methods"]["private"][0]["const"], True) - - def test_const_1(self): - self.assertEqual(self.cppHeader.classes["RockClass"]["methods"]["private"][1]["const"], False) - - -# Bug 3523196 -class Almond_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_rtn_type(self): - self.assertEqual(self.cppHeader.classes["AlmondClass"]["methods"]["public"][0]["rtnType"], "std::map > >") - - def test_param_1_name(self): - self.assertEqual(self.cppHeader.classes["AlmondClass"]["methods"]["public"][0]["parameters"][0]["name"], "flag") - - def test_param_1_type(self): - self.assertEqual(self.cppHeader.classes["AlmondClass"]["methods"]["public"][0]["parameters"][0]["type"], "bool") - - def test_param_2_name(self): - self.assertEqual(self.cppHeader.classes["AlmondClass"]["methods"]["public"][0]["parameters"][1]["name"], "bigArg") - - def test_param_2_type(self): - self.assertEqual(self.cppHeader.classes["AlmondClass"]["methods"]["public"][0]["parameters"][1]["type"], "std::map > >") - - -# Bug 3524327 -class Stone_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_const_0(self): - self.assertEqual(self.cppHeader.classes["StoneClass"]["methods"]["private"][0]["const"], True) - - def test_const_1(self): - self.assertEqual(self.cppHeader.classes["StoneClass"]["methods"]["private"][1]["const"], False) - - -# Bug 3531219 -class Kangaroo_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_kangaroo_methods(self): - self.assertEqual(len(self.cppHeader.classes["Kangaroo"]["methods"]["public"]), 1) - - def test_num_joey_methods(self): - self.assertEqual(len(self.cppHeader.classes["Kangaroo::Joey"]["methods"]["public"]), 1) - - -# Bug 3535465 -class Ant_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_constructor_1_params(self): - self.assertEqual(len(self.cppHeader.classes["Ant"]["methods"]["public"][0]["parameters"]), 3) - - def test_num_constructor_2_params(self): - self.assertEqual(len(self.cppHeader.classes["Ant"]["methods"]["public"][1]["parameters"]), 1) - -# Bug 3536069 -class Onion_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_public_properties_red(self): - self.assertEqual(len(self.cppHeader.classes["Onion"]["properties"]["public"]), 1) - - def test_num_public_properties_sweet(self): - self.assertEqual(len(self.cppHeader.classes["Onion"]["properties"]["public"]), 1) - - def test_class_template(self): - self.assertEqual(self.cppHeader.classes["Onion"]["template"], "template ") - -# Bug 3536067 -class BlueJay_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_public_methods(self): - self.assertEqual(len(self.cppHeader.classes["BlueJay"]["methods"]["public"]), 1) - -# Bug 3536266 -class functions_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("""\ - void global_funct1(int i); - int global_funct2(void); - """, "string") - - def test_num_functions(self): - self.assertEqual(len(self.cppHeader.functions), 2) - - def test_function_name_1(self): - self.assertEqual(self.cppHeader.functions[0]["name"], "global_funct1") - - def test_function_name_2(self): - self.assertEqual(self.cppHeader.functions[1]["name"], "global_funct2") - - -# Bug 3536071 -class Pea_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_num_inherits(self): - self.assertEqual(len(self.cppHeader.classes["Pea"]["inherits"]), 1) - - def test_name_inherits(self): - self.assertEqual(self.cppHeader.classes["Pea"]["inherits"][0]["class"], "Vegetable") - -# Bug 3540172 -class functions2_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("""\ - void global_funct1(int i); - int global_funct2(void){ - // do something - } - """, "string") - - def test_num_functions(self): - self.assertEqual(len(self.cppHeader.functions), 2) - - def test_function_name_1(self): - self.assertEqual(self.cppHeader.functions[0]["name"], "global_funct1") - - def test_function_name_2(self): - self.assertEqual(self.cppHeader.functions[1]["name"], "global_funct2") - -# Feature: line numbers -class line_num_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("LineNumTest.h") - - def test_lineno_function1(self): - return self.assertEqual(self.cppHeader.functions[0]["line_number"], 13) - - def test_lineno_function2(self): - return self.assertEqual(self.cppHeader.functions[1]["line_number"], 17) - - def test_lineno_Worm(self): - return self.assertEqual(self.cppHeader.classes["Worm"]["line_number"], 20) - - def test_lineno_Worm_Constructor(self): - return self.assertEqual(self.cppHeader.classes["Worm"]["methods"]["public"][0]["line_number"], 23) - - def test_lineno_Worm_getName(self): - return self.assertEqual(self.cppHeader.classes["Worm"]["methods"]["public"][1]["line_number"], 24) - - def test_lineno_Worm_namep(self): - return self.assertEqual(self.cppHeader.classes["Worm"]["properties"]["private"][0]["line_number"], 29) - -# Bug 3567172 -class Pear_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_property(self): - self.assertEqual(self.cppHeader.classes["Pear"]["properties"]["private"][0]["name"], "stem_property") - - - -# Bug 3567217 and 3569663 -class Macro_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader(r""" -#include -#include "../../debug.h" - -#define ONE 1 -#define TWO_NUM_N_NAME "2 (TWO)" -#pragma once - - #define DEBUG_PRINT(x) \ - printf("---------------\n"); \ - printf("DEBUG: %d\n", x); \ - printf("---------------\n");""", "string") - - def test_includes(self): - self.assertEqual(self.cppHeader.includes, ['', '"../../debug.h"']) - - def test_pragmas(self): - self.assertEqual(self.cppHeader.pragmas, ['once']) - - def test_pragmas0(self): - self.assertEqual(self.cppHeader.defines[0], 'ONE 1') - - def test_pragmas1(self): - self.assertEqual(self.cppHeader.defines[1], 'TWO_NUM_N_NAME "2 (TWO)"') - - def test_pragmas2(self): - self.assertEqual(self.cppHeader.defines[2], 'DEBUG_PRINT(x) \\\n printf("---------------\\n"); \\\n printf("DEBUG: %d\\n", x); \\\n printf("---------------\\n");') - - - -# Bug: 3567854 and 3568241 -class Beans_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_anonymous_union_name(self): - return self.assertEqual(self.cppHeader.classes["Beans"]["properties"]["public"][1]["name"], "") - - def test_second_anonymous_union_name(self): - return self.assertEqual(self.cppHeader.classes["Beans"]["properties"]["public"][3]["name"], "") - - -# Bug: 3567854 and 3568241 -class termite_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_termite_function(self): - self.assertEqual(self.cppHeader.functions[5]["name"], "termite") - - - -# Bug: 3569622 -class Japyx_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_japyxFunc(self): - self.assertEqual(self.cppHeader.functions[6]["name"], "japyxFunc") - - -# Bug: 3570105 -class Author_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual(self.cppHeader.enums[0]["name"], "Author") - - def test_name(self): - self.assertEqual(self.cppHeader.enums[0]["values"], [ - {'name': 'NAME', 'value': "( 'J' << 24 | 'A' << 16 | 'S' << 8 | 'H' )"}]) - - -# Bug: 3577484 -class Fly_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_exists(self): - self.assertEqual(self.cppHeader.classes.has_key("FruitFly"), True) - -# Bug BitBucket #2 -class ClassAfterMagicMacro_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_class_exists(self): - self.assertEqual(self.cppHeader.classes.has_key("ClassAfterMagicMacro"), True) - -# Bug BitBucket #3 -class FilterMagicMacro_TestCase(unittest.TestCase): - - def setUp(self): - savedIgnoreSymbols = CppHeaderParser.ignoreSymbols - CppHeaderParser.ignoreSymbols.append("MAGIC_FUNC()") - self.cppHeader = CppHeaderParser.CppHeader(r""" -class FilterMagicMacro -{ -public: - - MAGIC_FUNC(var) - MAGIC_FUNC(v, - a, - r) - MAGIC_FUNC((int)var) - MAGIC_FUNC(((()))var()()()) - MAGIC_FUNC("1) \" var") - - void FilterMagicMacroMethod(int); -};""", "string") - CppHeaderParser.ignoreSymbols = savedIgnoreSymbols - - def test_method_exists(self): - self.assertEqual(self.cppHeader.classes["FilterMagicMacro"]["methods"]["public"][0]["name"], "FilterMagicMacroMethod") - - def test_line_num_is_correct(self): - self.assertEqual(self.cppHeader.classes["FilterMagicMacro"]["methods"]["public"][0]["line_number"], 14); - -# Bug BitBucket #4 -class ClassRegularTypedefs_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_uint_exists(self): - self.assertEqual(self.cppHeader.typedefs.has_key("uint"), True) - - def test_string_array_exists(self): - self.assertEqual(self.cppHeader.typedefs.has_key("string_array"), True) - - def test_SmartObjPtr_exists(self): - self.assertEqual(self.cppHeader.typedefs.has_key("SmartObjPtr"), True) - - def test_StrStrMap_exists(self): - self.assertEqual(self.cppHeader.typedefs.has_key("StrStrMap"), True) - - def test_AfterTypedefClass_exists(self): - self.assertEqual(self.cppHeader.classes.has_key("AfterTypedefClass"), True) - -# Bug BitBucket #6 -class LineNumAfterDivide_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_line_num(self): - self.assertEqual(self.cppHeader.classes["LineNumAfterDivide"]["methods"]["private"][1]["line_number"], 583) - -# Bug BitBucket #5 -class ClassHerbCilantro_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_HerbCilantro_exists(self): - self.assertEqual(self.cppHeader.classes.has_key("Herb::Cilantro"), True) - -# Bug BitBucket #7 -class print_statement_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_function_name_type(self): - self.assertEqual(self.cppHeader.functions[7]["name"], "print_statement") - - def test_return_type(self): - self.assertEqual(self.cppHeader.functions[7]["returns"], "int") - -# Bug BitBucket #8 -class Garlic_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_function_exists(self): - self.assertEqual(self.cppHeader.classes["Garlic"]["methods"]["public"][0]["name"], "genNum") - -# Bug SourceForge #54 -class Wheat_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual(self.cppHeader.enums[1]["name"], "Wheat") - - def test_typedef(self): - self.assertEqual(self.cppHeader.enums[1]["typedef"], False) - -# Bug SourceForge #55 -class PeachPlumb_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_Peach_exists(self): - self.assertEqual(self.cppHeader.classes.has_key("Peach"), True) - - def test_Plumb_exists(self): - self.assertEqual(self.cppHeader.classes.has_key("Plumb"), True) - - def test_function_exists(self): - self.assertEqual(self.cppHeader.classes["Plumb"]["methods"]["private"][0]["name"], "doSomethingGreat") - -# Bug BitBucket #9 -class Grape_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_Grape_exists(self): - self.assertEqual(self.cppHeader.classes.has_key("Grape"), True) - - def test_a_exists(self): - self.assertEqual(self.cppHeader.classes["Grape"]["properties"]["public"][0]["name"], "a") - - def test_a_type(self): - self.assertEqual(self.cppHeader.classes["Grape"]["properties"]["public"][0]["type"], "int") - - def test_b_exists(self): - self.assertEqual(self.cppHeader.classes["Grape"]["properties"]["public"][1]["name"], "b") - - def test_b_type(self): - self.assertEqual(self.cppHeader.classes["Grape"]["properties"]["public"][1]["type"], "int") - - def test_c_exists(self): - self.assertEqual(self.cppHeader.classes["Grape"]["properties"]["public"][2]["name"], "c") - - def test_d_exists(self): - self.assertEqual(self.cppHeader.classes["Grape"]["properties"]["public"][3]["name"], "d") - - def test_e_exists(self): - self.assertEqual(self.cppHeader.classes["Grape"]["properties"]["public"][4]["name"], "e") - - def test_f_exists(self): - self.assertEqual(self.cppHeader.classes["Grape"]["properties"]["public"][5]["name"], "f") - -# Bug BitBucket #14 -class Avacado_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_Avacado_exists(self): - self.assertEqual(self.cppHeader.classes.has_key("Avacado"), True) - - def test_foo_return_type(self): - self.assertEqual(self.cppHeader.classes["Avacado"]["methods"]["public"][0]["returns"], "uint8_t") - - def test_bar_return_type(self): - self.assertEqual(self.cppHeader.classes["Avacado"]["methods"]["public"][1]["returns"], "::uint8_t") - -# Bug BitBucket #13 -class Raspberry_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_anon_struct_1_exists(self): - self.assertEqual(self.cppHeader.classes.has_key(""), True) - - def test_beta_exists(self): - self.assertEqual(self.cppHeader.classes[""]["properties"]["public"][0]["name"], "anon_struct_variable") - - def test_Raspberry_exists(self): - self.assertEqual(self.cppHeader.classes.has_key("Raspberry"), True) - - def test_a_exists(self): - self.assertEqual(self.cppHeader.classes["Raspberry"]["properties"]["public"][0]["name"], "a") - -# Bug BitBucket #15 & 16 -class Hen_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_default_a(self): - self.assertEqual(self.cppHeader.classes["Hen"]["methods"]["public"][0]["parameters"][0]["defaultValue"], "100") - - def test_default_b(self): - self.assertEqual(self.cppHeader.classes["Hen"]["methods"]["public"][0]["parameters"][1]["defaultValue"], "0xfd") - - def test_default_c(self): - self.assertEqual(self.cppHeader.classes["Hen"]["methods"]["public"][0]["parameters"][2]["defaultValue"], "1.7e-3") - - def test_default_d(self): - self.assertEqual(self.cppHeader.classes["Hen"]["methods"]["public"][0]["parameters"][3]["defaultValue"], "3.14") - - def test_default_s1(self): - self.assertEqual(self.cppHeader.classes["Hen"]["methods"]["public"][1]["parameters"][0]["defaultValue"], '""') - - def test_default_s2(self): - self.assertEqual(self.cppHeader.classes["Hen"]["methods"]["public"][1]["parameters"][1]["defaultValue"], '"nothing"') - - -# Bug BitBucket #19 -class Raddish_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_Avacado_exists(self): - self.assertEqual(self.cppHeader.classes["Raddish_SetIterator"]["properties"]["protected"][0]["name"], "_beg") - - def test_class_template(self): - template_str = \ - "template >" - self.assertEqual(self.cppHeader.classes["Raddish_SetIterator"]["template"], template_str) - - -# Bug bug 57 -class Carambola_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual(self.cppHeader.enums[2]["name"], "Carambola") - - def test_values(self): - self.assertEqual(self.cppHeader.enums[2]["values"], [ - {'name': 'StarFruit', 'value': '( 2 + 2 ) / 2'}]) - - def test_typedef(self): - self.assertEqual(self.cppHeader.enums[2]["typedef"], True) - - -# globals -class Globals_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_externVar_name(self): - self.assertEqual(self.cppHeader.variables[2]["name"], "externVar") - - def test_externVar_extern(self): - self.assertEqual(self.cppHeader.variables[2]["extern"], 1) - - def test_globalVar_name(self): - self.assertEqual(self.cppHeader.variables[3]["name"], "globalVar") - - def test_globalVar_extern(self): - self.assertEqual(self.cppHeader.variables[3]["extern"], 0) - -# globals -class TypedefArray_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual(self.cppHeader.typedefs.has_key("TenCharArray[10]"), True) - - def test_value(self): - self.assertEqual(self.cppHeader.typedefs["TenCharArray[10]"], "char") - -# typedef structs -class TypedefStruct_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_name(self): - self.assertEqual(self.cppHeader.typedefs.has_key("MAGIC_FILE"), True) - - def test_value(self): - self.assertEqual(self.cppHeader.typedefs["MAGIC_FILE"], "struct SUPER_MAGIC_FILE") - - -# Bug SourceForge #10 -class Picture_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_array_size(self): - self.assertEqual(self.cppHeader.classes["Picture"]["properties"]["public"][1]["array_size"], 16384) - - def test_multi_dimensional_array_size(self): - self.assertEqual(self.cppHeader.classes["Picture"]["properties"]["public"][1]["multi_dimensional_array_size"], "128x128") - - - -# SourceForge bug 58 -class Apricot_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_Apricot_exists(self): - self.assertEqual(self.cppHeader.classes.has_key("Apricot"), True) - - def test_i_exists(self): - self.assertEqual(self.cppHeader.classes["Apricot"]["members"][0]["name"], "i") - - def test_f_exists(self): - self.assertEqual(self.cppHeader.classes["Apricot"]["members"][1]["name"], "f") - - def test_s_exists(self): - self.assertEqual(self.cppHeader.classes["Apricot"]["members"][2]["name"], "s") - - -# SourceForge bug 59 -class LemonLime_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_lemon_not_final(self): - self.assertEqual(self.cppHeader.classes["Lemon"]["final"], False) - - def test_lime_final(self): - self.assertEqual(self.cppHeader.classes["Lime"]["final"], True) - - def test_lemon_foo_is_final(self): - self.assertEqual(self.cppHeader.classes["Lemon"]["methods"]["public"][0]["final"], True) - - def test_lemon_foo2_is_not_final(self): - self.assertEqual(self.cppHeader.classes["Lemon"]["methods"]["public"][1]["final"], False) - - def test_lime_abc_is_not_override(self): - self.assertEqual(self.cppHeader.classes["Lime"]["methods"]["public"][0]["override"], False) - - def test_lime_foo2_is_not_override(self): - self.assertEqual(self.cppHeader.classes["Lime"]["methods"]["public"][1]["override"], True) - - -class JSON_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader(r""" -struct Lemon -{ - virtual void foo() final; - virtual void foo2(); -}; - -struct Lime final : Lemon -{ - void abc(); - void foo2() override; -};""", "string") - self.jsonString = self.cppHeader.toJSON() - - def test_hasLemon(self): - hasString = ' "Lemon": {' in self.jsonString - self.assertEqual(hasString, True) - - def test_can_parse_complex_file(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - j = self.cppHeader.toJSON() - -# BitBucket bug 24 -class Mouse_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_MouseClass_exists(self): - self.assertEqual(self.cppHeader.classes.has_key("MouseClass"), True) - - def test_mouse_typedef_correct_value(self): - self.assertEqual(self.cppHeader.classes["MouseClass"]["methods"]["public"][0]["parameters"][0]['raw_type'], - "MouseNS::MouseClass::mouse_typedef") - -# BitBucket bug 26 -class Fig_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_Fig_exists(self): - self.assertEqual(self.cppHeader.classes.has_key("Fig"), True) - - def test_a_exists(self): - self.assertEqual(self.cppHeader.classes["Grape"]["properties"]["public"][0]["name"], "a") - -# BitBucket bug 27 -class Olive_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_Olive_exists(self): - self.assertEqual(self.cppHeader.classes.has_key("union olive"), True) - - def test_union_member_x(self): - cmp_values = {'constant': 0, 'name': 'x', 'reference': 0, 'type': 'int', 'static': 0, 'pointer': 0} - self.assertEqual(filter_dict_keys(self.cppHeader.classes["union olive"]["members"][0], cmp_values.keys()), cmp_values) - -# BitBucket bug 61 -class Beet_TestCase(unittest.TestCase): - - def setUp(self): - self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h") - - def test_Beet_exists(self): - self.assertEqual(self.cppHeader.classes.has_key("BeetStruct"), True) - - def test_BeetEnum_exists(self): - self.assertEqual(self.cppHeader.classes["BeetStruct"]["enums"]["public"][0]["name"], "BeetEnum") - - - -if __name__ == '__main__': - unittest.main() - - diff --git a/CppHeaderParser/tojson.py b/CppHeaderParser/tojson.py new file mode 100644 index 0000000..e9ea24a --- /dev/null +++ b/CppHeaderParser/tojson.py @@ -0,0 +1,10 @@ +# Utility module + +import sys +import json + +from .CppHeaderParser import CppHeader + +if __name__ == "__main__": + for arg in sys.argv[1:]: + print(CppHeader(arg).toJSON()) diff --git a/MANIFEST.in b/MANIFEST.in index e608a82..1021a91 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,4 @@ -include README.txt -include README.html -include CppHeaderParser/doc/CppHeaderParser.html -include CppHeaderParser/examples/readSampleClass.py -include CppHeaderParser/examples/SampleClass.h +include README.rst +include LICENSE.txt +include examples/readSampleClass.py +include examples/SampleClass.h diff --git a/Makefile b/Makefile deleted file mode 100644 index cc76c13..0000000 --- a/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -all: package - -doc: - @pydoc -w CppHeaderParser/CppHeaderParser.py && mv CppHeaderParser.html CppHeaderParser/doc - @python doc_generator.py - -test: - @echo "" - @echo "" - @echo "Testing Python 2.x" - @(cd CppHeaderParser/test; python test_CppHeaderParser.py) - @echo "" - @echo "" - @echo "Testing Python 3.x" - @if [ ! -e CppHeaderParser/python3-libs ]; \ - then \ - echo "Can't test python3 version without CppHeaderParser/python3-libs containing"; \ - echo " * ply"; \ - echo " * unittest"; \ - exit 1; \ - fi; - @(cd CppHeaderParser/test; python3 test_CppHeaderParser3.py) - -package: doc - @python setup.py sdist --formats=gztar,zip - -install: doc - @python setup.py install - - -upload: doc - @python setup.py sdist upload - - -help: - @echo "doc - Build Documentation" - @echo "test - Run regression tests" - @echo "package - Build a distributable package" - @echo "install - Install the CppHeaderParser package" - @echo "upload - Upload the latest package to pypi" diff --git a/README.html b/README.html deleted file mode 100644 index 8b43596..0000000 --- a/README.html +++ /dev/null @@ -1,598 +0,0 @@ - - - - - - -Codestin Search App - - - -

- - -
-

Python package "CppHeaderParser"

-

Purpose: Parse C++ header files and generate a data structure representing the class

-

Author: Jashua Cloutier

-

Licence: BSD

-

External modules required: PLY

-

Quick start:

-
-#include <vector>
-#include <string>
-
-#define DEF_1 1
-#define OS_NAME "Linux"
-
-using namespace std;
-class SampleClass
-{
-public:
-    SampleClass();
-    /*!
-     * Method 1
-     */
-    string meth1();
-
-    ///
-    /// Method 2 description
-    ///
-    /// @param v1 Variable 1
-    ///
-    int meth2(int v1);
-
-    /**
-     * Method 3 description
-     *
-     * \param v1 Variable 1
-     * \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;
-};
-namespace Alpha
-{
-    class AlphaClass
-    {
-    public:
-        AlphaClass();
-
-        void alphaMethod();
-
-        string alphaString;
-    };
-
-    namespace Omega
-    {
-        class OmegaClass
-        {
-        public:
-            OmegaClass();
-
-            string omegaString;
-        };
-    };
-}
-
-int sampleFreeFunction(int i)
-{
-    return i + 1;
-}
-
-int anotherFreeFunction(void);
-}
-
-

Python code:

-
-#!/usr/bin/python
-import sys
-sys.path = ["../"] + sys.path
-import CppHeaderParser
-try:
-    cppHeader = CppHeaderParser.CppHeader("SampleClass.h")
-except CppHeaderParser.CppParseError as e:
-    print(e)
-    sys.exit(1)
-
-print("CppHeaderParser view of %s"%cppHeader)
-
-sampleClass = cppHeader.classes["SampleClass"]
-print("Number of public methods %d"%(len(sampleClass["methods"]["public"])))
-print("Number of private properties %d"%(len(sampleClass["properties"]["private"])))
-meth3 = [m for m in sampleClass["methods"]["public"] if m["name"] == "meth3"][0] #get meth3
-meth3ParamTypes = [t["type"] for t in meth3["parameters"]] #get meth3s parameters
-print("Parameter Types for public method meth3 %s"%(meth3ParamTypes))
-
-print("\nReturn type for meth1:")
-print(cppHeader.classes["SampleClass"]["methods"]["public"][1]["rtnType"])
-
-print("\nDoxygen for meth2:")
-print(cppHeader.classes["SampleClass"]["methods"]["public"][2]["doxygen"])
-
-print("\nParameters for meth3:")
-print(cppHeader.classes["SampleClass"]["methods"]["public"][3]["parameters"])
-
-print("\nDoxygen for meth4:")
-print(cppHeader.classes["SampleClass"]["methods"]["public"][4]["doxygen"])
-
-print("\nReturn type for meth5:")
-print(cppHeader.classes["SampleClass"]["methods"]["private"][0]["rtnType"])
-
-print("\nDoxygen type for prop1:")
-print(cppHeader.classes["SampleClass"]["properties"]["private"][0]["doxygen"])
-
-print("\nType for prop5:")
-print(cppHeader.classes["SampleClass"]["properties"]["private"][1]["type"])
-
-print("\nNamespace for AlphaClass is:")
-print(cppHeader.classes["AlphaClass"]["namespace"])
-
-print("\nReturn type for alphaMethod is:")
-print(cppHeader.classes["AlphaClass"]["methods"]["public"][0]["rtnType"])
-
-print("\nNamespace for OmegaClass is:")
-print(cppHeader.classes["OmegaClass"]["namespace"])
-
-print("\nType for omegaString is:")
-print(cppHeader.classes["AlphaClass"]["properties"]["public"][0]["type"])
-
-print("\nFree functions are:")
-for func in cppHeader.functions:
-    print(" %s"%func["name"])
-
-print("\n#includes are:")
-for incl in cppHeader.includes:
-    print(" %s"%incl)
-
-print("\n#defines are:")
-for define in cppHeader.defines:
-    print(" %s"%define)
-
-

Output:

-
-CppHeaderParser view of class SampleClass
-{
-public
-    // Methods
-   {'line_number': 11, 'parent': {'inherits': [], 'line_number': 8, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'SampleClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}, {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{...}, {'line_number': 15, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': False, 'rtnType': 'string', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'returns_unknown': True, 'doxygen': '/*!\n* Method 1\n*/', 'const': False, 'name': 'meth1', 'pure_virtual': False, 'debug': 'string meth1 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'string', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 22, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 22, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': False, 'name': 'v1', 'fundamental': True}], 'class': None, 'returns_reference': False, 'doxygen': '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///', 'const': False, 'name': 'meth2', 'pure_virtual': False, 'debug': 'int meth2 ( int v1 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 30, 'unresolved_parameters': True, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 30, 'constant': 1, 'reference': 1, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'const string &', 'method': {...}, 'parent': None, 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': True, 'name': 'v1', 'fundamental': 0}, {'line_number': 30, 'constant': 0, 'reference': 1, 'raw_type': 'vector<string>', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['vector<string>'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'template': 'vector<string>', 'mutable': False, 'type': 'vector<string> &', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 2', 'unresolved': True, 'name': 'v2', 'fundamental': 0}], 'class': None, 'returns_reference': False, 'doxygen': '/**\n* Method 3 description\n*\n* \\param v1 Variable 1\n* \\param v2 Variable 2\n*/', 'const': False, 'name': 'meth3', 'pure_virtual': False, 'debug': 'void meth3 ( const string & v1 , vector <string> & v2 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 37, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'unsigned int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'doxygen': '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/', 'const': False, 'name': 'meth4', 'pure_virtual': False, 'debug': 'unsigned int meth4 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'unsigned int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': [{'line_number': 39, 'parent': {...}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void *', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 1, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'meth5', 'pure_virtual': False, 'debug': 'void * meth5 ( ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}]}}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'SampleClass', 'pure_virtual': False, 'debug': 'SampleClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}
-   {'line_number': 15, 'parent': {'inherits': [], 'line_number': 8, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'SampleClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}, {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 11, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'SampleClass', 'pure_virtual': False, 'debug': 'SampleClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {...}, {'line_number': 22, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 22, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': False, 'name': 'v1', 'fundamental': True}], 'class': None, 'returns_reference': False, 'doxygen': '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///', 'const': False, 'name': 'meth2', 'pure_virtual': False, 'debug': 'int meth2 ( int v1 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 30, 'unresolved_parameters': True, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 30, 'constant': 1, 'reference': 1, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'const string &', 'method': {...}, 'parent': None, 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': True, 'name': 'v1', 'fundamental': 0}, {'line_number': 30, 'constant': 0, 'reference': 1, 'raw_type': 'vector<string>', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['vector<string>'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'template': 'vector<string>', 'mutable': False, 'type': 'vector<string> &', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 2', 'unresolved': True, 'name': 'v2', 'fundamental': 0}], 'class': None, 'returns_reference': False, 'doxygen': '/**\n* Method 3 description\n*\n* \\param v1 Variable 1\n* \\param v2 Variable 2\n*/', 'const': False, 'name': 'meth3', 'pure_virtual': False, 'debug': 'void meth3 ( const string & v1 , vector <string> & v2 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 37, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'unsigned int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'doxygen': '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/', 'const': False, 'name': 'meth4', 'pure_virtual': False, 'debug': 'unsigned int meth4 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'unsigned int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': [{'line_number': 39, 'parent': {...}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void *', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 1, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'meth5', 'pure_virtual': False, 'debug': 'void * meth5 ( ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}]}}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': False, 'rtnType': 'string', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'returns_unknown': True, 'doxygen': '/*!\n* Method 1\n*/', 'const': False, 'name': 'meth1', 'pure_virtual': False, 'debug': 'string meth1 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'string', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}
-   {'line_number': 22, 'parent': {'inherits': [], 'line_number': 8, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'SampleClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}, {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 11, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'SampleClass', 'pure_virtual': False, 'debug': 'SampleClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 15, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': False, 'rtnType': 'string', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'returns_unknown': True, 'doxygen': '/*!\n* Method 1\n*/', 'const': False, 'name': 'meth1', 'pure_virtual': False, 'debug': 'string meth1 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'string', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {...}, {'line_number': 30, 'unresolved_parameters': True, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 30, 'constant': 1, 'reference': 1, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'const string &', 'method': {...}, 'parent': None, 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': True, 'name': 'v1', 'fundamental': 0}, {'line_number': 30, 'constant': 0, 'reference': 1, 'raw_type': 'vector<string>', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['vector<string>'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'template': 'vector<string>', 'mutable': False, 'type': 'vector<string> &', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 2', 'unresolved': True, 'name': 'v2', 'fundamental': 0}], 'class': None, 'returns_reference': False, 'doxygen': '/**\n* Method 3 description\n*\n* \\param v1 Variable 1\n* \\param v2 Variable 2\n*/', 'const': False, 'name': 'meth3', 'pure_virtual': False, 'debug': 'void meth3 ( const string & v1 , vector <string> & v2 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 37, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'unsigned int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'doxygen': '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/', 'const': False, 'name': 'meth4', 'pure_virtual': False, 'debug': 'unsigned int meth4 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'unsigned int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': [{'line_number': 39, 'parent': {...}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void *', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 1, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'meth5', 'pure_virtual': False, 'debug': 'void * meth5 ( ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}]}}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 22, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': False, 'name': 'v1', 'fundamental': True}], 'class': None, 'returns_reference': False, 'doxygen': '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///', 'const': False, 'name': 'meth2', 'pure_virtual': False, 'debug': 'int meth2 ( int v1 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}
-   {'line_number': 30, 'unresolved_parameters': True, 'parent': {'inherits': [], 'line_number': 8, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'SampleClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}, {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 11, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'SampleClass', 'pure_virtual': False, 'debug': 'SampleClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 15, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': False, 'rtnType': 'string', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'returns_unknown': True, 'doxygen': '/*!\n* Method 1\n*/', 'const': False, 'name': 'meth1', 'pure_virtual': False, 'debug': 'string meth1 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'string', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 22, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 22, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': False, 'name': 'v1', 'fundamental': True}], 'class': None, 'returns_reference': False, 'doxygen': '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///', 'const': False, 'name': 'meth2', 'pure_virtual': False, 'debug': 'int meth2 ( int v1 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {...}, {'line_number': 37, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'unsigned int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'doxygen': '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/', 'const': False, 'name': 'meth4', 'pure_virtual': False, 'debug': 'unsigned int meth4 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'unsigned int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': [{'line_number': 39, 'parent': {...}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void *', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 1, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'meth5', 'pure_virtual': False, 'debug': 'void * meth5 ( ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}]}}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 30, 'constant': 1, 'reference': 1, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'const string &', 'method': {...}, 'parent': None, 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': True, 'name': 'v1', 'fundamental': 0}, {'line_number': 30, 'constant': 0, 'reference': 1, 'raw_type': 'vector<string>', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['vector<string>'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'template': 'vector<string>', 'mutable': False, 'type': 'vector<string> &', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 2', 'unresolved': True, 'name': 'v2', 'fundamental': 0}], 'class': None, 'returns_reference': False, 'doxygen': '/**\n* Method 3 description\n*\n* \\param v1 Variable 1\n* \\param v2 Variable 2\n*/', 'const': False, 'name': 'meth3', 'pure_virtual': False, 'debug': 'void meth3 ( const string & v1 , vector <string> & v2 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}
-   {'line_number': 37, 'parent': {'inherits': [], 'line_number': 8, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'SampleClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}, {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 11, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'SampleClass', 'pure_virtual': False, 'debug': 'SampleClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 15, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': False, 'rtnType': 'string', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'returns_unknown': True, 'doxygen': '/*!\n* Method 1\n*/', 'const': False, 'name': 'meth1', 'pure_virtual': False, 'debug': 'string meth1 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'string', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 22, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 22, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': False, 'name': 'v1', 'fundamental': True}], 'class': None, 'returns_reference': False, 'doxygen': '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///', 'const': False, 'name': 'meth2', 'pure_virtual': False, 'debug': 'int meth2 ( int v1 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 30, 'unresolved_parameters': True, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 30, 'constant': 1, 'reference': 1, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'const string &', 'method': {...}, 'parent': None, 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': True, 'name': 'v1', 'fundamental': 0}, {'line_number': 30, 'constant': 0, 'reference': 1, 'raw_type': 'vector<string>', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['vector<string>'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'template': 'vector<string>', 'mutable': False, 'type': 'vector<string> &', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 2', 'unresolved': True, 'name': 'v2', 'fundamental': 0}], 'class': None, 'returns_reference': False, 'doxygen': '/**\n* Method 3 description\n*\n* \\param v1 Variable 1\n* \\param v2 Variable 2\n*/', 'const': False, 'name': 'meth3', 'pure_virtual': False, 'debug': 'void meth3 ( const string & v1 , vector <string> & v2 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {...}], 'private': [{'line_number': 39, 'parent': {...}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void *', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 1, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'meth5', 'pure_virtual': False, 'debug': 'void * meth5 ( ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}]}}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'unsigned int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'doxygen': '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/', 'const': False, 'name': 'meth4', 'pure_virtual': False, 'debug': 'unsigned int meth4 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'unsigned int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}
-protected
-private
-    // Properties
-    {'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}
-    {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}
-    // Methods
-   {'line_number': 39, 'parent': {'inherits': [], 'line_number': 8, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'SampleClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}, {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 11, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'SampleClass', 'pure_virtual': False, 'debug': 'SampleClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 15, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': False, 'rtnType': 'string', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'returns_unknown': True, 'doxygen': '/*!\n* Method 1\n*/', 'const': False, 'name': 'meth1', 'pure_virtual': False, 'debug': 'string meth1 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'string', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 22, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 22, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': False, 'name': 'v1', 'fundamental': True}], 'class': None, 'returns_reference': False, 'doxygen': '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///', 'const': False, 'name': 'meth2', 'pure_virtual': False, 'debug': 'int meth2 ( int v1 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 30, 'unresolved_parameters': True, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 30, 'constant': 1, 'reference': 1, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'const string &', 'method': {...}, 'parent': None, 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': True, 'name': 'v1', 'fundamental': 0}, {'line_number': 30, 'constant': 0, 'reference': 1, 'raw_type': 'vector<string>', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['vector<string>'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'template': 'vector<string>', 'mutable': False, 'type': 'vector<string> &', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 2', 'unresolved': True, 'name': 'v2', 'fundamental': 0}], 'class': None, 'returns_reference': False, 'doxygen': '/**\n* Method 3 description\n*\n* \\param v1 Variable 1\n* \\param v2 Variable 2\n*/', 'const': False, 'name': 'meth3', 'pure_virtual': False, 'debug': 'void meth3 ( const string & v1 , vector <string> & v2 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 37, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'unsigned int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'doxygen': '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/', 'const': False, 'name': 'meth4', 'pure_virtual': False, 'debug': 'unsigned int meth4 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'unsigned int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': [{...}]}}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void *', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 1, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'meth5', 'pure_virtual': False, 'debug': 'void * meth5 ( ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}
-}
-
-class Alpha::AlphaClass
-{
-public
-    // Properties
-    {'raw_type': 'string', 'line_number': 55, 'typedef': None, 'unresolved': True, 'constant': 0, 'name': 'alphaString', 'parent': None, 'pointer': 0, 'namespace': 'Alpha::', 'function_pointer': 0, 'property_of_class': 'AlphaClass', 'static': 0, 'fundamental': 0, 'mutable': False, 'extern': False, 'typedefs': 0, 'array': 0, 'type': 'string', 'class': 0, 'reference': 0, 'aliases': ['string']}
-    // Methods
-   {'line_number': 51, 'parent': {'inherits': [], 'line_number': 48, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'AlphaClass', 'parent': None, 'abstract': False, 'namespace': 'Alpha', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [{'raw_type': 'string', 'line_number': 55, 'typedef': None, 'unresolved': True, 'constant': 0, 'name': 'alphaString', 'parent': None, 'pointer': 0, 'namespace': 'Alpha::', 'function_pointer': 0, 'property_of_class': 'AlphaClass', 'static': 0, 'fundamental': 0, 'mutable': False, 'extern': False, 'typedefs': 0, 'array': 0, 'type': 'string', 'class': 0, 'reference': 0, 'aliases': ['string']}], 'private': []}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{...}, {'line_number': 53, 'parent': {...}, 'defined': False, 'namespace': 'Alpha::', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'Alpha::AlphaClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'alphaMethod', 'pure_virtual': False, 'debug': 'void alphaMethod ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': []}}, 'defined': False, 'namespace': 'Alpha::', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'Alpha::AlphaClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'AlphaClass', 'pure_virtual': False, 'debug': 'AlphaClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}
-   {'line_number': 53, 'parent': {'inherits': [], 'line_number': 48, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'AlphaClass', 'parent': None, 'abstract': False, 'namespace': 'Alpha', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [{'raw_type': 'string', 'line_number': 55, 'typedef': None, 'unresolved': True, 'constant': 0, 'name': 'alphaString', 'parent': None, 'pointer': 0, 'namespace': 'Alpha::', 'function_pointer': 0, 'property_of_class': 'AlphaClass', 'static': 0, 'fundamental': 0, 'mutable': False, 'extern': False, 'typedefs': 0, 'array': 0, 'type': 'string', 'class': 0, 'reference': 0, 'aliases': ['string']}], 'private': []}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 51, 'parent': {...}, 'defined': False, 'namespace': 'Alpha::', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'Alpha::AlphaClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'AlphaClass', 'pure_virtual': False, 'debug': 'AlphaClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {...}], 'private': []}}, 'defined': False, 'namespace': 'Alpha::', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'Alpha::AlphaClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'alphaMethod', 'pure_virtual': False, 'debug': 'void alphaMethod ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}
-protected
-private
-}
-
-class Alpha::Omega::OmegaClass
-{
-public
-    // Properties
-    {'raw_type': 'string', 'line_number': 65, 'typedef': None, 'unresolved': True, 'constant': 0, 'name': 'omegaString', 'parent': None, 'pointer': 0, 'namespace': 'Alpha::Omega::', 'function_pointer': 0, 'property_of_class': 'OmegaClass', 'static': 0, 'fundamental': 0, 'mutable': False, 'extern': False, 'typedefs': 0, 'array': 0, 'type': 'string', 'class': 0, 'reference': 0, 'aliases': ['string']}
-    // Methods
-   {'line_number': 63, 'parent': {'inherits': [], 'line_number': 60, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'OmegaClass', 'parent': None, 'abstract': False, 'namespace': 'Alpha::Omega', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [{'raw_type': 'string', 'line_number': 65, 'typedef': None, 'unresolved': True, 'constant': 0, 'name': 'omegaString', 'parent': None, 'pointer': 0, 'namespace': 'Alpha::Omega::', 'function_pointer': 0, 'property_of_class': 'OmegaClass', 'static': 0, 'fundamental': 0, 'mutable': False, 'extern': False, 'typedefs': 0, 'array': 0, 'type': 'string', 'class': 0, 'reference': 0, 'aliases': ['string']}], 'private': []}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{...}], 'private': []}}, 'defined': False, 'namespace': 'Alpha::Omega::', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'Alpha::Omega::OmegaClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'OmegaClass', 'pure_virtual': False, 'debug': 'OmegaClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}
-protected
-private
-}
-
-// functions
-{'line_number': 70, 'static': False, 'rtnType': 'int', 'const': False, 'parameters': [{'line_number': 70, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {'line_number': 70, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'returns_pointer': 0, 'parameters': [...], 'class': None, 'returns_reference': False, 'const': False, 'name': 'sampleFreeFunction', 'pure_virtual': False, 'debug': 'int sampleFreeFunction ( int i ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': False, 'name': 'i', 'fundamental': True}], 'namespace': '', 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'override': False, 'final': False, 'friend': False, 'returns_class': False, 'extern': False, 'returns_pointer': 0, 'class': None, 'name': 'sampleFreeFunction', 'pure_virtual': False, 'explicit': False, 'returns_fundamental': True, 'constructor': False, 'debug': 'int sampleFreeFunction ( int i ) {', 'inline': False}
-{'line_number': 75, 'static': False, 'rtnType': 'int', 'const': False, 'parameters': [{'line_number': 75, 'constant': 0, 'reference': 0, 'raw_type': 'void', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'void', 'method': {'line_number': 75, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'returns_pointer': 0, 'parameters': [...], 'class': None, 'returns_reference': False, 'const': False, 'name': 'anotherFreeFunction', 'pure_virtual': False, 'debug': 'int anotherFreeFunction ( void ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': False, 'name': '', 'fundamental': True}], 'namespace': '', 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'override': False, 'final': False, 'friend': False, 'returns_class': False, 'extern': False, 'returns_pointer': 0, 'class': None, 'name': 'anotherFreeFunction', 'pure_virtual': False, 'explicit': False, 'returns_fundamental': True, 'constructor': False, 'debug': 'int anotherFreeFunction ( void ) ;', 'inline': False}
-
-Number of public methods 5
-Number of private properties 2
-Parameter Types for public method meth3 ['const string &', 'vector<string> &']
-
-Return type for meth1:
-string
-
-Doxygen for meth2:
-///
-/// Method 2 description
-///
-/// @param v1 Variable 1
-///
-
-Parameters for meth3:
-[{'line_number': 30, 'constant': 1, 'reference': 1, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'const string &', 'method': {'line_number': 30, 'unresolved_parameters': True, 'parent': {'inherits': [], 'line_number': 8, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'SampleClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}, {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 11, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'SampleClass', 'pure_virtual': False, 'debug': 'SampleClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 15, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': False, 'rtnType': 'string', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'returns_unknown': True, 'doxygen': '/*!\n* Method 1\n*/', 'const': False, 'name': 'meth1', 'pure_virtual': False, 'debug': 'string meth1 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'string', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 22, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 22, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': False, 'name': 'v1', 'fundamental': True}], 'class': None, 'returns_reference': False, 'doxygen': '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///', 'const': False, 'name': 'meth2', 'pure_virtual': False, 'debug': 'int meth2 ( int v1 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {...}, {'line_number': 37, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'unsigned int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'doxygen': '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/', 'const': False, 'name': 'meth4', 'pure_virtual': False, 'debug': 'unsigned int meth4 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'unsigned int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': [{'line_number': 39, 'parent': {...}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void *', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 1, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'meth5', 'pure_virtual': False, 'debug': 'void * meth5 ( ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}]}}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [...], 'class': None, 'returns_reference': False, 'doxygen': '/**\n* Method 3 description\n*\n* \\param v1 Variable 1\n* \\param v2 Variable 2\n*/', 'const': False, 'name': 'meth3', 'pure_virtual': False, 'debug': 'void meth3 ( const string & v1 , vector <string> & v2 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, 'parent': None, 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': True, 'name': 'v1', 'fundamental': 0}, {'line_number': 30, 'constant': 0, 'reference': 1, 'raw_type': 'vector<string>', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['vector<string>'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'template': 'vector<string>', 'mutable': False, 'type': 'vector<string> &', 'method': {'line_number': 30, 'unresolved_parameters': True, 'parent': {'inherits': [], 'line_number': 8, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'SampleClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}, {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 11, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'SampleClass', 'pure_virtual': False, 'debug': 'SampleClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 15, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': False, 'rtnType': 'string', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'returns_unknown': True, 'doxygen': '/*!\n* Method 1\n*/', 'const': False, 'name': 'meth1', 'pure_virtual': False, 'debug': 'string meth1 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'string', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 22, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 22, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': False, 'name': 'v1', 'fundamental': True}], 'class': None, 'returns_reference': False, 'doxygen': '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///', 'const': False, 'name': 'meth2', 'pure_virtual': False, 'debug': 'int meth2 ( int v1 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {...}, {'line_number': 37, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'unsigned int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'doxygen': '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/', 'const': False, 'name': 'meth4', 'pure_virtual': False, 'debug': 'unsigned int meth4 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'unsigned int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': [{'line_number': 39, 'parent': {...}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void *', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 1, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'meth5', 'pure_virtual': False, 'debug': 'void * meth5 ( ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}]}}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [...], 'class': None, 'returns_reference': False, 'doxygen': '/**\n* Method 3 description\n*\n* \\param v1 Variable 1\n* \\param v2 Variable 2\n*/', 'const': False, 'name': 'meth3', 'pure_virtual': False, 'debug': 'void meth3 ( const string & v1 , vector <string> & v2 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 2', 'unresolved': True, 'name': 'v2', 'fundamental': 0}]
-
-Doxygen for meth4:
-/**********************************
-* Method 4 description
-*
-* @return Return value
-*********************************/
-
-Return type for meth5:
-void *
-
-Doxygen type for prop1:
-/// prop1 description
-
-Type for prop5:
-int
-
-Namespace for AlphaClass is:
-Alpha
-
-Return type for alphaMethod is:
-void
-
-Namespace for OmegaClass is:
-Alpha::Omega
-
-Type for omegaString is:
-string
-
-Free functions are:
- sampleFreeFunction
- anotherFreeFunction
-
-#includes are:
- <vector>
- <string>
-
-#defines are:
- DEF_1 1
- OS_NAME "Linux"
-
-
-
-

Contributors

-
    -
  • Chris Love
  • -
  • HartsAntler
  • -
-
-
- - diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..627f849 --- /dev/null +++ b/README.rst @@ -0,0 +1,74 @@ +robotpy-cppheaderparser +======================= + +**robotpy-cppheaderparser is DEPRECATED, and we are no longer updating it**. +We will accept pull requests that have fixes and appropriate tests, but we +will no longer be making any fixes ourselves. + +We highly recommend all current and future users to migrate to cxxheaderparser, +which supports all the syntax that CppHeaderParser does and much much more. The +parser output is very different, but it is strictly typed and hopefully easier +to work with. You can find it at https://github.com/robotpy/cxxheaderparser, +or try the live interactive demo at https://robotpy.github.io/cxxheaderparser/ + +--------- + +CppHeaderParser is a pure python C++ header parser that parses C++ +headers and creates a data structure that you can use to do many types +of things. We’ve found it particularly useful for creating programs that +generate python wrappers around existing C++ programs. + +robotpy-cppheaderparser is a fork of the `CppHeaderParser`_ library +originally created by @senex. CppHeaderParser is an excellent library +and critical to some of the stuff we do in the RobotPy project. +Unfortunately, the maintainer seems to be busy, so +robotpy-cppheaderparser was born. + +We aim to maintain (some) compatibility with the existing code and make +improvements and bugfixes as we need them -- though some decisions made +early on in this code's development means some compatibility may be broken +as things get fixed. + +If you find an bug, we encourage you to submit a pull request! New +changes will only be accepted if there are tests to cover the change you +made (and if they don’t break existing tests). + +.. note:: CppHeaderParser only does some very minimal interpretation of + preprocessor directives -- and we're looking at removing some + of that from this library. If you need anything complex, you + should preprocess the code yourself. You can use the excellent + pure python preprocessor `pcpp`_, or the preprocessing facilities + provided by your favorite compiler. + +Documentation +------------- + +Documentation can be found at https://cppheaderparser.readthedocs.io + +Install +------- + +:: + + pip install robotpy-cppheaderparser + +License +------- + +BSD License + +Authors +------- + +Originally developed by Jashua Cloutier, this fork is maintained by the +RobotPy project. + +Past contributors include: + +* Jashua Cloutier +* Chris Love +* HartsAntler + +.. _CppHeaderParser: https://bitbucket.org/senex/cppheaderparser + +.. _pcpp: https://github.com/ned14/pcpp diff --git a/README.txt b/README.txt deleted file mode 100644 index f7de4dd..0000000 --- a/README.txt +++ /dev/null @@ -1,267 +0,0 @@ -Python package "CppHeaderParser" --------------------------------- -**Purpose:** Parse C++ header files and generate a data structure representing the class - -**Author:** Jashua Cloutier - -**Licence:** BSD - -**External modules required:** PLY - -**Quick start**:: - - #include - #include - - #define DEF_1 1 - #define OS_NAME "Linux" - - using namespace std; - class SampleClass - { - public: - SampleClass(); - /*! - * Method 1 - */ - string meth1(); - - /// - /// Method 2 description - /// - /// @param v1 Variable 1 - /// - int meth2(int v1); - - /** - * Method 3 description - * - * \param v1 Variable 1 - * \param v2 Variable 2 - */ - void meth3(const string & v1, vector & v2); - - /********************************** - * Method 4 description - * - * @return Return value - *********************************/ - unsigned int meth4(); - private: - void * meth5(){return NULL}; - - /// prop1 description - string prop1; - //! prop5 description - int prop5; - }; - namespace Alpha - { - class AlphaClass - { - public: - AlphaClass(); - - void alphaMethod(); - - string alphaString; - }; - - namespace Omega - { - class OmegaClass - { - public: - OmegaClass(); - - string omegaString; - }; - }; - } - - int sampleFreeFunction(int i) - { - return i + 1; - } - - int anotherFreeFunction(void); - } - - -**Python code**:: - - #!/usr/bin/python - import sys - sys.path = ["../"] + sys.path - import CppHeaderParser - try: - cppHeader = CppHeaderParser.CppHeader("SampleClass.h") - except CppHeaderParser.CppParseError as e: - print(e) - sys.exit(1) - - print("CppHeaderParser view of %s"%cppHeader) - - sampleClass = cppHeader.classes["SampleClass"] - print("Number of public methods %d"%(len(sampleClass["methods"]["public"]))) - print("Number of private properties %d"%(len(sampleClass["properties"]["private"]))) - meth3 = [m for m in sampleClass["methods"]["public"] if m["name"] == "meth3"][0] #get meth3 - meth3ParamTypes = [t["type"] for t in meth3["parameters"]] #get meth3s parameters - print("Parameter Types for public method meth3 %s"%(meth3ParamTypes)) - - print("\nReturn type for meth1:") - print(cppHeader.classes["SampleClass"]["methods"]["public"][1]["rtnType"]) - - print("\nDoxygen for meth2:") - print(cppHeader.classes["SampleClass"]["methods"]["public"][2]["doxygen"]) - - print("\nParameters for meth3:") - print(cppHeader.classes["SampleClass"]["methods"]["public"][3]["parameters"]) - - print("\nDoxygen for meth4:") - print(cppHeader.classes["SampleClass"]["methods"]["public"][4]["doxygen"]) - - print("\nReturn type for meth5:") - print(cppHeader.classes["SampleClass"]["methods"]["private"][0]["rtnType"]) - - print("\nDoxygen type for prop1:") - print(cppHeader.classes["SampleClass"]["properties"]["private"][0]["doxygen"]) - - print("\nType for prop5:") - print(cppHeader.classes["SampleClass"]["properties"]["private"][1]["type"]) - - print("\nNamespace for AlphaClass is:") - print(cppHeader.classes["AlphaClass"]["namespace"]) - - print("\nReturn type for alphaMethod is:") - print(cppHeader.classes["AlphaClass"]["methods"]["public"][0]["rtnType"]) - - print("\nNamespace for OmegaClass is:") - print(cppHeader.classes["OmegaClass"]["namespace"]) - - print("\nType for omegaString is:") - print(cppHeader.classes["AlphaClass"]["properties"]["public"][0]["type"]) - - print("\nFree functions are:") - for func in cppHeader.functions: - print(" %s"%func["name"]) - - print("\n#includes are:") - for incl in cppHeader.includes: - print(" %s"%incl) - - print("\n#defines are:") - for define in cppHeader.defines: - print(" %s"%define) - - -**Output**:: - - CppHeaderParser view of class SampleClass - { - public - // Methods - {'line_number': 11, 'parent': {'inherits': [], 'line_number': 8, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'SampleClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}, {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{...}, {'line_number': 15, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': False, 'rtnType': 'string', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'returns_unknown': True, 'doxygen': '/*!\n* Method 1\n*/', 'const': False, 'name': 'meth1', 'pure_virtual': False, 'debug': 'string meth1 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'string', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 22, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 22, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': False, 'name': 'v1', 'fundamental': True}], 'class': None, 'returns_reference': False, 'doxygen': '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///', 'const': False, 'name': 'meth2', 'pure_virtual': False, 'debug': 'int meth2 ( int v1 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 30, 'unresolved_parameters': True, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 30, 'constant': 1, 'reference': 1, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'const string &', 'method': {...}, 'parent': None, 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': True, 'name': 'v1', 'fundamental': 0}, {'line_number': 30, 'constant': 0, 'reference': 1, 'raw_type': 'vector', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['vector'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'template': 'vector', 'mutable': False, 'type': 'vector &', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 2', 'unresolved': True, 'name': 'v2', 'fundamental': 0}], 'class': None, 'returns_reference': False, 'doxygen': '/**\n* Method 3 description\n*\n* \\param v1 Variable 1\n* \\param v2 Variable 2\n*/', 'const': False, 'name': 'meth3', 'pure_virtual': False, 'debug': 'void meth3 ( const string & v1 , vector & v2 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 37, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'unsigned int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'doxygen': '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/', 'const': False, 'name': 'meth4', 'pure_virtual': False, 'debug': 'unsigned int meth4 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'unsigned int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': [{'line_number': 39, 'parent': {...}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void *', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 1, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'meth5', 'pure_virtual': False, 'debug': 'void * meth5 ( ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}]}}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'SampleClass', 'pure_virtual': False, 'debug': 'SampleClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False} - {'line_number': 15, 'parent': {'inherits': [], 'line_number': 8, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'SampleClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}, {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 11, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'SampleClass', 'pure_virtual': False, 'debug': 'SampleClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {...}, {'line_number': 22, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 22, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': False, 'name': 'v1', 'fundamental': True}], 'class': None, 'returns_reference': False, 'doxygen': '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///', 'const': False, 'name': 'meth2', 'pure_virtual': False, 'debug': 'int meth2 ( int v1 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 30, 'unresolved_parameters': True, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 30, 'constant': 1, 'reference': 1, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'const string &', 'method': {...}, 'parent': None, 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': True, 'name': 'v1', 'fundamental': 0}, {'line_number': 30, 'constant': 0, 'reference': 1, 'raw_type': 'vector', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['vector'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'template': 'vector', 'mutable': False, 'type': 'vector &', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 2', 'unresolved': True, 'name': 'v2', 'fundamental': 0}], 'class': None, 'returns_reference': False, 'doxygen': '/**\n* Method 3 description\n*\n* \\param v1 Variable 1\n* \\param v2 Variable 2\n*/', 'const': False, 'name': 'meth3', 'pure_virtual': False, 'debug': 'void meth3 ( const string & v1 , vector & v2 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 37, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'unsigned int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'doxygen': '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/', 'const': False, 'name': 'meth4', 'pure_virtual': False, 'debug': 'unsigned int meth4 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'unsigned int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': [{'line_number': 39, 'parent': {...}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void *', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 1, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'meth5', 'pure_virtual': False, 'debug': 'void * meth5 ( ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}]}}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': False, 'rtnType': 'string', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'returns_unknown': True, 'doxygen': '/*!\n* Method 1\n*/', 'const': False, 'name': 'meth1', 'pure_virtual': False, 'debug': 'string meth1 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'string', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False} - {'line_number': 22, 'parent': {'inherits': [], 'line_number': 8, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'SampleClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}, {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 11, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'SampleClass', 'pure_virtual': False, 'debug': 'SampleClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 15, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': False, 'rtnType': 'string', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'returns_unknown': True, 'doxygen': '/*!\n* Method 1\n*/', 'const': False, 'name': 'meth1', 'pure_virtual': False, 'debug': 'string meth1 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'string', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {...}, {'line_number': 30, 'unresolved_parameters': True, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 30, 'constant': 1, 'reference': 1, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'const string &', 'method': {...}, 'parent': None, 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': True, 'name': 'v1', 'fundamental': 0}, {'line_number': 30, 'constant': 0, 'reference': 1, 'raw_type': 'vector', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['vector'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'template': 'vector', 'mutable': False, 'type': 'vector &', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 2', 'unresolved': True, 'name': 'v2', 'fundamental': 0}], 'class': None, 'returns_reference': False, 'doxygen': '/**\n* Method 3 description\n*\n* \\param v1 Variable 1\n* \\param v2 Variable 2\n*/', 'const': False, 'name': 'meth3', 'pure_virtual': False, 'debug': 'void meth3 ( const string & v1 , vector & v2 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 37, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'unsigned int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'doxygen': '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/', 'const': False, 'name': 'meth4', 'pure_virtual': False, 'debug': 'unsigned int meth4 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'unsigned int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': [{'line_number': 39, 'parent': {...}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void *', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 1, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'meth5', 'pure_virtual': False, 'debug': 'void * meth5 ( ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}]}}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 22, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': False, 'name': 'v1', 'fundamental': True}], 'class': None, 'returns_reference': False, 'doxygen': '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///', 'const': False, 'name': 'meth2', 'pure_virtual': False, 'debug': 'int meth2 ( int v1 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False} - {'line_number': 30, 'unresolved_parameters': True, 'parent': {'inherits': [], 'line_number': 8, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'SampleClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}, {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 11, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'SampleClass', 'pure_virtual': False, 'debug': 'SampleClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 15, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': False, 'rtnType': 'string', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'returns_unknown': True, 'doxygen': '/*!\n* Method 1\n*/', 'const': False, 'name': 'meth1', 'pure_virtual': False, 'debug': 'string meth1 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'string', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 22, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 22, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': False, 'name': 'v1', 'fundamental': True}], 'class': None, 'returns_reference': False, 'doxygen': '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///', 'const': False, 'name': 'meth2', 'pure_virtual': False, 'debug': 'int meth2 ( int v1 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {...}, {'line_number': 37, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'unsigned int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'doxygen': '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/', 'const': False, 'name': 'meth4', 'pure_virtual': False, 'debug': 'unsigned int meth4 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'unsigned int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': [{'line_number': 39, 'parent': {...}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void *', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 1, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'meth5', 'pure_virtual': False, 'debug': 'void * meth5 ( ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}]}}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 30, 'constant': 1, 'reference': 1, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'const string &', 'method': {...}, 'parent': None, 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': True, 'name': 'v1', 'fundamental': 0}, {'line_number': 30, 'constant': 0, 'reference': 1, 'raw_type': 'vector', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['vector'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'template': 'vector', 'mutable': False, 'type': 'vector &', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 2', 'unresolved': True, 'name': 'v2', 'fundamental': 0}], 'class': None, 'returns_reference': False, 'doxygen': '/**\n* Method 3 description\n*\n* \\param v1 Variable 1\n* \\param v2 Variable 2\n*/', 'const': False, 'name': 'meth3', 'pure_virtual': False, 'debug': 'void meth3 ( const string & v1 , vector & v2 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False} - {'line_number': 37, 'parent': {'inherits': [], 'line_number': 8, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'SampleClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}, {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 11, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'SampleClass', 'pure_virtual': False, 'debug': 'SampleClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 15, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': False, 'rtnType': 'string', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'returns_unknown': True, 'doxygen': '/*!\n* Method 1\n*/', 'const': False, 'name': 'meth1', 'pure_virtual': False, 'debug': 'string meth1 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'string', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 22, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 22, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': False, 'name': 'v1', 'fundamental': True}], 'class': None, 'returns_reference': False, 'doxygen': '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///', 'const': False, 'name': 'meth2', 'pure_virtual': False, 'debug': 'int meth2 ( int v1 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 30, 'unresolved_parameters': True, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 30, 'constant': 1, 'reference': 1, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'const string &', 'method': {...}, 'parent': None, 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': True, 'name': 'v1', 'fundamental': 0}, {'line_number': 30, 'constant': 0, 'reference': 1, 'raw_type': 'vector', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['vector'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'template': 'vector', 'mutable': False, 'type': 'vector &', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 2', 'unresolved': True, 'name': 'v2', 'fundamental': 0}], 'class': None, 'returns_reference': False, 'doxygen': '/**\n* Method 3 description\n*\n* \\param v1 Variable 1\n* \\param v2 Variable 2\n*/', 'const': False, 'name': 'meth3', 'pure_virtual': False, 'debug': 'void meth3 ( const string & v1 , vector & v2 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {...}], 'private': [{'line_number': 39, 'parent': {...}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void *', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 1, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'meth5', 'pure_virtual': False, 'debug': 'void * meth5 ( ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}]}}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'unsigned int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'doxygen': '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/', 'const': False, 'name': 'meth4', 'pure_virtual': False, 'debug': 'unsigned int meth4 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'unsigned int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False} - protected - private - // Properties - {'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0} - {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True} - // Methods - {'line_number': 39, 'parent': {'inherits': [], 'line_number': 8, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'SampleClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}, {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 11, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'SampleClass', 'pure_virtual': False, 'debug': 'SampleClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 15, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': False, 'rtnType': 'string', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'returns_unknown': True, 'doxygen': '/*!\n* Method 1\n*/', 'const': False, 'name': 'meth1', 'pure_virtual': False, 'debug': 'string meth1 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'string', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 22, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 22, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': False, 'name': 'v1', 'fundamental': True}], 'class': None, 'returns_reference': False, 'doxygen': '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///', 'const': False, 'name': 'meth2', 'pure_virtual': False, 'debug': 'int meth2 ( int v1 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 30, 'unresolved_parameters': True, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 30, 'constant': 1, 'reference': 1, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'const string &', 'method': {...}, 'parent': None, 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': True, 'name': 'v1', 'fundamental': 0}, {'line_number': 30, 'constant': 0, 'reference': 1, 'raw_type': 'vector', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['vector'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'template': 'vector', 'mutable': False, 'type': 'vector &', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 2', 'unresolved': True, 'name': 'v2', 'fundamental': 0}], 'class': None, 'returns_reference': False, 'doxygen': '/**\n* Method 3 description\n*\n* \\param v1 Variable 1\n* \\param v2 Variable 2\n*/', 'const': False, 'name': 'meth3', 'pure_virtual': False, 'debug': 'void meth3 ( const string & v1 , vector & v2 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 37, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'unsigned int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'doxygen': '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/', 'const': False, 'name': 'meth4', 'pure_virtual': False, 'debug': 'unsigned int meth4 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'unsigned int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': [{...}]}}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void *', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 1, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'meth5', 'pure_virtual': False, 'debug': 'void * meth5 ( ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False} - } - - class Alpha::AlphaClass - { - public - // Properties - {'raw_type': 'string', 'line_number': 55, 'typedef': None, 'unresolved': True, 'constant': 0, 'name': 'alphaString', 'parent': None, 'pointer': 0, 'namespace': 'Alpha::', 'function_pointer': 0, 'property_of_class': 'AlphaClass', 'static': 0, 'fundamental': 0, 'mutable': False, 'extern': False, 'typedefs': 0, 'array': 0, 'type': 'string', 'class': 0, 'reference': 0, 'aliases': ['string']} - // Methods - {'line_number': 51, 'parent': {'inherits': [], 'line_number': 48, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'AlphaClass', 'parent': None, 'abstract': False, 'namespace': 'Alpha', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [{'raw_type': 'string', 'line_number': 55, 'typedef': None, 'unresolved': True, 'constant': 0, 'name': 'alphaString', 'parent': None, 'pointer': 0, 'namespace': 'Alpha::', 'function_pointer': 0, 'property_of_class': 'AlphaClass', 'static': 0, 'fundamental': 0, 'mutable': False, 'extern': False, 'typedefs': 0, 'array': 0, 'type': 'string', 'class': 0, 'reference': 0, 'aliases': ['string']}], 'private': []}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{...}, {'line_number': 53, 'parent': {...}, 'defined': False, 'namespace': 'Alpha::', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'Alpha::AlphaClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'alphaMethod', 'pure_virtual': False, 'debug': 'void alphaMethod ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': []}}, 'defined': False, 'namespace': 'Alpha::', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'Alpha::AlphaClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'AlphaClass', 'pure_virtual': False, 'debug': 'AlphaClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False} - {'line_number': 53, 'parent': {'inherits': [], 'line_number': 48, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'AlphaClass', 'parent': None, 'abstract': False, 'namespace': 'Alpha', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [{'raw_type': 'string', 'line_number': 55, 'typedef': None, 'unresolved': True, 'constant': 0, 'name': 'alphaString', 'parent': None, 'pointer': 0, 'namespace': 'Alpha::', 'function_pointer': 0, 'property_of_class': 'AlphaClass', 'static': 0, 'fundamental': 0, 'mutable': False, 'extern': False, 'typedefs': 0, 'array': 0, 'type': 'string', 'class': 0, 'reference': 0, 'aliases': ['string']}], 'private': []}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 51, 'parent': {...}, 'defined': False, 'namespace': 'Alpha::', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'Alpha::AlphaClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'AlphaClass', 'pure_virtual': False, 'debug': 'AlphaClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {...}], 'private': []}}, 'defined': False, 'namespace': 'Alpha::', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'Alpha::AlphaClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'alphaMethod', 'pure_virtual': False, 'debug': 'void alphaMethod ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False} - protected - private - } - - class Alpha::Omega::OmegaClass - { - public - // Properties - {'raw_type': 'string', 'line_number': 65, 'typedef': None, 'unresolved': True, 'constant': 0, 'name': 'omegaString', 'parent': None, 'pointer': 0, 'namespace': 'Alpha::Omega::', 'function_pointer': 0, 'property_of_class': 'OmegaClass', 'static': 0, 'fundamental': 0, 'mutable': False, 'extern': False, 'typedefs': 0, 'array': 0, 'type': 'string', 'class': 0, 'reference': 0, 'aliases': ['string']} - // Methods - {'line_number': 63, 'parent': {'inherits': [], 'line_number': 60, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'OmegaClass', 'parent': None, 'abstract': False, 'namespace': 'Alpha::Omega', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [{'raw_type': 'string', 'line_number': 65, 'typedef': None, 'unresolved': True, 'constant': 0, 'name': 'omegaString', 'parent': None, 'pointer': 0, 'namespace': 'Alpha::Omega::', 'function_pointer': 0, 'property_of_class': 'OmegaClass', 'static': 0, 'fundamental': 0, 'mutable': False, 'extern': False, 'typedefs': 0, 'array': 0, 'type': 'string', 'class': 0, 'reference': 0, 'aliases': ['string']}], 'private': []}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{...}], 'private': []}}, 'defined': False, 'namespace': 'Alpha::Omega::', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'Alpha::Omega::OmegaClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'OmegaClass', 'pure_virtual': False, 'debug': 'OmegaClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False} - protected - private - } - - // functions - {'line_number': 70, 'static': False, 'rtnType': 'int', 'const': False, 'parameters': [{'line_number': 70, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {'line_number': 70, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'returns_pointer': 0, 'parameters': [...], 'class': None, 'returns_reference': False, 'const': False, 'name': 'sampleFreeFunction', 'pure_virtual': False, 'debug': 'int sampleFreeFunction ( int i ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': False, 'name': 'i', 'fundamental': True}], 'namespace': '', 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'override': False, 'final': False, 'friend': False, 'returns_class': False, 'extern': False, 'returns_pointer': 0, 'class': None, 'name': 'sampleFreeFunction', 'pure_virtual': False, 'explicit': False, 'returns_fundamental': True, 'constructor': False, 'debug': 'int sampleFreeFunction ( int i ) {', 'inline': False} - {'line_number': 75, 'static': False, 'rtnType': 'int', 'const': False, 'parameters': [{'line_number': 75, 'constant': 0, 'reference': 0, 'raw_type': 'void', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'void', 'method': {'line_number': 75, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'returns_pointer': 0, 'parameters': [...], 'class': None, 'returns_reference': False, 'const': False, 'name': 'anotherFreeFunction', 'pure_virtual': False, 'debug': 'int anotherFreeFunction ( void ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': False, 'name': '', 'fundamental': True}], 'namespace': '', 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'override': False, 'final': False, 'friend': False, 'returns_class': False, 'extern': False, 'returns_pointer': 0, 'class': None, 'name': 'anotherFreeFunction', 'pure_virtual': False, 'explicit': False, 'returns_fundamental': True, 'constructor': False, 'debug': 'int anotherFreeFunction ( void ) ;', 'inline': False} - - Number of public methods 5 - Number of private properties 2 - Parameter Types for public method meth3 ['const string &', 'vector &'] - - Return type for meth1: - string - - Doxygen for meth2: - /// - /// Method 2 description - /// - /// @param v1 Variable 1 - /// - - Parameters for meth3: - [{'line_number': 30, 'constant': 1, 'reference': 1, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'const string &', 'method': {'line_number': 30, 'unresolved_parameters': True, 'parent': {'inherits': [], 'line_number': 8, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'SampleClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}, {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 11, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'SampleClass', 'pure_virtual': False, 'debug': 'SampleClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 15, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': False, 'rtnType': 'string', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'returns_unknown': True, 'doxygen': '/*!\n* Method 1\n*/', 'const': False, 'name': 'meth1', 'pure_virtual': False, 'debug': 'string meth1 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'string', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 22, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 22, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': False, 'name': 'v1', 'fundamental': True}], 'class': None, 'returns_reference': False, 'doxygen': '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///', 'const': False, 'name': 'meth2', 'pure_virtual': False, 'debug': 'int meth2 ( int v1 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {...}, {'line_number': 37, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'unsigned int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'doxygen': '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/', 'const': False, 'name': 'meth4', 'pure_virtual': False, 'debug': 'unsigned int meth4 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'unsigned int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': [{'line_number': 39, 'parent': {...}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void *', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 1, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'meth5', 'pure_virtual': False, 'debug': 'void * meth5 ( ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}]}}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [...], 'class': None, 'returns_reference': False, 'doxygen': '/**\n* Method 3 description\n*\n* \\param v1 Variable 1\n* \\param v2 Variable 2\n*/', 'const': False, 'name': 'meth3', 'pure_virtual': False, 'debug': 'void meth3 ( const string & v1 , vector & v2 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, 'parent': None, 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': True, 'name': 'v1', 'fundamental': 0}, {'line_number': 30, 'constant': 0, 'reference': 1, 'raw_type': 'vector', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['vector'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'template': 'vector', 'mutable': False, 'type': 'vector &', 'method': {'line_number': 30, 'unresolved_parameters': True, 'parent': {'inherits': [], 'line_number': 8, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'SampleClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 42, 'constant': 0, 'reference': 0, 'raw_type': 'string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'string', 'property_of_class': 'SampleClass', 'parent': None, 'unresolved': True, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '/// prop1 description', 'name': 'prop1', 'fundamental': 0}, {'line_number': 44, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'SampleClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'unresolved': False, 'typedefs': 0, 'extern': False, 'class': 0, 'doxygen': '//! prop5 description', 'name': 'prop5', 'fundamental': True}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 11, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'SampleClass', 'pure_virtual': False, 'debug': 'SampleClass ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 15, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': False, 'rtnType': 'string', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'returns_unknown': True, 'doxygen': '/*!\n* Method 1\n*/', 'const': False, 'name': 'meth1', 'pure_virtual': False, 'debug': 'string meth1 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'string', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {'line_number': 22, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [{'line_number': 22, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'method': {...}, 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 1', 'unresolved': False, 'name': 'v1', 'fundamental': True}], 'class': None, 'returns_reference': False, 'doxygen': '///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///', 'const': False, 'name': 'meth2', 'pure_virtual': False, 'debug': 'int meth2 ( int v1 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {...}, {'line_number': 37, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'unsigned int', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'doxygen': '/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/', 'const': False, 'name': 'meth4', 'pure_virtual': False, 'debug': 'unsigned int meth4 ( ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'unsigned int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': [{'line_number': 39, 'parent': {...}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void *', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 1, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'meth5', 'pure_virtual': False, 'debug': 'void * meth5 ( ) {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}]}}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'SampleClass', 'returns_pointer': 0, 'parameters': [...], 'class': None, 'returns_reference': False, 'doxygen': '/**\n* Method 3 description\n*\n* \\param v1 Variable 1\n* \\param v2 Variable 2\n*/', 'const': False, 'name': 'meth3', 'pure_virtual': False, 'debug': 'void meth3 ( const string & v1 , vector & v2 ) ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'void', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'desc': 'Variable 2', 'unresolved': True, 'name': 'v2', 'fundamental': 0}] - - Doxygen for meth4: - /********************************** - * Method 4 description - * - * @return Return value - *********************************/ - - Return type for meth5: - void * - - Doxygen type for prop1: - /// prop1 description - - Type for prop5: - int - - Namespace for AlphaClass is: - Alpha - - Return type for alphaMethod is: - void - - Namespace for OmegaClass is: - Alpha::Omega - - Type for omegaString is: - string - - Free functions are: - sampleFreeFunction - anotherFreeFunction - - #includes are: - - - - #defines are: - DEF_1 1 - OS_NAME "Linux" - - - -Contributors ------------- -* Chris Love -* HartsAntler diff --git a/doc_generator.py b/doc_generator.py deleted file mode 100644 index 2cfd7d2..0000000 --- a/doc_generator.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/python -# Generate documenation -# * README.txt -# * README.html -import sys - -def gen_readme_html(): - """generate README.html""" - import cgi - f = open("templates/README.html").read() - sampleClass = open("CppHeaderParser/examples/SampleClass.h").read() - readSampleClass = open("CppHeaderParser/examples/readSampleClass.py").read() - - f = f.replace("{SAMPLE_CLASS_H}", cgi.escape(sampleClass)) - f = f.replace("{READ_SAMPLE_CLASS_PY}", cgi.escape(readSampleClass)) - f = f.replace("{READ_SAMPLE_CLASS_PY_OUTPUT}", cgi.escape(get_sample_class_output())) - open("README.html", "wa").write(f) - - -def gen_readme_txt(): - """generate README.txt""" - import cgi - f = open("templates/README.txt").read() - sampleClass = open("CppHeaderParser/examples/SampleClass.h").read() - readSampleClass = open("CppHeaderParser/examples/readSampleClass.py").read() - - f = f.replace("{SAMPLE_CLASS_H}", " " + sampleClass.replace("\n", "\n ")) - f = f.replace("{READ_SAMPLE_CLASS_PY}", " " + readSampleClass.replace("\n", "\n ")) - f = f.replace("{READ_SAMPLE_CLASS_PY_OUTPUT}", " " + get_sample_class_output().replace("\n", "\n ")) - open("README.txt", "wa").write(f) - print "wrote README.txt" - - import docutils.core - h = docutils.core.publish_string(source=open("README.txt").read(), writer_name='html') - h = h.replace("", "/*customization*/\npre.literal-block{\ncolor: #6A6A6A;\n}\n\n") - h = h.replace('
', '
')
-    open("README.html", "wa").write(h)
-    print "wrote README.html"
-
-
-def get_sample_class_output():
-    import subprocess
-    return subprocess.Popen(["python", "readSampleClass.py"],
-        stdout=subprocess.PIPE,
-        cwd="CppHeaderParser/examples"
-        ).communicate()[0]
-
-
-
-
-if __name__ == "__main__":
-    gen_readme_txt()
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..b8b9c15
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,177 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+	@echo "Please use \`make ' where  is one of"
+	@echo "  html       to make standalone HTML files"
+	@echo "  dirhtml    to make HTML files named index.html in directories"
+	@echo "  singlehtml to make a single large HTML file"
+	@echo "  pickle     to make pickle files"
+	@echo "  json       to make JSON files"
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
+	@echo "  qthelp     to make HTML files and a qthelp project"
+	@echo "  devhelp    to make HTML files and a Devhelp project"
+	@echo "  epub       to make an epub"
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+	@echo "  text       to make text files"
+	@echo "  man        to make manual pages"
+	@echo "  texinfo    to make Texinfo files"
+	@echo "  info       to make Texinfo files and run them through makeinfo"
+	@echo "  gettext    to make PO message catalogs"
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  xml        to make Docutils-native XML files"
+	@echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
+	@echo "  linkcheck  to check all external links for integrity"
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+	rm -rf $(BUILDDIR)/*
+
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+	@echo
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/sphinx.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/sphinx.qhc"
+
+devhelp:
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+	@echo
+	@echo "Build finished."
+	@echo "To view the help file:"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/sphinx"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/sphinx"
+	@echo "# devhelp"
+
+epub:
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+	@echo
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
+	      "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through pdflatex..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+latexpdfja:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through platex and dvipdfmx..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+	@echo
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+	@echo
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo
+	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+	@echo "Run \`make' in that directory to run these through makeinfo" \
+	      "(use \`make info' here to do that automatically)."
+
+info:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo "Running Texinfo files through makeinfo..."
+	make -C $(BUILDDIR)/texinfo info
+	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+	@echo
+	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."
+
+xml:
+	$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+	@echo
+	@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+pseudoxml:
+	$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+	@echo
+	@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
diff --git a/docs/api.rst b/docs/api.rst
new file mode 100644
index 0000000..f3d83b8
--- /dev/null
+++ b/docs/api.rst
@@ -0,0 +1,39 @@
+API
+===
+
+To parse a header file and retrieve the resulting data structure, you'll
+want to use the :class:`.CppHeader` object::
+
+    import CppHeaderParser
+
+    header = CppHeaderParser.CppHeader("path/to/header.h")
+
+Below is some documentation of the various object types that CppHeaderParser
+will generated after parsing a header file. The documentation is not yet
+currently comprehensive, so the best way to see what gets generated is
+by printing out the JSON representation:
+
+.. code-block:: sh
+
+   python -m CppHeaderParser.tojson /path/to/header.h
+
+.. warning:: CppHeaderParser is not safe to use from multiple threads
+
+.. note:: CppHeaderParser only does some very minimal interpretation of
+          preprocessor directives -- and we're looking at removing some
+          of that from this library. If you need anything complex, you
+          should preprocess the code yourself. You can use the excellent
+          pure python preprocessor `pcpp`_, or the preprocessing facilities
+          provided by your favorite compiler.
+
+CppHeaderParser
+---------------
+
+.. automodule:: CppHeaderParser.CppHeaderParser
+   :members: CppBaseDecl, CppClass, CppEnum, CppHeader, CppMethod, CppParseError,
+             CppTemplateParam, CppUnion, CppVariable, TagStr,
+             ignoreSymbols
+   :undoc-members:
+   :show-inheritance:
+
+.. _pcpp: https://github.com/ned14/pcpp
\ No newline at end of file
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..cc167b2
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,339 @@
+import sys
+import os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.abspath(".."))
+
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = ["sphinx.ext.autodoc", "sphinx.ext.viewcode"]
+
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ["_templates"]
+
+# The suffix of source filenames.
+source_suffix = ".rst"
+
+# The encoding of source files.
+# source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = "index"
+
+# General information about the project.
+project = "robotpy-cppheaderparser"
+copyright = "2019 RobotPy Development Team"
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+
+import CppHeaderParser
+
+# The short X.Y version.
+version = CppHeaderParser.__version__
+# The full version, including alpha/beta/rc tags.
+release = version
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+# language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+# today = ''
+# Else, today_fmt is used as the format for a strftime call.
+# today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ["_build"]
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+# default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+# add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+# add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+# show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = "sphinx"
+
+# A list of ignored prefixes for module index sorting.
+# modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+# keep_warnings = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+# html_theme = 'default'
+
+# on_rtd is whether we are on readthedocs.org, this line of code grabbed from docs.readthedocs.org
+on_rtd = os.environ.get("READTHEDOCS", None) == "True"
+
+if not on_rtd:  # only import and set the theme if we're building docs locally
+    import sphinx_rtd_theme
+
+    html_theme = "sphinx_rtd_theme"
+    html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
+else:
+    html_theme = "default"
+
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+# html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+# html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# " v documentation".
+# html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+# html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+# html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+# html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+# html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+# html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+# html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+# html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+# html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+# html_additional_pages = {}
+
+# If false, no module index is generated.
+# html_domain_indices = True
+
+# If false, no index is generated.
+# html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+# html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+# html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+# html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+# html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a  tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+# html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+# html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = "sphinxdoc"
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+    # The paper size ('letterpaper' or 'a4paper').
+    #'papersize': 'letterpaper',
+    # The font size ('10pt', '11pt' or '12pt').
+    #'pointsize': '10pt',
+    # Additional stuff for the LaTeX preamble.
+    #'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+    (
+        "index",
+        "sphinx.tex",
+        "robotpy-cppheaderparser Documentation",
+        "Author",
+        "manual",
+    )
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+# latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+# latex_use_parts = False
+
+# If true, show page references after internal links.
+# latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+# latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+# latex_appendices = []
+
+# If false, no module index is generated.
+# latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ("index", "sphinx", "robotpy-cppheaderparser Documentation", ["Author"], 1)
+]
+
+# If true, show URL addresses after external links.
+# man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+    (
+        "index",
+        "sphinx",
+        "robotpy-cppheaderparser Documentation",
+        "Author",
+        "sphinx",
+        "One line description of project.",
+        "Miscellaneous",
+    )
+]
+
+# Documents to append as an appendix to all manuals.
+# texinfo_appendices = []
+
+# If false, no module index is generated.
+# texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+# texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+# texinfo_no_detailmenu = False
+
+
+# -- Options for Epub output ----------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = "robotpy-cppheaderparser"
+epub_author = "RobotPy Development Team"
+epub_publisher = "RobotPy Development Team"
+epub_copyright = "2019 RobotPy Development Team"
+
+# The basename for the epub file. It defaults to the project name.
+# epub_basename = u'..'
+
+# The HTML theme for the epub output. Since the default themes are not optimized
+# for small screen space, using the same theme for HTML and epub output is
+# usually not wise. This defaults to 'epub', a theme designed to save visual
+# space.
+# epub_theme = 'epub'
+
+# The language of the text. It defaults to the language option
+# or en if the language is not set.
+# epub_language = ''
+
+# The scheme of the identifier. Typical schemes are ISBN or URL.
+# epub_scheme = ''
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+# epub_identifier = ''
+
+# A unique identification for the text.
+# epub_uid = ''
+
+# A tuple containing the cover image and cover page html template filenames.
+# epub_cover = ()
+
+# A sequence of (type, uri, title) tuples for the guide element of content.opf.
+# epub_guide = ()
+
+# HTML files that should be inserted before the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+# epub_pre_files = []
+
+# HTML files shat should be inserted after the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+# epub_post_files = []
+
+# A list of files that should not be packed into the epub file.
+epub_exclude_files = ["search.html"]
+
+# The depth of the table of contents in toc.ncx.
+# epub_tocdepth = 3
+
+# Allow duplicate toc entries.
+# epub_tocdup = True
+
+# Choose between 'default' and 'includehidden'.
+# epub_tocscope = 'default'
+
+# Fix unsupported image types using the PIL.
+# epub_fix_images = False
+
+# Scale large images.
+# epub_max_image_width = 0
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+# epub_show_urls = 'inline'
+
+# If false, no index is generated.
+# epub_use_index = True
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 0000000..d90e920
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,5 @@
+.. include:: ../README.rst
+
+.. toctree::
+
+   api
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644
index 0000000..4bf38ef
--- /dev/null
+++ b/docs/make.bat
@@ -0,0 +1,242 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+	set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+	set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+	set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+	:help
+	echo.Please use `make ^` where ^ is one of
+	echo.  html       to make standalone HTML files
+	echo.  dirhtml    to make HTML files named index.html in directories
+	echo.  singlehtml to make a single large HTML file
+	echo.  pickle     to make pickle files
+	echo.  json       to make JSON files
+	echo.  htmlhelp   to make HTML files and a HTML help project
+	echo.  qthelp     to make HTML files and a qthelp project
+	echo.  devhelp    to make HTML files and a Devhelp project
+	echo.  epub       to make an epub
+	echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+	echo.  text       to make text files
+	echo.  man        to make manual pages
+	echo.  texinfo    to make Texinfo files
+	echo.  gettext    to make PO message catalogs
+	echo.  changes    to make an overview over all changed/added/deprecated items
+	echo.  xml        to make Docutils-native XML files
+	echo.  pseudoxml  to make pseudoxml-XML files for display purposes
+	echo.  linkcheck  to check all external links for integrity
+	echo.  doctest    to run all doctests embedded in the documentation if enabled
+	goto end
+)
+
+if "%1" == "clean" (
+	for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+	del /q /s %BUILDDIR%\*
+	goto end
+)
+
+
+%SPHINXBUILD% 2> nul
+if errorlevel 9009 (
+	echo.
+	echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+	echo.installed, then set the SPHINXBUILD environment variable to point
+	echo.to the full path of the 'sphinx-build' executable. Alternatively you
+	echo.may add the Sphinx directory to PATH.
+	echo.
+	echo.If you don't have Sphinx installed, grab it from
+	echo.http://sphinx-doc.org/
+	exit /b 1
+)
+
+if "%1" == "html" (
+	%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+	goto end
+)
+
+if "%1" == "dirhtml" (
+	%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+	goto end
+)
+
+if "%1" == "singlehtml" (
+	%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+	goto end
+)
+
+if "%1" == "pickle" (
+	%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the pickle files.
+	goto end
+)
+
+if "%1" == "json" (
+	%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the JSON files.
+	goto end
+)
+
+if "%1" == "htmlhelp" (
+	%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+	goto end
+)
+
+if "%1" == "qthelp" (
+	%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+	echo.^> qcollectiongenerator %BUILDDIR%\qthelp\sphinx.qhcp
+	echo.To view the help file:
+	echo.^> assistant -collectionFile %BUILDDIR%\qthelp\sphinx.ghc
+	goto end
+)
+
+if "%1" == "devhelp" (
+	%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished.
+	goto end
+)
+
+if "%1" == "epub" (
+	%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The epub file is in %BUILDDIR%/epub.
+	goto end
+)
+
+if "%1" == "latex" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "latexpdf" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	cd %BUILDDIR%/latex
+	make all-pdf
+	cd %BUILDDIR%/..
+	echo.
+	echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "latexpdfja" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	cd %BUILDDIR%/latex
+	make all-pdf-ja
+	cd %BUILDDIR%/..
+	echo.
+	echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "text" (
+	%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The text files are in %BUILDDIR%/text.
+	goto end
+)
+
+if "%1" == "man" (
+	%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The manual pages are in %BUILDDIR%/man.
+	goto end
+)
+
+if "%1" == "texinfo" (
+	%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+	goto end
+)
+
+if "%1" == "gettext" (
+	%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+	goto end
+)
+
+if "%1" == "changes" (
+	%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.The overview file is in %BUILDDIR%/changes.
+	goto end
+)
+
+if "%1" == "linkcheck" (
+	%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+	goto end
+)
+
+if "%1" == "doctest" (
+	%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+	goto end
+)
+
+if "%1" == "xml" (
+	%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The XML files are in %BUILDDIR%/xml.
+	goto end
+)
+
+if "%1" == "pseudoxml" (
+	%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
+	goto end
+)
+
+:end
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000..07084c4
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1,2 @@
+sphinx
+sphinx-rtd-theme
\ No newline at end of file
diff --git a/CppHeaderParser/examples/SampleClass.h b/examples/SampleClass.h
similarity index 100%
rename from CppHeaderParser/examples/SampleClass.h
rename to examples/SampleClass.h
diff --git a/CppHeaderParser/examples/readSampleClass.py b/examples/readSampleClass.py
similarity index 66%
rename from CppHeaderParser/examples/readSampleClass.py
rename to examples/readSampleClass.py
index 0bab4f7..1b9e9be 100755
--- a/CppHeaderParser/examples/readSampleClass.py
+++ b/examples/readSampleClass.py
@@ -1,21 +1,27 @@
-#!/usr/bin/python
+#!/usr/bin/env python
+import pprint
 import sys
+
 sys.path = ["../"] + sys.path
-import CppHeaderParser
+from CppHeaderParser import CppHeader, CppParseError
+
 try:
-    cppHeader = CppHeaderParser.CppHeader("SampleClass.h")
-except CppHeaderParser.CppParseError as e:
+    cppHeader = CppHeader("SampleClass.h")
+except CppParseError as e:
     print(e)
     sys.exit(1)
 
-print("CppHeaderParser view of %s"%cppHeader)
+print("CppHeaderParser view of %s" % cppHeader)
 
 sampleClass = cppHeader.classes["SampleClass"]
-print("Number of public methods %d"%(len(sampleClass["methods"]["public"])))
-print("Number of private properties %d"%(len(sampleClass["properties"]["private"])))
-meth3 = [m for m in sampleClass["methods"]["public"] if m["name"] == "meth3"][0] #get meth3
-meth3ParamTypes = [t["type"] for t in meth3["parameters"]] #get meth3s parameters
-print("Parameter Types for public method meth3 %s"%(meth3ParamTypes))
+print("Number of public methods %d" % (len(sampleClass["methods"]["public"])))
+print("Number of private properties %d" % (len(sampleClass["properties"]["private"])))
+meth3 = [m for m in sampleClass["methods"]["public"] if m["name"] == "meth3"][
+    0
+]  # get meth3
+meth3ParamTypes = [t["type"] for t in meth3["parameters"]]  # get meth3s parameters
+print("Parameter Types for public method meth3")
+pprint.pprint(meth3ParamTypes)
 
 print("\nReturn type for meth1:")
 print(cppHeader.classes["SampleClass"]["methods"]["public"][1]["rtnType"])
@@ -24,7 +30,7 @@
 print(cppHeader.classes["SampleClass"]["methods"]["public"][2]["doxygen"])
 
 print("\nParameters for meth3:")
-print(cppHeader.classes["SampleClass"]["methods"]["public"][3]["parameters"])
+pprint.pprint(cppHeader.classes["SampleClass"]["methods"]["public"][3]["parameters"])
 
 print("\nDoxygen for meth4:")
 print(cppHeader.classes["SampleClass"]["methods"]["public"][4]["doxygen"])
@@ -52,12 +58,12 @@
 
 print("\nFree functions are:")
 for func in cppHeader.functions:
-    print(" %s"%func["name"])
+    print(" %s" % func["name"])
 
 print("\n#includes are:")
 for incl in cppHeader.includes:
-    print(" %s"%incl)
+    print(" %s" % incl)
 
 print("\n#defines are:")
 for define in cppHeader.defines:
-    print(" %s"%define)
+    print(" %s" % define)
diff --git a/run_tests.sh b/run_tests.sh
new file mode 100755
index 0000000..83b59b6
--- /dev/null
+++ b/run_tests.sh
@@ -0,0 +1,4 @@
+#!/bin/sh -e
+
+cd test/
+python test_CppHeaderParser.py
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..9853d1a
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,3 @@
+[metadata]
+# Include the license file in wheels.
+license_file = LICENSE.txt
diff --git a/setup.py b/setup.py
index 9d1df9a..5de215c 100644
--- a/setup.py
+++ b/setup.py
@@ -1,47 +1,78 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
-import sys, glob
-try:
-    from setuptools import setup
-except ImportError:
-    from distutils.core import setup
+from __future__ import print_function
 
-DESCRIPTION = (
-    'Parse C++ header files and generate a data structure '
-    'representing the class'
+from os.path import dirname, exists, join
+import sys, subprocess
+
+from setuptools import find_packages, setup
+
+setup_dir = dirname(__file__)
+git_dir = join(setup_dir, ".git")
+version_file = join(setup_dir, "CppHeaderParser", "version.py")
+
+# Automatically generate a version.py based on the git version
+if exists(git_dir):
+    p = subprocess.Popen(
+        ["git", "describe", "--tags", "--long", "--dirty=-dirty"],
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
     )
+    out, err = p.communicate()
+    # Make sure the git version has at least one tag
+    if err:
+        print("Error: You need to create a tag for this repo to use the builder")
+        sys.exit(1)
+
+    # Convert git version to PEP440 compliant version
+    # - Older versions of pip choke on local identifiers, so we can't include the git commit
+    v, commits, local = out.decode("utf-8").rstrip().split("-", 2)
+    if commits != "0" or "-dirty" in local:
+        v = "%s.post0.dev%s" % (v, commits)
+
+    # Create the version.py file
+    with open(version_file, "w") as fp:
+        fp.write("# Autogenerated by setup.py\n__version__ = '{0}'".format(v))
+
+with open(version_file, "r") as fp:
+    exec(fp.read(), globals())
+
+DESCRIPTION = (
+    "Parse C++ header files and generate a data structure " "representing the class"
+)
 
 
 CLASSIFIERS = [
-    'Operating System :: OS Independent',
-    'Programming Language :: Python',
-    'Programming Language :: Python :: 2',
-    'Programming Language :: Python :: 3',
-    'Programming Language :: C++',
-    'License :: OSI Approved :: BSD License',
-    'Development Status :: 5 - Production/Stable',
-    'Intended Audience :: Developers',
-    'Topic :: Software Development',
-    'Topic :: Software Development :: Code Generators',
-    'Topic :: Software Development :: Compilers',
-    'Topic :: Software Development :: Disassemblers'
-    ]
+    "Operating System :: OS Independent",
+    "Programming Language :: Python",
+    "Programming Language :: Python :: 2",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: C++",
+    "License :: OSI Approved :: BSD License",
+    "Development Status :: 5 - Production/Stable",
+    "Intended Audience :: Developers",
+    "Topic :: Software Development",
+    "Topic :: Software Development :: Code Generators",
+    "Topic :: Software Development :: Compilers",
+    "Topic :: Software Development :: Disassemblers",
+]
 
 setup(
-    name = 'CppHeaderParser',
-    version = '2.7.4',
-    author = 'Jashua Cloutier',
-    author_email = 'jashuac@bellsouth.net',
-    url = 'http://senexcanis.com/open-source/cppheaderparser/',
-    description = DESCRIPTION,
-    long_description = open('README.txt').read(),
-    license = 'BSD',
-    platforms = 'Platform Independent',
-    packages = ['CppHeaderParser'],
-    keywords = 'c++ header parser ply',
-    classifiers = CLASSIFIERS,
-    requires = ['ply'],
-    install_requires=['ply'],
-    package_data = { 'CppHeaderParser': ['README', 'README.html', 'doc/*.*', 'examples/*.*'], },
-    )
+    name="robotpy-cppheaderparser",
+    version=__version__,
+    author="Jashua Cloutier",
+    author_email="jashuac@bellsouth.net",
+    maintainer="RobotPy Development Team",
+    maintainer_email="robotpy@googlegroups.com",
+    url="https://github.com/robotpy/robotpy-cppheaderparser",
+    description=DESCRIPTION,
+    long_description=open("README.rst").read(),
+    license="BSD",
+    platforms="Platform Independent",
+    packages=["CppHeaderParser"],
+    keywords="c++ header parser ply",
+    classifiers=CLASSIFIERS,
+    requires=["ply"],
+    install_requires=["ply"],
+)
diff --git a/templates/README.txt b/templates/README.txt
deleted file mode 100644
index 2ff1451..0000000
--- a/templates/README.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-Python package "CppHeaderParser"
---------------------------------
-**Purpose:** Parse C++ header files and generate a data structure representing the class
-
-**Author:** Jashua Cloutier
-
-**Licence:** BSD
-
-**External modules required:** PLY
-
-**Quick start**::
-
-{SAMPLE_CLASS_H}
-
-**Python code**::
-
-{READ_SAMPLE_CLASS_PY}
-
-**Output**::
-
-{READ_SAMPLE_CLASS_PY_OUTPUT}
-
-
-Contributors
-------------
-* Chris Love
-* HartsAntler
diff --git a/CppHeaderParser/test/LineNumTest.h b/test/LineNumTest.h
similarity index 100%
rename from CppHeaderParser/test/LineNumTest.h
rename to test/LineNumTest.h
diff --git a/CppHeaderParser/test/TestSampleClass.h b/test/TestSampleClass.h
similarity index 88%
rename from CppHeaderParser/test/TestSampleClass.h
rename to test/TestSampleClass.h
index b803203..45efef7 100644
--- a/CppHeaderParser/test/TestSampleClass.h
+++ b/test/TestSampleClass.h
@@ -47,6 +47,14 @@ class SampleClass: public BaseSampleClass
     string prop1;
     //! prop5 description
     int prop5;
+
+    bool prop6;     /*!< prop6 description */
+
+    double prop7;   //!< prop7 description
+                    //!< with two lines
+    
+    /// prop8 description
+    int prop8;
 };
 namespace Alpha
 {
@@ -65,6 +73,8 @@ namespace Alpha
     		Z_B = 0x2B,
     		Z_C = 'j',
 			Z_D,
+         Z_E = '9',
+         Z_F = 9,
     	} Zebra;
     };
 
@@ -82,9 +92,12 @@ namespace Alpha
 			///
 			typedef enum
 			{
-				RI_ZERO,
-				RI_ONE,
-				RI_TWO
+				RI_ZERO, /// item zero
+				RI_ONE,  /** item one */
+				RI_TWO,   //!< item two
+				RI_THREE,
+				/// item four
+				RI_FOUR,
 			} Rino;
 		};
     };
@@ -574,15 +587,6 @@ class AfterTypedefClass
   public:
 }
 
-// Bug BitBucket #6
-class LineNumAfterDivide
-{
-  static int func1(float alpha_num)
-  { return funcX(alpha_num /
-                 beta_num); }
-  void func2();
-};
-
 // Bug BitBucket #5
 class Herb
 {
@@ -753,4 +757,39 @@ typedef struct
         FAIL = 0,
         PASS = 1
     }; 
-} BeetStruct;
\ No newline at end of file
+} BeetStruct;
+
+void set_callback(int* b, long (*callback) (struct test_st *, int, const char*, int long, long, long));
+
+// Bitbucket bug 35
+struct Grackle
+{
+    void no_noexcept();
+    void just_noexcept() noexcept;
+    void const_noexcept() const noexcept;
+    void noexcept_bool() noexcept(true);
+    void const_noexcept_bool() const noexcept(true);
+    void noexcept_noexceptOperator() noexcept(noexcept(Grackle()));
+    void const_noexcept_noexceptOperator() const noexcept(noexcept(Grackle()));
+};
+
+// Two prototypes that are the same apart from the ...
+int vararg_func(int foo, const char* fmt, ...);
+
+int non_vararg_func(int foo, const char* fmt);
+
+// Sample class for testing default constructor destructor
+class DefaultConstDest {
+public:
+    DefaultConstDest() =default ;     // spacing check
+    DefaultConstDest() = default  ;   // spacing check
+};
+// default constructor on a class containing "default" as name (edge case check)
+class default_class_tricky {
+public:
+    default_class_tricky();
+    default_class_tricky();
+
+    void randomMethod1_default();
+    void defaultrandomMethod2();
+};
diff --git a/test/test_CppHeaderParser.py b/test/test_CppHeaderParser.py
new file mode 100644
index 0000000..4f949f5
--- /dev/null
+++ b/test/test_CppHeaderParser.py
@@ -0,0 +1,4309 @@
+# -*- coding: utf-8 -*-
+import unittest
+import sys
+
+import CppHeaderParser as CppHeaderParser
+
+
+def filter_pameters(p, extra=[]):
+    "Reduce a list of dictionaries to the desired keys for function parameter testing"
+    rtn = []
+    for d in p:
+        rd = {}
+        for k in ["name", "desc", "type"] + extra:
+            rd[k] = d.get(k)
+        rtn.append(rd)
+    return rtn
+
+
+def filter_dict_keys(d, keys):
+    "Filter a dictonary to a specified set of keys"
+    rtn = {}
+    for k in keys:
+        rtn[k] = d.get(k, None)
+    return rtn
+
+
+class SampleClass_SampleClass_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["methods"]["public"][0]["name"],
+            "SampleClass",
+        )
+
+    def test_rtntype(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["methods"]["public"][0]["rtnType"],
+            "void",
+        )
+
+    def test_parameters(self):
+        self.assertEqual(
+            filter_pameters(
+                self.cppHeader.classes["SampleClass"]["methods"]["public"][0][
+                    "parameters"
+                ]
+            ),
+            [],
+        )
+
+    def test_doxygen(self):
+        self.assertTrue(
+            "doxygen"
+            not in self.cppHeader.classes["SampleClass"]["methods"]["public"][0].keys()
+        )
+
+
+class SampleClass_meth1_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["methods"]["public"][1]["name"],
+            "meth1",
+        )
+
+    def test_rtntype(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["methods"]["public"][1]["rtnType"],
+            "string",
+        )
+
+    def test_parameters(self):
+        self.assertEqual(
+            filter_pameters(
+                self.cppHeader.classes["SampleClass"]["methods"]["public"][1][
+                    "parameters"
+                ]
+            ),
+            [],
+        )
+
+    def test_doxygen(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["methods"]["public"][1]["doxygen"],
+            "/*!\n* Method 1\n*/",
+        )
+
+
+class SampleClass_meth2_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["methods"]["public"][2]["name"],
+            "meth2",
+        )
+
+    def test_rtntype(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["methods"]["public"][2]["rtnType"],
+            "int",
+        )
+
+    def test_parameters(self):
+        self.assertEqual(
+            filter_pameters(
+                self.cppHeader.classes["SampleClass"]["methods"]["public"][2][
+                    "parameters"
+                ]
+            ),
+            [{"type": "int", "name": "v1", "desc": "Variable 1"}],
+        )
+
+    def test_doxygen(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["methods"]["public"][2]["doxygen"],
+            "///\n/// Method 2 description\n///\n/// @param v1 Variable 1\n///",
+        )
+
+
+class SampleClass_meth3_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["methods"]["public"][3]["name"],
+            "meth3",
+        )
+
+    def test_rtntype(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["methods"]["public"][3]["rtnType"],
+            "void",
+        )
+
+    def test_parameters(self):
+        self.assertEqual(
+            filter_pameters(
+                self.cppHeader.classes["SampleClass"]["methods"]["public"][3][
+                    "parameters"
+                ]
+            ),
+            [
+                {
+                    "type": "const string &",
+                    "name": "v1",
+                    "desc": "Variable 1 with a really long wrapping description",
+                },
+                {"type": "vector &", "name": "v2", "desc": "Variable 2"},
+            ],
+        )
+
+    def test_doxygen(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["methods"]["public"][3]["doxygen"],
+            "/**\n* Method 3 description\n*\n* \\param v1 Variable 1 with a really long\n* wrapping description\n* \\param v2 Variable 2\n*/",
+        )
+
+
+class SampleClass_meth4_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["methods"]["public"][4]["name"],
+            "meth4",
+        )
+
+    def test_rtntype(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["methods"]["public"][4]["rtnType"],
+            "unsigned int",
+        )
+
+    def test_parameters(self):
+        self.assertEqual(
+            filter_pameters(
+                self.cppHeader.classes["SampleClass"]["methods"]["public"][4][
+                    "parameters"
+                ]
+            ),
+            [],
+        )
+
+    def test_doxygen(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["methods"]["public"][4]["doxygen"],
+            "/**********************************\n* Method 4 description\n*\n* @return Return value\n*********************************/",
+        )
+
+
+class SampleClass_meth5_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["methods"]["private"][0]["name"],
+            "meth5",
+        )
+
+    def test_rtntype(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["methods"]["private"][0]["rtnType"],
+            "void *",
+        )
+
+    def test_parameters(self):
+        self.assertEqual(
+            filter_pameters(
+                self.cppHeader.classes["SampleClass"]["methods"]["private"][0][
+                    "parameters"
+                ]
+            ),
+            [],
+        )
+
+    def test_doxygen(self):
+        self.assertTrue(
+            "doxygen"
+            not in self.cppHeader.classes["SampleClass"]["methods"]["private"][0].keys()
+        )
+
+
+class SampleClass_doxygen_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_prop1(self):
+        m = self.cppHeader.classes["SampleClass"]["properties"]["private"][0]
+        self.assertEqual(m["name"], "prop1")
+        self.assertEqual(m["type"], "string")
+        self.assertEqual(m["doxygen"], "/// prop1 description")
+
+    def test_prop5(self):
+        m = self.cppHeader.classes["SampleClass"]["properties"]["private"][1]
+        self.assertEqual(m["name"], "prop5")
+        self.assertEqual(m["type"], "int")
+        self.assertEqual(m["doxygen"], "//! prop5 description")
+
+    def test_prop6(self):
+        m = self.cppHeader.classes["SampleClass"]["properties"]["private"][2]
+        self.assertEqual(m["name"], "prop6")
+        self.assertEqual(m["type"], "bool")
+        self.assertEqual(m["doxygen"], "/*!< prop6 description */")
+
+    def test_prop7(self):
+        m = self.cppHeader.classes["SampleClass"]["properties"]["private"][3]
+        self.assertEqual(m["name"], "prop7")
+        self.assertEqual(m["type"], "double")
+        self.assertEqual(m["doxygen"], "//!< prop7 description\n//!< with two lines")
+
+    def test_prop8(self):
+        m = self.cppHeader.classes["SampleClass"]["properties"]["private"][4]
+        self.assertEqual(m["name"], "prop8")
+        self.assertEqual(m["type"], "int")
+        self.assertEqual(m["doxygen"], "/// prop8 description")
+
+
+class SampleClass_Elephant_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["enums"]["public"][0]["name"],
+            "Elephant",
+        )
+
+    def test_namespace(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["enums"]["public"][0]["namespace"], ""
+        )
+
+    def test_doxygen(self):
+        self.assertTrue(
+            "doxygen"
+            not in self.cppHeader.classes["SampleClass"]["enums"]["public"][0].keys()
+        )
+
+    def test_values(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleClass"]["enums"]["public"][0]["values"],
+            [
+                {"name": "EL_ONE", "value": 1},
+                {"name": "EL_TWO", "value": 2},
+                {"name": "EL_NINE", "value": 9},
+                {"name": "EL_TEN", "value": 10},
+            ],
+        )
+
+
+class AlphaClass_AlphaClass_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["AlphaClass"]["methods"]["public"][0]["name"],
+            "AlphaClass",
+        )
+
+    def test_rtntype(self):
+        self.assertEqual(
+            self.cppHeader.classes["AlphaClass"]["methods"]["public"][0]["rtnType"],
+            "void",
+        )
+
+    def test_parameters(self):
+        self.assertEqual(
+            filter_pameters(
+                self.cppHeader.classes["AlphaClass"]["methods"]["public"][0][
+                    "parameters"
+                ]
+            ),
+            [],
+        )
+
+    def test_doxygen(self):
+        self.assertTrue(
+            "doxygen"
+            not in self.cppHeader.classes["AlphaClass"]["methods"]["public"][0].keys()
+        )
+
+
+class AlphaClass_alphaMethod_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["AlphaClass"]["methods"]["public"][1]["name"],
+            "alphaMethod",
+        )
+
+    def test_rtntype(self):
+        self.assertEqual(
+            self.cppHeader.classes["AlphaClass"]["methods"]["public"][1]["rtnType"],
+            "void",
+        )
+
+    def test_parameters(self):
+        self.assertEqual(
+            filter_pameters(
+                self.cppHeader.classes["AlphaClass"]["methods"]["public"][1][
+                    "parameters"
+                ]
+            ),
+            [],
+        )
+
+    def test_doxygen(self):
+        self.assertTrue(
+            "doxygen"
+            not in self.cppHeader.classes["AlphaClass"]["methods"]["public"][1].keys()
+        )
+
+
+class AlphaClass_alphaString_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["AlphaClass"]["properties"]["public"][0]["name"],
+            "alphaString",
+        )
+
+    def test_type(self):
+        self.assertEqual(
+            self.cppHeader.classes["AlphaClass"]["properties"]["public"][0]["type"],
+            "string",
+        )
+
+    def test_doxygen(self):
+        self.assertTrue(
+            "doxygen"
+            not in self.cppHeader.classes["AlphaClass"]["properties"]["public"][
+                0
+            ].keys()
+        )
+
+
+class AlphaClass_Zebra_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["AlphaClass"]["enums"]["protected"][0]["name"],
+            "Zebra",
+        )
+
+    def test_namespace(self):
+        self.assertEqual(
+            self.cppHeader.classes["AlphaClass"]["enums"]["protected"][0]["namespace"],
+            "Alpha",
+        )
+
+    def test_doxygen(self):
+        self.assertTrue(
+            "doxygen"
+            not in self.cppHeader.classes["AlphaClass"]["enums"]["protected"][0].keys()
+        )
+
+    def test_values(self):
+        self.assertEqual(
+            self.cppHeader.classes["AlphaClass"]["enums"]["protected"][0]["values"],
+            [
+                {"name": "Z_A", "value": 0},
+                {"name": "Z_B", "raw_value": "0x2B", "value": 43},
+                {"name": "Z_C", "raw_value": "j", "value": 106},
+                {"name": "Z_D", "value": 107},
+                {"name": "Z_E", "raw_value": "9", "value": 57},
+                {"name": "Z_F", "value": 9},
+            ],
+        )
+
+
+class OmegaClass_OmegaClass_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["OmegaClass"]["methods"]["public"][0]["name"],
+            "OmegaClass",
+        )
+
+    def test_rtntype(self):
+        self.assertEqual(
+            self.cppHeader.classes["OmegaClass"]["methods"]["public"][0]["rtnType"],
+            "void",
+        )
+
+    def test_parameters(self):
+        self.assertEqual(
+            filter_pameters(
+                self.cppHeader.classes["OmegaClass"]["methods"]["public"][0][
+                    "parameters"
+                ]
+            ),
+            [],
+        )
+
+    def test_doxygen(self):
+        self.assertTrue(
+            "doxygen"
+            not in self.cppHeader.classes["OmegaClass"]["methods"]["public"][0].keys()
+        )
+
+
+class OmegaClass_omegaString_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["OmegaClass"]["properties"]["public"][0]["name"],
+            "omegaString",
+        )
+
+    def test_type(self):
+        self.assertEqual(
+            self.cppHeader.classes["OmegaClass"]["properties"]["public"][0]["type"],
+            "string",
+        )
+
+    def test_doxygen(self):
+        self.assertTrue(
+            "doxygen"
+            not in self.cppHeader.classes["OmegaClass"]["properties"]["public"][
+                0
+            ].keys()
+        )
+
+
+class OmegaClass_Rino_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["OmegaClass"]["enums"]["protected"][0]["name"],
+            "Rino",
+        )
+
+    def test_namespace(self):
+        self.assertEqual(
+            self.cppHeader.classes["OmegaClass"]["enums"]["protected"][0]["namespace"],
+            "Alpha::Omega",
+        )
+
+    def test_doxygen(self):
+        self.assertEqual(
+            self.cppHeader.classes["OmegaClass"]["enums"]["protected"][0]["doxygen"],
+            "///\n/// @brief Rino Numbers, not that that means anything\n///",
+        )
+
+    def test_values(self):
+        self.assertEqual(
+            self.cppHeader.classes["OmegaClass"]["enums"]["protected"][0]["values"],
+            [
+                {"name": "RI_ZERO", "value": 0, "doxygen": "/// item zero"},
+                {"name": "RI_ONE", "value": 1, "doxygen": "/** item one */"},
+                {"name": "RI_TWO", "value": 2, "doxygen": "//!< item two"},
+                {"name": "RI_THREE", "value": 3},
+                {"name": "RI_FOUR", "value": 4, "doxygen": "/// item four"},
+            ],
+        )
+
+
+class Bug3488053_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_public(self):
+        self.assertEqual(
+            len(
+                self.cppHeader.classes["Bug_3488053::Bug_3488053_Nested"]["properties"][
+                    "public"
+                ]
+            ),
+            1,
+        )
+
+    def test_private(self):
+        self.assertEqual(
+            len(
+                self.cppHeader.classes["Bug_3488053::Bug_3488053_Nested"]["properties"][
+                    "private"
+                ]
+            ),
+            0,
+        )
+
+    def test_protected(self):
+        self.assertEqual(
+            len(
+                self.cppHeader.classes["Bug_3488053::Bug_3488053_Nested"]["properties"][
+                    "protected"
+                ]
+            ),
+            0,
+        )
+
+
+class Bug3488360_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_BloodOrange_inherits(self):
+        self.assertEqual(self.cppHeader.classes["BloodOrange"]["inherits"], [])
+
+    def test_Bananna_inherits(self):
+        self.assertEqual(
+            self.cppHeader.classes["Bananna"]["inherits"],
+            [
+                {
+                    "access": "public",
+                    "class": "Citrus::BloodOrange",
+                    "decl_name": "Citrus::BloodOrange",
+                    "decltype": False,
+                    "virtual": False,
+                    "...": False,
+                }
+            ],
+        )
+
+    def test_ExcellentCake_inherits(self):
+        self.assertEqual(
+            self.cppHeader.classes["ExcellentCake"]["inherits"],
+            [
+                {
+                    "access": "private",
+                    "class": "Citrus::BloodOrange",
+                    "decl_name": "Citrus::BloodOrange",
+                    "decltype": False,
+                    "virtual": False,
+                    "...": False,
+                },
+                {
+                    "access": "private",
+                    "class": "Convoluted::Nested::Mixin",
+                    "decl_name": "Convoluted::Nested::Mixin",
+                    "decltype": False,
+                    "virtual": False,
+                    "...": False,
+                },
+            ],
+        )
+
+
+class Bug3487551_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_method_rtn_type(self):
+        self.assertEqual(
+            self.cppHeader.classes["Bug_3487551"]["methods"]["public"][0]["rtnType"],
+            "int",
+        )
+
+
+class SampleStruct_meth_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleStruct"]["methods"]["public"][0]["name"],
+            "meth",
+        )
+
+    def test_rtntype(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleStruct"]["methods"]["public"][0]["rtnType"],
+            "unsigned int",
+        )
+
+    def test_parameters(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleStruct"]["methods"]["public"][0][
+                "parameters"
+            ],
+            [],
+        )
+
+    def test_doxygen(self):
+        self.assertTrue(
+            "doxygen"
+            not in self.cppHeader.classes["SampleStruct"]["methods"]["public"][0].keys()
+        )
+
+
+class SampleStruct_prop_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleStruct"]["properties"]["private"][0]["name"],
+            "prop",
+        )
+
+    def test_type(self):
+        self.assertEqual(
+            self.cppHeader.classes["SampleStruct"]["properties"]["private"][0]["type"],
+            "int",
+        )
+
+    def test_doxygen(self):
+        self.assertTrue(
+            "doxygen"
+            not in self.cppHeader.classes["SampleStruct"]["properties"]["private"][
+                0
+            ].keys()
+        )
+
+
+class Bird_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_items_array(self):
+        self.assertEqual(
+            self.cppHeader.classes["Bird"]["properties"]["private"][0]["array"], 1
+        )
+
+    def test_otherItems_array(self):
+        self.assertEqual(
+            self.cppHeader.classes["Bird"]["properties"]["private"][1]["array"], 1
+        )
+
+    def test_oneItem_array(self):
+        self.assertEqual(
+            self.cppHeader.classes["Bird"]["properties"]["private"][2]["array"], 0
+        )
+
+    def test_items_array_size(self):
+        self.assertEqual(
+            self.cppHeader.classes["Bird"]["properties"]["private"][0]["array_size"],
+            "MAX_ITEM",
+        )
+
+    def test_otherItems_array_size(self):
+        self.assertEqual(
+            self.cppHeader.classes["Bird"]["properties"]["private"][1]["array_size"],
+            "7",
+        )
+
+
+class Monkey_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_public_methods(self):
+        self.assertEqual(len(self.cppHeader.classes["Monkey"]["methods"]["public"]), 0)
+
+    def test_num_private_methods(self):
+        self.assertEqual(len(self.cppHeader.classes["Monkey"]["methods"]["private"]), 1)
+
+    def test_num_protected_methods(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["Monkey"]["methods"]["protected"]), 0
+        )
+
+
+class Chicken_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_public_methods(self):
+        self.assertEqual(len(self.cppHeader.classes["Chicken"]["methods"]["public"]), 0)
+
+    def test_num_private_methods(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["Chicken"]["methods"]["private"]), 1
+        )
+
+    def test_num_protected_methods(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["Chicken"]["methods"]["protected"]), 0
+        )
+
+    def test_template(self):
+        self.assertEqual(
+            self.cppHeader.classes["Chicken"]["methods"]["private"][0]["template"],
+            "template",
+        )
+
+
+class Lizzard_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_normal_constructor(self):
+        cmp_values = {
+            "inline": False,
+            "name": "Lizzard",
+            "parameters": [],
+            "friend": False,
+            "explicit": False,
+            "constructor": True,
+            "namespace": "",
+            "destructor": False,
+            "pure_virtual": False,
+            "returns": "",
+            "static": False,
+            "virtual": False,
+            "template": False,
+            "rtnType": "void",
+            "extern": False,
+            "path": "Lizzard",
+            "returns_pointer": 0,
+            "class": None,
+        }
+        self.assertEqual(
+            filter_dict_keys(
+                self.cppHeader.classes["Lizzard"]["methods"]["private"][0],
+                cmp_values.keys(),
+            ),
+            cmp_values,
+        )
+
+    def test_explicit_constructor(self):
+        cmp_values = {
+            "inline": False,
+            "name": "Lizzard",
+            "friend": False,
+            "explicit": True,
+            "constructor": True,
+            "namespace": "",
+            "destructor": False,
+            "pure_virtual": False,
+            "returns": "",
+            "static": False,
+            "virtual": False,
+            "template": False,
+            "rtnType": "void",
+            "extern": False,
+            "path": "Lizzard",
+            "returns_pointer": 0,
+            "class": None,
+        }
+        self.assertEqual(
+            filter_dict_keys(
+                self.cppHeader.classes["Lizzard"]["methods"]["private"][1],
+                cmp_values.keys(),
+            ),
+            cmp_values,
+        )
+
+
+class Owl_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_public_methods(self):
+        self.assertEqual(len(self.cppHeader.classes["Owl"]["methods"]["public"]), 0)
+
+    def test_num_private_methods(self):
+        self.assertEqual(len(self.cppHeader.classes["Owl"]["methods"]["private"]), 1)
+
+    def test_num_protected_methods(self):
+        self.assertEqual(len(self.cppHeader.classes["Owl"]["methods"]["protected"]), 0)
+
+
+class Grape_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_public_properties(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["GrapeClass"]["properties"]["public"]), 0
+        )
+
+    def test_num_private_properties(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["GrapeClass"]["properties"]["private"]), 1
+        )
+
+    def test_num_protected_properties(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["GrapeClass"]["properties"]["protected"]), 0
+        )
+
+    def test_num_public_methods(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["GrapeClass"]["methods"]["public"]), 0
+        )
+
+    def test_num_private_methods(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["GrapeClass"]["methods"]["private"]), 1
+        )
+
+    def test_num_protected_methods(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["GrapeClass"]["methods"]["protected"]), 0
+        )
+
+
+class AnonHolderClass_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_property(self):
+        cmp_values = {
+            "constant": 0,
+            "name": "a",
+            "reference": 0,
+            "type": "",
+            "static": 0,
+            "pointer": 0,
+        }
+        self.assertEqual(
+            filter_dict_keys(
+                self.cppHeader.classes["AnonHolderClass"]["properties"]["public"][0],
+                cmp_values.keys(),
+            ),
+            cmp_values,
+        )
+
+
+class CowClass_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_class_declaration_method(self):
+        self.assertEqual(
+            self.cppHeader.classes["CowClass"]["declaration_method"], "class"
+        )
+
+    def test_struct_declaration_method(self):
+        self.assertEqual(
+            self.cppHeader.classes["CowStruct"]["declaration_method"], "struct"
+        )
+
+
+class Mango_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_virtual_inherits(self):
+        self.assertEqual(
+            self.cppHeader.classes["MangoClass"]["inherits"][0]["virtual"], True
+        )
+
+
+class Eagle_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_property(self):
+        cmp_values = {
+            "constant": 0,
+            "name": "a",
+            "reference": 0,
+            "array_size": "MAX_LEN",
+            "type": "int",
+            "static": 0,
+            "pointer": 0,
+        }
+        self.assertEqual(
+            filter_dict_keys(
+                self.cppHeader.classes["EagleClass"]["properties"]["private"][0],
+                cmp_values.keys(),
+            ),
+            cmp_values,
+        )
+
+
+class Frog_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_private_properties(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["FrogClass"]["properties"]["private"]), 3
+        )
+
+
+class Cat_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_private_properties(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["CatClass"]["properties"]["private"]), 0
+        )
+
+
+class Fish_TestCase(unittest.TestCase):
+    def setUp(self):
+        # Just make sure it doesnt crash
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+
+class Panda_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_property_CONST_A(self):
+        cmp_values = {
+            "typedef": None,
+            "unresolved": False,
+            "constant": 1,
+            "name": "CONST_A",
+            "parent": self.cppHeader.classes["PandaClass"],
+            "pointer": 0,
+            "namespace": "",
+            "raw_type": "int",
+            "class": 0,
+            "property_of_class": "PandaClass",
+            "static": 1,
+            "fundamental": True,
+            "mutable": False,
+            "typedefs": 0,
+            "array": 0,
+            "type": "static const int",
+            "reference": 0,
+            "aliases": [],
+        }
+        self.assertEqual(
+            filter_dict_keys(
+                self.cppHeader.classes["PandaClass"]["properties"]["private"][0],
+                cmp_values.keys(),
+            ),
+            cmp_values,
+        )
+
+    def test_property_CONST_B(self):
+        cmp_values = {
+            "typedef": None,
+            "unresolved": False,
+            "constant": 1,
+            "name": "CONST_B",
+            "parent": self.cppHeader.classes["PandaClass"],
+            "pointer": 0,
+            "namespace": "",
+            "raw_type": "int",
+            "class": 0,
+            "property_of_class": "PandaClass",
+            "static": 1,
+            "fundamental": True,
+            "mutable": False,
+            "typedefs": 0,
+            "array": 0,
+            "type": "static const int",
+            "reference": 0,
+            "aliases": [],
+        }
+        self.assertEqual(
+            filter_dict_keys(
+                self.cppHeader.classes["PandaClass"]["properties"]["private"][1],
+                cmp_values.keys(),
+            ),
+            cmp_values,
+        )
+
+
+class Potato_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_private_properties_potato(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["PotatoClass"]["properties"]["private"]), 1
+        )
+
+    def test_num_public_properties_potato_fwdstruct(self):
+        self.assertEqual(
+            len(
+                self.cppHeader.classes["PotatoClass::FwdStruct"]["properties"]["public"]
+            ),
+            1,
+        )
+
+
+class Hog_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_private_properties_potato(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["HogClass"]["properties"]["private"]), 1
+        )
+
+    def test_property(self):
+        cmp_values = {
+            "constant": 0,
+            "name": "u",
+            "reference": 0,
+            "type": "HogUnion",
+            "static": 0,
+            "pointer": 0,
+        }
+        self.assertEqual(
+            filter_dict_keys(
+                self.cppHeader.classes["HogClass"]["properties"]["private"][0],
+                cmp_values.keys(),
+            ),
+            cmp_values,
+        )
+
+    def test_union(self):
+        cmp_values = {
+            "name": "HogUnion",
+            "parent": self.cppHeader.classes["HogClass"],
+            "declaration_method": "union",
+        }
+        self.assertEqual(
+            filter_dict_keys(
+                self.cppHeader.classes["HogClass::HogUnion"], cmp_values.keys()
+            ),
+            cmp_values,
+        )
+
+    def test_union_member_a(self):
+        cmp_values = {
+            "constant": 0,
+            "name": "a",
+            "reference": 0,
+            "type": "int",
+            "static": 0,
+            "pointer": 0,
+        }
+        self.assertEqual(
+            filter_dict_keys(
+                self.cppHeader.classes["HogClass::HogUnion"]["members"][0],
+                cmp_values.keys(),
+            ),
+            cmp_values,
+        )
+
+    def test_union_member_b(self):
+        cmp_values = {
+            "constant": 0,
+            "name": "b",
+            "reference": 0,
+            "type": "float",
+            "static": 0,
+            "pointer": 0,
+        }
+        self.assertEqual(
+            filter_dict_keys(
+                self.cppHeader.classes["HogClass::HogUnion"]["members"][1],
+                cmp_values.keys(),
+            ),
+            cmp_values,
+        )
+
+
+# Bug 3497158
+class CherryClass_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_public_properties(self):
+        self.assertEqual(
+            len(
+                self.cppHeader.classes["CherryClass::NestStruct"]["properties"][
+                    "public"
+                ]
+            ),
+            1,
+        )
+
+    def test_num_public_methods(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["CherryClass::NestStruct"]["methods"]["public"]),
+            1,
+        )
+
+
+# Bug 3517308
+class GarlicClass_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_public_properties(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["GarlicClass"]["properties"]["public"]), 0
+        )
+
+    def test_num_public_methods(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["GarlicClass"]["methods"]["public"]), 3
+        )
+
+
+# Bug 3514728
+class CarrotClass_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_private_properties(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["CarrotClass"]["properties"]["private"]), 1
+        )
+
+    def test_num_private_methods(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["CarrotClass"]["methods"]["private"]), 1
+        )
+
+    def test_method_params(self):
+        self.assertEqual(
+            filter_pameters(
+                self.cppHeader.classes["CarrotClass"]["methods"]["private"][0][
+                    "parameters"
+                ]
+            ),
+            [],
+        )
+
+
+# Bug 3517289
+class ExternClass_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_private_methods(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["ExternClass"]["methods"]["private"]), 1
+        )
+
+
+# Bug 3514671
+class OliveStruct_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_public_properties(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["OliveStruct"]["properties"]["public"]), 4
+        )
+
+    def test_var_a(self):
+        self.assertEqual(
+            self.cppHeader.classes["OliveStruct"]["properties"]["public"][0]["name"],
+            "a",
+        )
+
+
+# Bug 3515330
+class Rooster_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_public_properties(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["RoosterOuterClass"]["properties"]["public"]), 1
+        )
+
+    def test_num_private_properties(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["RoosterOuterClass"]["properties"]["private"]), 1
+        )
+
+    def test_num_sub1_public_properties(self):
+        self.assertEqual(
+            len(
+                self.cppHeader.classes["RoosterOuterClass::RoosterSubClass1"][
+                    "properties"
+                ]["public"]
+            ),
+            1,
+        )
+
+    def test_num_sub1_private_properties(self):
+        self.assertEqual(
+            len(
+                self.cppHeader.classes["RoosterOuterClass::RoosterSubClass1"][
+                    "properties"
+                ]["private"]
+            ),
+            1,
+        )
+
+    def test_num_sub2_public_properties(self):
+        self.assertEqual(
+            len(
+                self.cppHeader.classes["RoosterOuterClass::RoosterSubClass2"][
+                    "properties"
+                ]["public"]
+            ),
+            1,
+        )
+
+    def test_num_sub2_private_properties(self):
+        self.assertEqual(
+            len(
+                self.cppHeader.classes["RoosterOuterClass::RoosterSubClass2"][
+                    "properties"
+                ]["private"]
+            ),
+            1,
+        )
+
+
+# Bug 3514672
+class OperatorClass_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_op_0(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][0]["name"],
+            "operator=",
+        )
+
+    def test_op_1(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][1]["name"],
+            "operator-=",
+        )
+
+    def test_op_2(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][2]["name"],
+            "operator+=",
+        )
+
+    def test_op_3(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][3]["name"],
+            "operator[]",
+        )
+
+    def test_op_4(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][4]["name"],
+            "operator==",
+        )
+
+    def test_op_5(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][5]["name"],
+            "operator+",
+        )
+
+    def test_op_6(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][6]["name"],
+            "operator-",
+        )
+
+    def test_op_7(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][7]["name"],
+            "operator*",
+        )
+
+    def test_op_8(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][8]["name"],
+            "operator\\",
+        )
+
+    def test_op_9(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][9]["name"],
+            "operator%",
+        )
+
+    def test_op_10(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][10]["name"],
+            "operator^",
+        )
+
+    def test_op_11(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][11]["name"],
+            "operator|",
+        )
+
+    def test_op_12(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][12]["name"],
+            "operator&",
+        )
+
+    def test_op_13(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][13]["name"],
+            "operator~",
+        )
+
+    def test_op_14(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][14]["name"],
+            "operator<<",
+        )
+
+    def test_op_15(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][15]["name"],
+            "operator>>",
+        )
+
+    def test_op_16(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][16]["name"],
+            "operator!=",
+        )
+
+    def test_op_17(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][17]["name"],
+            "operator<",
+        )
+
+    def test_op_18(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][18]["name"],
+            "operator>",
+        )
+
+    def test_op_19(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][19]["name"],
+            "operator>=",
+        )
+
+    def test_op_20(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][20]["name"],
+            "operator<=",
+        )
+
+    def test_op_21(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][21]["name"],
+            "operator!",
+        )
+
+    def test_op_22(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][22]["name"],
+            "operator&&",
+        )
+
+    def test_op_23(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][23]["name"],
+            "operator||",
+        )
+
+    def test_op_24(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][24]["name"],
+            "operator+=",
+        )
+
+    def test_op_25(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][25]["name"],
+            "operator-=",
+        )
+
+    def test_op_26(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][26]["name"],
+            "operator*=",
+        )
+
+    def test_op_27(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][27]["name"],
+            "operator\\=",
+        )
+
+    def test_op_28(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][28]["name"],
+            "operator%=",
+        )
+
+    def test_op_29(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][29]["name"],
+            "operator&=",
+        )
+
+    def test_op_30(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][30]["name"],
+            "operator|=",
+        )
+
+    def test_op_31(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][31]["name"],
+            "operator^=",
+        )
+
+    def test_op_32(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][32]["name"],
+            "operator<<=",
+        )
+
+    def test_op_33(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][33]["name"],
+            "operator>>=",
+        )
+
+    def test_op_34(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][34]["name"],
+            "operator++",
+        )
+
+    def test_op_35(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][35]["name"],
+            "operator--",
+        )
+
+    def test_op_36(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][36]["name"],
+            "operator()",
+        )
+
+    def test_op_37(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][37]["name"],
+            "operator->",
+        )
+
+    def test_op_38(self):
+        self.assertEqual(
+            self.cppHeader.classes["OperatorClass"]["methods"]["public"][38]["name"],
+            "operator,",
+        )
+
+
+# Feature Request 3519502 & 3523010
+class CrowClass_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.savedSupportedAccessSpecifier = CppHeaderParser.supportedAccessSpecifier
+        CppHeaderParser.supportedAccessSpecifier.append(
+            "public  slots "
+        )  # intentionally add expra spaces to make sure they get cleaned up
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_public_methods(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["CrowClass"]["methods"]["public"]), 1
+        )
+
+    def test_rtntype_public_slot_method(self):
+        self.assertEqual(
+            self.cppHeader.classes["CrowClass"]["methods"]["public slots"][0][
+                "rtnType"
+            ],
+            "void",
+        )
+
+    def test_num_public_slot_methods(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["CrowClass"]["methods"]["public slots"]), 1
+        )
+
+    def tearDown(self):
+        CppHeaderParser.supportedAccessSpecifier = self.savedSupportedAccessSpecifier
+
+
+# Bug 3497170
+class DriverFuncs_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name_0(self):
+        self.assertEqual(
+            self.cppHeader.classes["DriverFuncs"]["properties"]["public"][0]["name"],
+            "init",
+        )
+
+    def test_type_0(self):
+        self.assertEqual(
+            self.cppHeader.classes["DriverFuncs"]["properties"]["public"][0]["type"],
+            "void * ( * ) ( )",
+        )
+
+    def test_function_pointer_field_0(self):
+        self.assertEqual(
+            self.cppHeader.classes["DriverFuncs"]["properties"]["public"][0][
+                "function_pointer"
+            ],
+            1,
+        )
+
+    def test_name_1(self):
+        self.assertEqual(
+            self.cppHeader.classes["DriverFuncs"]["properties"]["public"][1]["name"],
+            "write",
+        )
+
+    def test_type_1(self):
+        self.assertEqual(
+            self.cppHeader.classes["DriverFuncs"]["properties"]["public"][1]["type"],
+            "void ( * ) ( void * buf, int buflen )",
+        )
+
+    def test_function_pointer_field_1(self):
+        self.assertEqual(
+            self.cppHeader.classes["DriverFuncs"]["properties"]["public"][1][
+                "function_pointer"
+            ],
+            1,
+        )
+
+
+# Bug 3519178
+class Snail_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_rtn_type(self):
+        self.assertEqual(
+            self.cppHeader.classes["Snail2Class"]["methods"]["public"][0]["rtnType"],
+            "SnailNamespace::SnailClass",
+        )
+
+    def test_param_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["Snail2Class"]["methods"]["public"][0]["parameters"][
+                0
+            ]["name"],
+            "",
+        )
+
+    def test_param_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["Snail2Class"]["methods"]["public"][0]["parameters"][
+                0
+            ]["type"],
+            "tr1::shared_ptr >",
+        )
+
+
+# Feature Request 3523198
+class Quale_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_rtn_type(self):
+        self.assertEqual(
+            self.cppHeader.classes["QualeClass"]["methods"]["private"][0]["rtnType"],
+            "void",
+        )
+
+
+# Feature Request 3523235
+class Rock_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_const_0(self):
+        self.assertEqual(
+            self.cppHeader.classes["RockClass"]["methods"]["private"][0]["const"], True
+        )
+
+    def test_const_1(self):
+        self.assertEqual(
+            self.cppHeader.classes["RockClass"]["methods"]["private"][1]["const"], False
+        )
+
+
+# Bug 3523196
+class Almond_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_rtn_type(self):
+        self.assertEqual(
+            self.cppHeader.classes["AlmondClass"]["methods"]["public"][0]["rtnType"],
+            "std::map > >",
+        )
+
+    def test_param_1_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["AlmondClass"]["methods"]["public"][0]["parameters"][
+                0
+            ]["name"],
+            "flag",
+        )
+
+    def test_param_1_type(self):
+        self.assertEqual(
+            self.cppHeader.classes["AlmondClass"]["methods"]["public"][0]["parameters"][
+                0
+            ]["type"],
+            "bool",
+        )
+
+    def test_param_2_name(self):
+        self.assertEqual(
+            self.cppHeader.classes["AlmondClass"]["methods"]["public"][0]["parameters"][
+                1
+            ]["name"],
+            "bigArg",
+        )
+
+    def test_param_2_type(self):
+        self.assertEqual(
+            self.cppHeader.classes["AlmondClass"]["methods"]["public"][0]["parameters"][
+                1
+            ]["type"],
+            "std::map > >",
+        )
+
+
+# Bug 3524327
+class Stone_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_const_0(self):
+        self.assertEqual(
+            self.cppHeader.classes["StoneClass"]["methods"]["private"][0]["const"], True
+        )
+
+    def test_const_1(self):
+        self.assertEqual(
+            self.cppHeader.classes["StoneClass"]["methods"]["private"][1]["const"],
+            False,
+        )
+
+
+# Bug 3531219
+class Kangaroo_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_kangaroo_methods(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["Kangaroo"]["methods"]["public"]), 1
+        )
+
+    def test_num_joey_methods(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["Kangaroo::Joey"]["methods"]["public"]), 1
+        )
+
+
+# Bug 3535465
+class Ant_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_constructor_1_params(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["Ant"]["methods"]["public"][0]["parameters"]), 3
+        )
+
+    def test_num_constructor_2_params(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["Ant"]["methods"]["public"][1]["parameters"]), 1
+        )
+
+
+# Bug 3536069
+class Onion_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_public_properties_red(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["Onion"]["properties"]["public"]), 1
+        )
+
+    def test_num_public_properties_sweet(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["Onion"]["properties"]["public"]), 1
+        )
+
+    def test_class_template(self):
+        self.assertEqual(
+            self.cppHeader.classes["Onion"]["template"],
+            "template",
+        )
+
+
+# Bug 3536067
+class BlueJay_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_public_methods(self):
+        self.assertEqual(len(self.cppHeader.classes["BlueJay"]["methods"]["public"]), 1)
+
+
+# Bug 3536266
+class functions_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader(
+            """\
+              void global_funct1(int i);             
+              int global_funct2(void);
+              """,
+            "string",
+        )
+
+    def test_num_functions(self):
+        self.assertEqual(len(self.cppHeader.functions), 2)
+
+    def test_function_name_1(self):
+        self.assertEqual(self.cppHeader.functions[0]["name"], "global_funct1")
+
+    def test_function_name_2(self):
+        self.assertEqual(self.cppHeader.functions[1]["name"], "global_funct2")
+
+
+# Bug 3536071
+class Pea_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_num_inherits(self):
+        self.assertEqual(len(self.cppHeader.classes["Pea"]["inherits"]), 1)
+
+    def test_name_inherits(self):
+        self.assertEqual(
+            self.cppHeader.classes["Pea"]["inherits"][0]["class"], "Vegetable"
+        )
+
+
+# Bug 3540172
+class functions2_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader(
+            """\
+              void global_funct1(int i);             
+              int global_funct2(void){
+                  // do something
+              }
+              """,
+            "string",
+        )
+
+    def test_num_functions(self):
+        self.assertEqual(len(self.cppHeader.functions), 2)
+
+    def test_function_name_1(self):
+        self.assertEqual(self.cppHeader.functions[0]["name"], "global_funct1")
+
+    def test_function_name_2(self):
+        self.assertEqual(self.cppHeader.functions[1]["name"], "global_funct2")
+
+
+# Feature: line numbers
+class line_num_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("LineNumTest.h")
+
+    def test_lineno_function1(self):
+        return self.assertEqual(self.cppHeader.functions[0]["line_number"], 13)
+
+    def test_lineno_function2(self):
+        return self.assertEqual(self.cppHeader.functions[1]["line_number"], 17)
+
+    def test_lineno_Worm(self):
+        return self.assertEqual(self.cppHeader.classes["Worm"]["line_number"], 20)
+
+    def test_lineno_Worm_Constructor(self):
+        return self.assertEqual(
+            self.cppHeader.classes["Worm"]["methods"]["public"][0]["line_number"], 23
+        )
+
+    def test_lineno_Worm_getName(self):
+        return self.assertEqual(
+            self.cppHeader.classes["Worm"]["methods"]["public"][1]["line_number"], 24
+        )
+
+    def test_lineno_Worm_namep(self):
+        return self.assertEqual(
+            self.cppHeader.classes["Worm"]["properties"]["private"][0]["line_number"],
+            29,
+        )
+
+
+# Bug 3567172
+class Pear_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_property(self):
+        self.assertEqual(
+            self.cppHeader.classes["Pear"]["properties"]["private"][0]["name"],
+            "stem_property",
+        )
+
+
+# Bug 3567217 and 3569663
+class Macro_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader(
+            r"""
+#include 
+#include "../../debug.h"
+
+#define ONE 1
+#define TWO_NUM_N_NAME "2 (TWO)"
+#pragma once
+
+ #define DEBUG_PRINT(x)           \
+    printf("---------------\n"); \
+    printf("DEBUG: %d\n", x);    \
+    printf("---------------\n");""",
+            "string",
+        )
+
+    def test_includes(self):
+        self.assertEqual(self.cppHeader.includes, ["", '"../../debug.h"'])
+        self.assertEqual(self.cppHeader.includes_detail[0]["value"], "")
+        self.assertEqual(self.cppHeader.includes_detail[0]["line_number"], 2)
+        self.assertEqual(self.cppHeader.includes_detail[1]["value"], '"../../debug.h"')
+        self.assertEqual(self.cppHeader.includes_detail[1]["line_number"], 3)
+
+    def test_pragmas(self):
+        self.assertEqual(self.cppHeader.pragmas, ["once"])
+        self.assertEqual(self.cppHeader.pragmas_detail[0]["value"], "once")
+        self.assertEqual(self.cppHeader.pragmas_detail[0]["line_number"], 7)
+
+    def test_pragmas0(self):
+        self.assertEqual(self.cppHeader.defines[0], "ONE 1")
+        self.assertEqual(self.cppHeader.defines_detail[0]["value"], "ONE 1")
+        self.assertEqual(self.cppHeader.defines_detail[0]["line_number"], 5)
+
+    def test_pragmas1(self):
+        self.assertEqual(self.cppHeader.defines[1], 'TWO_NUM_N_NAME "2 (TWO)"')
+        self.assertEqual(
+            self.cppHeader.defines_detail[1]["value"], 'TWO_NUM_N_NAME "2 (TWO)"'
+        )
+        self.assertEqual(self.cppHeader.defines_detail[1]["line_number"], 6)
+
+    def test_pragmas2(self):
+        self.assertEqual(
+            self.cppHeader.defines[2],
+            'DEBUG_PRINT(x)           \\\n    printf("---------------\\n"); \\\n    printf("DEBUG: %d\\n", x);    \\\n    printf("---------------\\n");',
+        )
+
+
+# Bug: 3567854 and 3568241
+class Beans_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_public_props(self):
+        self.assertEqual(
+            len(self.cppHeader.classes["Beans"]["properties"]["public"]), 4
+        )
+        self.assertEqual(
+            self.cppHeader.classes["Beans"]["properties"]["public"][2]["name"], "data"
+        )
+
+    def test_anonymous_union_name(self):
+        return self.assertEqual(
+            self.cppHeader.classes["Beans"]["properties"]["public"][1]["name"], ""
+        )
+
+    def test_second_anonymous_union_name(self):
+        return self.assertEqual(
+            self.cppHeader.classes["Beans"]["properties"]["public"][3]["name"], ""
+        )
+
+
+# Bug: 3567854 and 3568241
+class termite_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_termite_function(self):
+        f = self.cppHeader.functions[5]
+        self.assertEqual(f["name"], "termite")
+        self.assertEqual(len(f["parameters"]), 0)
+
+
+# Bug: 3569622
+class Japyx_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_japyxFunc(self):
+        self.assertEqual(self.cppHeader.functions[6]["name"], "japyxFunc")
+
+
+# Bug: 3570105
+class Author_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(self.cppHeader.enums[0]["name"], "Author")
+
+    def test_name(self):
+        self.assertEqual(
+            self.cppHeader.enums[0]["values"],
+            [{"name": "NAME", "value": "( 'J' << 24 | 'A' << 16 | 'S' << 8 | 'H' )"}],
+        )
+
+
+# Bug: 3577484
+class Fly_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_exists(self):
+        self.assertEqual("FruitFly" in self.cppHeader.classes, True)
+
+
+# Bug BitBucket #2
+class ClassAfterMagicMacro_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_class_exists(self):
+        self.assertEqual("ClassAfterMagicMacro" in self.cppHeader.classes, True)
+
+
+# Bug BitBucket #3
+class FilterMagicMacro_TestCase(unittest.TestCase):
+    def setUp(self):
+        savedIgnoreSymbols = CppHeaderParser.ignoreSymbols
+        CppHeaderParser.ignoreSymbols.append("MAGIC_FUNC()")
+        self.cppHeader = CppHeaderParser.CppHeader(
+            r"""
+class FilterMagicMacro
+{
+public:
+
+  MAGIC_FUNC(var)
+  MAGIC_FUNC(v,
+             a,
+             r)
+  MAGIC_FUNC((int)var)
+  MAGIC_FUNC(((()))var()()())
+  MAGIC_FUNC("1) \" var")
+
+  void FilterMagicMacroMethod(int);
+};""",
+            "string",
+        )
+        CppHeaderParser.ignoreSymbols = savedIgnoreSymbols
+
+    def test_method_exists(self):
+        self.assertEqual(
+            self.cppHeader.classes["FilterMagicMacro"]["methods"]["public"][0]["name"],
+            "FilterMagicMacroMethod",
+        )
+
+    def test_line_num_is_correct(self):
+        self.assertEqual(
+            self.cppHeader.classes["FilterMagicMacro"]["methods"]["public"][0][
+                "line_number"
+            ],
+            14,
+        )
+
+
+# Bug BitBucket #4
+class ClassRegularTypedefs_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_uint_exists(self):
+        self.assertEqual("uint" in self.cppHeader.typedefs, True)
+
+    def test_string_array_exists(self):
+        self.assertEqual("string_array" in self.cppHeader.typedefs, True)
+
+    def test_SmartObjPtr_exists(self):
+        self.assertEqual("SmartObjPtr" in self.cppHeader.typedefs, True)
+
+    def test_StrStrMap_exists(self):
+        self.assertEqual("StrStrMap" in self.cppHeader.typedefs, True)
+
+    def test_AfterTypedefClass_exists(self):
+        self.assertEqual("AfterTypedefClass" in self.cppHeader.classes, True)
+
+
+# Bug BitBucket #6
+class LineNumAfterDivide_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader(
+            """
+
+// Bug BitBucket #6
+class LineNumAfterDivide
+{
+  static int func1(float alpha_num)
+  { return funcX(alpha_num /
+                 beta_num); }
+  void func2();
+};
+
+""",
+            "string",
+        )
+
+    def test_line_num(self):
+        m = self.cppHeader.classes["LineNumAfterDivide"]["methods"]["private"][1]
+        self.assertEqual("func2", m["name"])
+        self.assertEqual(9, m["line_number"])
+
+
+# Bug BitBucket #5
+class ClassHerbCilantro_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_HerbCilantro_exists(self):
+        self.assertEqual("Herb::Cilantro" in self.cppHeader.classes, True)
+
+
+# Bug BitBucket #7
+class print_statement_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_function_name_type(self):
+        self.assertEqual(self.cppHeader.functions[7]["name"], "print_statement")
+
+    def test_return_type(self):
+        self.assertEqual(self.cppHeader.functions[7]["returns"], "int")
+
+
+# Bug BitBucket #8
+class Garlic_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_function_exists(self):
+        self.assertEqual(
+            self.cppHeader.classes["Garlic"]["methods"]["public"][0]["name"], "genNum"
+        )
+
+
+# Bug SourceForge #54
+class Wheat_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(self.cppHeader.enums[1]["name"], "Wheat")
+
+    def test_typedef(self):
+        self.assertEqual(self.cppHeader.enums[1]["typedef"], False)
+
+
+# Bug SourceForge #55
+class PeachPlumb_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_Peach_exists(self):
+        self.assertEqual("Peach" in self.cppHeader.classes, True)
+
+    def test_Plumb_exists(self):
+        self.assertEqual("Plumb" in self.cppHeader.classes, True)
+
+    def test_function_exists(self):
+        self.assertEqual(
+            self.cppHeader.classes["Plumb"]["methods"]["private"][0]["name"],
+            "doSomethingGreat",
+        )
+
+
+# Bug BitBucket #9
+class Grape_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_Grape_exists(self):
+        self.assertEqual("Grape" in self.cppHeader.classes, True)
+
+    def test_a_exists(self):
+        self.assertEqual(
+            self.cppHeader.classes["Grape"]["properties"]["public"][0]["name"], "a"
+        )
+
+    def test_a_type(self):
+        self.assertEqual(
+            self.cppHeader.classes["Grape"]["properties"]["public"][0]["type"], "int"
+        )
+
+    def test_b_exists(self):
+        self.assertEqual(
+            self.cppHeader.classes["Grape"]["properties"]["public"][1]["name"], "b"
+        )
+
+    def test_b_type(self):
+        self.assertEqual(
+            self.cppHeader.classes["Grape"]["properties"]["public"][1]["type"], "int"
+        )
+
+    def test_c_exists(self):
+        self.assertEqual(
+            self.cppHeader.classes["Grape"]["properties"]["public"][2]["name"], "c"
+        )
+
+    def test_d_exists(self):
+        self.assertEqual(
+            self.cppHeader.classes["Grape"]["properties"]["public"][3]["name"], "d"
+        )
+
+    def test_e_exists(self):
+        self.assertEqual(
+            self.cppHeader.classes["Grape"]["properties"]["public"][4]["name"], "e"
+        )
+
+    def test_f_exists(self):
+        self.assertEqual(
+            self.cppHeader.classes["Grape"]["properties"]["public"][5]["name"], "f"
+        )
+
+
+# Bug BitBucket #14
+class Avacado_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_Avacado_exists(self):
+        self.assertEqual("Avacado" in self.cppHeader.classes, True)
+
+    def test_foo_return_type(self):
+        self.assertEqual(
+            self.cppHeader.classes["Avacado"]["methods"]["public"][0]["returns"],
+            "uint8_t",
+        )
+
+    def test_bar_return_type(self):
+        self.assertEqual(
+            self.cppHeader.classes["Avacado"]["methods"]["public"][1]["returns"],
+            "::uint8_t",
+        )
+
+
+# Bug BitBucket #13
+class Raspberry_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_anon_struct_1_exists(self):
+        self.assertEqual("" in self.cppHeader.classes, True)
+
+    def test_beta_exists(self):
+        self.assertEqual(
+            self.cppHeader.classes[""]["properties"]["public"][0][
+                "name"
+            ],
+            "anon_struct_variable",
+        )
+
+    def test_Raspberry_exists(self):
+        self.assertEqual("Raspberry" in self.cppHeader.classes, True)
+
+    def test_a_exists(self):
+        self.assertEqual(
+            self.cppHeader.classes["Raspberry"]["properties"]["public"][0]["name"], "a"
+        )
+
+
+# Bug BitBucket #15 & 16
+class Hen_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_default_a(self):
+        self.assertEqual(
+            self.cppHeader.classes["Hen"]["methods"]["public"][0]["parameters"][0][
+                "defaultValue"
+            ],
+            "100",
+        )
+
+    def test_default_b(self):
+        self.assertEqual(
+            self.cppHeader.classes["Hen"]["methods"]["public"][0]["parameters"][1][
+                "defaultValue"
+            ],
+            "0xfd",
+        )
+
+    def test_default_c(self):
+        self.assertEqual(
+            self.cppHeader.classes["Hen"]["methods"]["public"][0]["parameters"][2][
+                "defaultValue"
+            ],
+            "1.7e-3",
+        )
+
+    def test_default_d(self):
+        self.assertEqual(
+            self.cppHeader.classes["Hen"]["methods"]["public"][0]["parameters"][3][
+                "defaultValue"
+            ],
+            "3.14",
+        )
+
+    def test_default_s1(self):
+        self.assertEqual(
+            self.cppHeader.classes["Hen"]["methods"]["public"][1]["parameters"][0][
+                "defaultValue"
+            ],
+            '""',
+        )
+
+    def test_default_s2(self):
+        self.assertEqual(
+            self.cppHeader.classes["Hen"]["methods"]["public"][1]["parameters"][1][
+                "defaultValue"
+            ],
+            '"nothing"',
+        )
+
+
+# Bug BitBucket #19
+class Raddish_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_Avacado_exists(self):
+        self.assertEqual(
+            self.cppHeader.classes["Raddish_SetIterator"]["properties"]["protected"][0][
+                "name"
+            ],
+            "_beg",
+        )
+
+    def test_class_template(self):
+        template_str = "template>"
+        self.assertEqual(
+            self.cppHeader.classes["Raddish_SetIterator"]["template"], template_str
+        )
+
+
+# Bug bug 57
+class Carambola_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual(self.cppHeader.enums[2]["name"], "Carambola")
+
+    def test_values(self):
+        self.assertEqual(
+            self.cppHeader.enums[2]["values"],
+            [{"name": "StarFruit", "value": "( 2 + 2 ) / 2"}],
+        )
+
+    def test_typedef(self):
+        self.assertEqual(self.cppHeader.enums[2]["typedef"], True)
+
+
+# globals
+class Globals_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_externVar_name(self):
+        self.assertEqual(self.cppHeader.variables[2]["name"], "externVar")
+
+    def test_externVar_extern(self):
+        self.assertEqual(self.cppHeader.variables[2]["extern"], 1)
+
+    def test_globalVar_name(self):
+        self.assertEqual(self.cppHeader.variables[3]["name"], "globalVar")
+
+    def test_globalVar_extern(self):
+        self.assertEqual(self.cppHeader.variables[3]["extern"], 0)
+
+
+# globals
+class TypedefArray_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual("TenCharArray[10]" in self.cppHeader.typedefs, True)
+
+    def test_value(self):
+        self.assertEqual(self.cppHeader.typedefs["TenCharArray[10]"], "char")
+
+
+# typedef structs
+class TypedefStruct_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_name(self):
+        self.assertEqual("MAGIC_FILE" in self.cppHeader.typedefs, True)
+
+    def test_value(self):
+        self.assertEqual(
+            self.cppHeader.typedefs["MAGIC_FILE"], "struct SUPER_MAGIC_FILE"
+        )
+
+
+# Bug SourceForge #10
+class Picture_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_array_size(self):
+        self.assertEqual(
+            self.cppHeader.classes["Picture"]["properties"]["public"][1]["array_size"],
+            "16384",
+        )
+
+    def test_multi_dimensional_array_size(self):
+        self.assertEqual(
+            self.cppHeader.classes["Picture"]["properties"]["public"][1][
+                "multi_dimensional_array_size"
+            ],
+            "128x128",
+        )
+
+
+# SourceForge bug 58
+class Apricot_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_Apricot_exists(self):
+        self.assertEqual("Apricot" in self.cppHeader.classes, True)
+
+    def test_i_exists(self):
+        self.assertEqual(self.cppHeader.classes["Apricot"]["members"][0]["name"], "i")
+
+    def test_f_exists(self):
+        self.assertEqual(self.cppHeader.classes["Apricot"]["members"][1]["name"], "f")
+
+    def test_s_exists(self):
+        self.assertEqual(self.cppHeader.classes["Apricot"]["members"][2]["name"], "s")
+
+
+# SourceForge bug 59
+class LemonLime_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_lemon_not_final(self):
+        self.assertEqual(self.cppHeader.classes["Lemon"]["final"], False)
+
+    def test_lime_final(self):
+        self.assertEqual(self.cppHeader.classes["Lime"]["final"], True)
+
+    def test_lemon_foo_is_final(self):
+        self.assertEqual(
+            self.cppHeader.classes["Lemon"]["methods"]["public"][0]["final"], True
+        )
+
+    def test_lemon_foo2_is_not_final(self):
+        self.assertEqual(
+            self.cppHeader.classes["Lemon"]["methods"]["public"][1]["final"], False
+        )
+
+    def test_lime_abc_is_not_override(self):
+        self.assertEqual(
+            self.cppHeader.classes["Lime"]["methods"]["public"][0]["override"], False
+        )
+
+    def test_lime_foo2_is_not_override(self):
+        self.assertEqual(
+            self.cppHeader.classes["Lime"]["methods"]["public"][1]["override"], True
+        )
+
+
+class JSON_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader(
+            r"""
+struct Lemon
+{
+    virtual void foo() final;
+    virtual void foo2();
+};
+ 
+struct Lime final : Lemon
+{
+    void abc();
+    void foo2() override;
+};""",
+            "string",
+        )
+        self.jsonString = self.cppHeader.toJSON()
+
+    def test_hasLemon(self):
+        hasString = '        "Lemon": {' in self.jsonString
+        self.assertEqual(hasString, True)
+
+    def test_can_parse_complex_file(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+        j = self.cppHeader.toJSON()
+
+
+# BitBucket bug 24
+class Mouse_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_MouseClass_exists(self):
+        self.assertEqual("MouseClass" in self.cppHeader.classes, True)
+
+    def test_mouse_typedef_correct_value(self):
+        self.assertEqual(
+            self.cppHeader.classes["MouseClass"]["methods"]["public"][0]["parameters"][
+                0
+            ]["raw_type"],
+            "MouseNS::MouseClass::mouse_typedef",
+        )
+
+
+# BitBucket bug 26
+class Fig_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_Fig_exists(self):
+        self.assertEqual("Fig" in self.cppHeader.classes, True)
+
+    def test_a_exists(self):
+        self.assertEqual(
+            self.cppHeader.classes["Grape"]["properties"]["public"][0]["name"], "a"
+        )
+
+
+# BitBucket bug 27
+class Olive_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_Olive_exists(self):
+        self.assertEqual("olive" in self.cppHeader.classes, True)
+
+    def test_union_member_x(self):
+        cmp_values = {
+            "constant": 0,
+            "name": "x",
+            "reference": 0,
+            "type": "int",
+            "static": 0,
+            "pointer": 0,
+        }
+        self.assertEqual(
+            filter_dict_keys(
+                self.cppHeader.classes["olive"]["members"][0], cmp_values.keys()
+            ),
+            cmp_values,
+        )
+
+
+# BitBucket bug 61
+class Beet_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_Beet_exists(self):
+        self.assertEqual("BeetStruct" in self.cppHeader.classes, True)
+
+    def test_BeetEnum_exists(self):
+        self.assertEqual(
+            self.cppHeader.classes["BeetStruct"]["enums"]["public"][0]["name"],
+            "BeetEnum",
+        )
+
+
+# BitBucket bug 40
+class set_callback_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_set_callback(self):
+        self.assertEqual(self.cppHeader.functions[8]["name"], "set_callback")
+        self.assertEqual(
+            self.cppHeader.functions[8]["parameters"][1]["name"], "callback"
+        )
+        self.assertEqual(
+            self.cppHeader.functions[8]["parameters"][1]["function_pointer"], 1
+        )
+        self.assertEqual(
+            self.cppHeader.functions[8]["parameters"][1]["type"],
+            "long ( * ) ( struct test_st *, int, const char *, int long, long, long )",
+        )
+
+
+# BitBucket bug 45
+class HALControlWord_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader(
+            """\
+            struct HAL_ControlWord {
+                int x : 1;
+                int y : 1;
+            };
+            typedef struct HAL_ControlWord HAL_ControlWord;
+            int HAL_GetControlWord(HAL_ControlWord* controlWord);
+        """,
+            "string",
+        )
+
+    def test_functions(self):
+        self.assertEqual(len(self.cppHeader.functions), 1)
+        self.assertEqual(self.cppHeader.functions[0]["name"], "HAL_GetControlWord")
+
+    def test_classes(self):
+        self.assertEqual(len(self.cppHeader.classes), 1)
+        self.assertEqual(
+            self.cppHeader.classes["HAL_ControlWord"]["name"], "HAL_ControlWord"
+        )
+
+    def test_num_typedefs(self):
+        self.assertEqual(len(self.cppHeader.typedefs), 1)
+        self.assertEqual(
+            self.cppHeader.typedefs["HAL_ControlWord"], "struct HAL_ControlWord"
+        )
+
+
+# Bitbucket bug 47
+class CommentEOF_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader(
+            """
+namespace a {
+}  // namespace a""",
+            "string",
+        )
+
+    def test_comment(self):
+        self.assertTrue("a" in self.cppHeader.namespaces)
+
+
+# BitBucket bug 35
+class Grackle_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_Grackle_exists(self):
+        self.assertEqual("Grackle" in self.cppHeader.classes, True)
+
+    def test_Grackle_no_noexcept_None(self):
+        self.assertEqual(
+            self.cppHeader.classes["Grackle"]["methods"]["public"][0]["noexcept"], None
+        )
+
+    def test_Grackle_noexcept(self):
+        self.assertEqual(
+            self.cppHeader.classes["Grackle"]["methods"]["public"][1]["noexcept"],
+            "noexcept",
+        )
+
+    def test_Grackle_const_noexcept(self):
+        self.assertEqual(
+            self.cppHeader.classes["Grackle"]["methods"]["public"][2]["const"], True
+        )
+        self.assertEqual(
+            self.cppHeader.classes["Grackle"]["methods"]["public"][2]["noexcept"],
+            "noexcept",
+        )
+
+    def test_Grackle_noexcept_true(self):
+        self.assertEqual(
+            self.cppHeader.classes["Grackle"]["methods"]["public"][3]["noexcept"],
+            "noexcept(true)",
+        )
+
+    def test_Grackle_const_noexcept_true(self):
+        self.assertEqual(
+            self.cppHeader.classes["Grackle"]["methods"]["public"][4]["const"], True
+        )
+        self.assertEqual(
+            self.cppHeader.classes["Grackle"]["methods"]["public"][4]["noexcept"],
+            "noexcept(true)",
+        )
+
+    def test_Grackle_noexcept_noexcept_operator(self):
+        self.assertEqual(
+            self.cppHeader.classes["Grackle"]["methods"]["public"][5]["noexcept"],
+            "noexcept(noexcept(Grackle()))",
+        )
+
+    def test_Grackle_const_noexcept_noexcept_operator(self):
+        self.assertEqual(
+            self.cppHeader.classes["Grackle"]["methods"]["public"][6]["const"], True
+        )
+        self.assertEqual(
+            self.cppHeader.classes["Grackle"]["methods"]["public"][6]["noexcept"],
+            "noexcept(noexcept(Grackle()))",
+        )
+
+
+# Test enhancement 13 (default constructor / destructor)
+class DefaultConstDest_TestCase:
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_DefaultConstDest_exists(self):
+        self.assertEqual("DefaultConstDest" in self.cppHeader.classes, True)
+        self.assertEqual("default_class_tricky" in self.cppHeader.classes, True)
+
+    def test_DefaultConstDest_constructor_default(self):
+        self.assertEqual(
+            self.cppHeader.classes["DefaultConstDest"]["methods"]["public"][0][
+                "constructor"
+            ],
+            True,
+        )
+        self.assertEqual(
+            self.cppHeader.classes["DefaultConstDest"]["methods"]["public"][0][
+                "default"
+            ],
+            True,
+        )
+        self.assertEqual(
+            self.cppHeader.classes["DefaultConstDest"]["methods"]["public"][0][
+                "defined"
+            ],
+            True,
+        )
+
+    def test_DefaultConstDest_destructor_default(self):
+        self.assertEqual(
+            self.cppHeader.classes["DefaultConstDest"]["methods"]["public"][1][
+                "destructor"
+            ],
+            True,
+        )
+        self.assertEqual(
+            self.cppHeader.classes["DefaultConstDest"]["methods"]["public"][1][
+                "default"
+            ],
+            True,
+        )
+        self.assertEqual(
+            self.cppHeader.classes["DefaultConstDest"]["methods"]["public"][1][
+                "defined"
+            ],
+            True,
+        )
+
+    def test_DefaultConstDest_default_edgeCaseNaming(self):
+        self.assertEqual(
+            self.cppHeader.classes["default_class_tricky"]["methods"]["public"][0][
+                "constructor"
+            ],
+            True,
+        )
+        self.assertEqual(
+            self.cppHeader.classes["default_class_tricky"]["methods"]["public"][0][
+                "default"
+            ],
+            False,
+        )
+        self.assertEqual(
+            self.cppHeader.classes["default_class_tricky"]["methods"]["public"][0][
+                "defined"
+            ],
+            False,
+        )
+        self.assertEqual(
+            self.cppHeader.classes["default_class_tricky"]["methods"]["public"][1][
+                "destructor"
+            ],
+            True,
+        )
+        self.assertEqual(
+            self.cppHeader.classes["default_class_tricky"]["methods"]["public"][1][
+                "default"
+            ],
+            False,
+        )
+        self.assertEqual(
+            self.cppHeader.classes["default_class_tricky"]["methods"]["public"][1][
+                "defined"
+            ],
+            False,
+        )
+        self.assertEqual(
+            self.cppHeader.classes["default_class_tricky"]["methods"]["public"][2][
+                "name"
+            ],
+            "randomMethod1_default",
+        )
+        self.assertEqual(
+            self.cppHeader.classes["default_class_tricky"]["methods"]["public"][2][
+                "destructor"
+            ],
+            False,
+        )
+        self.assertEqual(
+            self.cppHeader.classes["default_class_tricky"]["methods"]["public"][2][
+                "default"
+            ],
+            False,
+        )
+        self.assertEqual(
+            self.cppHeader.classes["default_class_tricky"]["methods"]["public"][2][
+                "defined"
+            ],
+            False,
+        )
+        self.assertEqual(
+            self.cppHeader.classes["default_class_tricky"]["methods"]["public"][3][
+                "name"
+            ],
+            "defaultrandomMethod2",
+        )
+        self.assertEqual(
+            self.cppHeader.classes["default_class_tricky"]["methods"]["public"][3][
+                "destructor"
+            ],
+            False,
+        )
+        self.assertEqual(
+            self.cppHeader.classes["default_class_tricky"]["methods"]["public"][3][
+                "default"
+            ],
+            False,
+        )
+        self.assertEqual(
+            self.cppHeader.classes["default_class_tricky"]["methods"]["public"][3][
+                "defined"
+            ],
+            False,
+        )
+
+
+class VarargFunc_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader("TestSampleClass.h")
+
+    def test_vararg_func(self):
+        vf = next(x for x in self.cppHeader.functions if x["name"] == "vararg_func")
+        nvf = next(
+            x for x in self.cppHeader.functions if x["name"] == "non_vararg_func"
+        )
+        self.assertTrue(vf["vararg"])
+        self.assertFalse(nvf["vararg"])
+        self.assertEqual(len(vf["parameters"]), len(nvf["parameters"]))
+
+
+class UsingNamespace_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader(
+            """
+using std::thing;
+using MyThing = SomeThing;
+namespace a {
+    using std::string;
+    using VoidFunction = std::function;
+
+    void fn(string &s, VoidFunction fn, thing * t);
+
+    class A : public B {
+    public:
+        using B::B;
+        using IntFunction = std::function;
+
+        void a(string &s, IntFunction fn, thing * t);
+    };
+}
+""",
+            "string",
+        )
+
+    def test_using(self):
+        self.assertEqual(len(self.cppHeader.using), 4)
+
+        self.assertEqual(
+            filter_pameters(
+                [self.cppHeader.using["a::string"]],
+                extra=["using_type", "raw_type", "namespace"],
+            ),
+            [
+                {
+                    "desc": None,
+                    "name": "",
+                    "namespace": "std::",
+                    "raw_type": "std::string",
+                    "type": "string",
+                    "using_type": "declaration",
+                }
+            ],
+        )
+
+        self.assertEqual(
+            filter_pameters(
+                [self.cppHeader.using["a::VoidFunction"]],
+                extra=["using_type", "raw_type", "namespace", "typealias"],
+            ),
+            [
+                {
+                    "desc": None,
+                    "name": "",
+                    "namespace": "std::",
+                    "raw_type": "std::function",
+                    "type": "function",
+                    "typealias": "VoidFunction",
+                    "using_type": "typealias",
+                }
+            ],
+        )
+
+        self.assertEqual(
+            filter_pameters(
+                [self.cppHeader.using["thing"]],
+                extra=["using_type", "raw_type", "namespace"],
+            ),
+            [
+                {
+                    "desc": None,
+                    "name": "",
+                    "namespace": "std::",
+                    "raw_type": "std::thing",
+                    "type": "thing",
+                    "using_type": "declaration",
+                }
+            ],
+        )
+
+        self.assertEqual(
+            filter_pameters(
+                [self.cppHeader.using["MyThing"]],
+                extra=["using_type", "raw_type", "namespace", "typealias"],
+            ),
+            [
+                {
+                    "desc": None,
+                    "name": "",
+                    "namespace": "",
+                    "raw_type": "SomeThing",
+                    "type": "SomeThing",
+                    "typealias": "MyThing",
+                    "using_type": "typealias",
+                }
+            ],
+        )
+
+    def test_fn(self):
+        self.assertEqual(len(self.cppHeader.functions), 1)
+        fn = self.cppHeader.functions[0]
+        self.assertEqual(fn["name"], "fn")
+        self.assertEqual(
+            filter_pameters(fn["parameters"], ["namespace", "raw_type"]),
+            [
+                {
+                    "type": "string",
+                    "name": "s",
+                    "desc": None,
+                    "namespace": "std::",
+                    "raw_type": "std::string",
+                },
+                {
+                    "type": "function",
+                    "name": "fn",
+                    "desc": None,
+                    "namespace": "std::",
+                    "raw_type": "std::function",
+                },
+                {
+                    "type": "thing",
+                    "name": "t",
+                    "desc": None,
+                    "namespace": "std::",
+                    "raw_type": "std::thing",
+                },
+            ],
+        )
+
+    def test_class(self):
+        c = self.cppHeader.classes["A"]
+
+        self.assertEqual(len(c["using"]), 2)
+        self.assertIn("B", c["using"])
+        self.assertIn("IntFunction", c["using"])
+
+        self.assertEqual(len(c["methods"]["public"]), 1)
+        fn = c["methods"]["public"][0]
+        self.assertEqual(fn["name"], "a")
+        self.assertEqual(
+            filter_pameters(fn["parameters"], ["namespace", "raw_type"]),
+            [
+                {
+                    "type": "string",
+                    "name": "s",
+                    "desc": None,
+                    "namespace": "std::",
+                    "raw_type": "std::string",
+                },
+                {
+                    "type": "function",
+                    "name": "fn",
+                    "desc": None,
+                    "namespace": "std::",
+                    "raw_type": "std::function",
+                },
+                {
+                    "type": "thing",
+                    "name": "t",
+                    "desc": None,
+                    "namespace": "std::",
+                    "raw_type": "std::thing",
+                },
+            ],
+        )
+
+
+class StaticFn_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader(
+            """
+class A {
+    static int fn();
+};
+""",
+            "string",
+        )
+
+    def test_fn(self):
+        m = self.cppHeader.classes["A"]["methods"]["private"][0]
+        self.assertEqual(m["static"], True)
+        self.assertEqual(m["rtnType"], "int")
+
+
+class ConstExpr_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader(
+            """
+class A {
+    static constexpr double kThing = 0.02;
+};
+""",
+            "string",
+        )
+
+    def test_fn(self):
+        p = self.cppHeader.classes["A"]["properties"]["private"][0]
+        self.assertEqual(p["static"], 1)
+        self.assertEqual(p["constexpr"], 1)
+        self.assertEqual(p["raw_type"], "double")
+        self.assertEqual(p["defaultValue"], "0.02")
+
+
+class ConstExprFn_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader(
+            """
+constexpr int overloaded_constexpr(int a, int b, int c) { return a + b + c; }
+""",
+            "string",
+        )
+
+    def test_fn(self):
+        m = self.cppHeader.functions[0]
+        self.assertEqual(m["constexpr"], True)
+        self.assertEqual(m["rtnType"], "int")
+
+
+class DefaultEnum_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader(
+            """
+class A {
+    enum {
+        v1,
+        v2,
+    } m_v1 = v1;
+
+    enum {
+        vv1,
+        vv2, vv3
+    } m_v2 = vv2, m_v3 = vv3;
+};
+""",
+            "string",
+        )
+
+    def test_fn(self):
+        p = self.cppHeader.classes["A"]["properties"]["private"][0]
+        self.assertEqual("enum", p["type"])
+        self.assertEqual("m_v1", p["name"])
+        self.assertEqual("v1", p["default"])
+        self.assertEqual(
+            p.get("enum_type", {}).get("values"),
+            [{"name": "v1", "value": 0}, {"name": "v2", "value": 1}],
+        )
+
+        p = self.cppHeader.classes["A"]["properties"]["private"][1]
+        self.assertEqual("enum", p["type"])
+        self.assertEqual("m_v2", p["name"])
+        self.assertEqual("vv2", p["default"])
+        self.assertEqual(
+            p.get("enum_type", {}).get("values"),
+            [
+                {"name": "vv1", "value": 0},
+                {"name": "vv2", "value": 1},
+                {"name": "vv3", "value": 2},
+            ],
+        )
+
+        p = self.cppHeader.classes["A"]["properties"]["private"][2]
+        self.assertEqual("enum", p["type"])
+        self.assertEqual("m_v3", p["name"])
+        self.assertEqual("vv3", p["default"])
+        self.assertEqual(
+            p.get("enum_type", {}).get("values"),
+            [
+                {"name": "vv1", "value": 0},
+                {"name": "vv2", "value": 1},
+                {"name": "vv3", "value": 2},
+            ],
+        )
+
+
+class MultiFile_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader(
+            """
+#line 3 "child.h"
+#include 
+#line 3 "base.h"
+void functionInBase(void);
+
+class Base
+{
+public:
+    virtual void baseFunction();
+};
+#line 7 "child.h"
+void functionInChild(void);
+
+class Child : public Base
+{
+public:
+    void childOnlyFunction();
+    void baseFunction() override;
+};
+
+""",
+            "string",
+        )
+
+    def assertLocation(self, thing, fname, lineno):
+        self.assertEqual(fname, thing["filename"])
+        self.assertEqual(lineno, thing["line_number"])
+
+    def test_fn(self):
+        baseFn = self.cppHeader.functions[0]
+        self.assertEqual("functionInBase", baseFn["name"])
+        self.assertLocation(baseFn, "base.h", 3)
+
+        base = self.cppHeader.classes["Base"]
+        self.assertLocation(base, "base.h", 5)
+
+        childFn = self.cppHeader.functions[1]
+        self.assertEqual("functionInChild", childFn["name"])
+        self.assertLocation(childFn, "child.h", 7)
+
+        child = self.cppHeader.classes["Child"]
+        self.assertLocation(child, "child.h", 9)
+
+
+class TemplateMadness_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader(
+            """
+template 
+class XYZ : public MyBaseClass
+{
+    public:
+    XYZ();
+};
+
+template 
+class concat_iterator
+    : public iterator_facade_base,
+                                  std::forward_iterator_tag, ValueT> {
+};
+
+template 
+struct build_index_impl : build_index_impl {};
+
+template 
+struct build_index_impl<0, I...> : index_sequence {};
+
+//template 
+//struct is_callable,
+//        void_t()).*std::declval())(std::declval()...))>>
+//    : std::true_type {};
+
+template 
+struct S : public T... {};
+
+""",
+            "string",
+        )
+
+    def testXYZ(self):
+        c = self.cppHeader.classes["XYZ"]
+        self.assertEqual("XYZ", c["name"])
+        self.assertEqual(
+            [
+                {
+                    "access": "public",
+                    "class": "MyBaseClass",
+                    "decltype": False,
+                    "decl_name": "MyBaseClass",
+                    "decl_params": [
+                        {"param": "Type", "...": False, "decltype": False},
+                        {"param": "int", "...": False, "decltype": False},
+                    ],
+                    "virtual": False,
+                    "...": False,
+                }
+            ],
+            c["inherits"],
+        )
+
+    def testConcatIterator(self):
+        c = self.cppHeader.classes["concat_iterator"]
+        self.assertEqual("concat_iterator", c["name"])
+        self.assertEqual(
+            [
+                {
+                    "access": "public",
+                    "class": "iterator_facade_base,std::forward_iterator_tag,ValueT>",
+                    "decltype": False,
+                    "decl_name": "iterator_facade_base",
+                    "decl_params": [
+                        {
+                            "decltype": False,
+                            "param": "concat_iterator",
+                            "params": [
+                                {"param": "ValueT", "...": False, "decltype": False},
+                                {"param": "IterTs", "...": True, "decltype": False},
+                            ],
+                            "...": False,
+                        },
+                        {
+                            "decltype": False,
+                            "param": "std::forward_iterator_tag",
+                            "...": False,
+                        },
+                        {"decltype": False, "param": "ValueT", "...": False},
+                    ],
+                    "virtual": False,
+                    "...": False,
+                }
+            ],
+            c["inherits"],
+        )
+
+    def testBuildIndexImpl1(self):
+        c = self.cppHeader.classes["build_index_impl"]
+        self.assertEqual("build_index_impl", c["name"])
+        self.assertEqual(
+            [
+                {
+                    "access": "public",
+                    "class": "build_index_impl",
+                    "decltype": False,
+                    "decl_name": "build_index_impl",
+                    "decl_params": [
+                        {"param": "N-1", "...": False, "decltype": False},
+                        {"param": "N-1", "...": False, "decltype": False},
+                        {"param": "I", "...": True, "decltype": False},
+                    ],
+                    "virtual": False,
+                    "...": False,
+                }
+            ],
+            c["inherits"],
+        )
+
+    def testBuildIndexImpl2(self):
+        c = self.cppHeader.classes["build_index_impl<0,I...>"]
+        self.assertEqual("build_index_impl", c["bare_name"])
+        self.assertEqual("build_index_impl<0,I...>", c["name"])
+        self.assertEqual(
+            [
+                {"decltype": False, "param": "0", "...": False},
+                {"decltype": False, "param": "I", "...": True},
+            ],
+            c["class_params"],
+        )
+        self.assertEqual(
+            [
+                {
+                    "access": "public",
+                    "class": "index_sequence",
+                    "decltype": False,
+                    "decl_name": "index_sequence",
+                    "decl_params": [{"decltype": False, "param": "I", "...": True}],
+                    "virtual": False,
+                    "...": False,
+                }
+            ],
+            c["inherits"],
+        )
+
+    # def testIsCallable(self):
+    #     c = self.cppHeader.classes["is_callable"]
+    #     self.assertEqual("is_callable", c["name"])
+    #     self.assertEqual(
+    #         [
+    #             {"param": "F", "...": False, "decltype": False},
+    #             {"param": "P", "...": False, "decltype": False},
+    #             {
+    #                 "param": "typelist",
+    #                 "...": False,
+    #                 "decltype": False,
+    #                 "params": [{"param": "T", "...": True, "decltype": False},],
+    #             },
+    #             {
+    #                 "param": "void_t",
+    #                 "...": False,
+    #                 "decltype": False,
+    #                 "params": [
+    #                     {
+    #                         "param": "(((*std::declval

()).*std::declval())(std::declval()...))", + # "...": False, + # "decltype": True, + # }, + # ], + # }, + # ], + # c["class_params"], + # ) + # self.assertEqual( + # [{"access": "private", "class": "std::true_type", "virtual": False,}], + # c["inherits"], + # ) + + def testS(self): + c = self.cppHeader.classes["S"] + self.assertEqual("S", c["name"]) + self.assertEqual( + [ + { + "access": "public", + "class": "T...", + "decl_name": "T", + "virtual": False, + "...": True, + "decltype": False, + } + ], + c["inherits"], + ) + + +class Attributes_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ + +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 {}; + +""", + "string", + ) + + def test_existance(self): + self.assertIn("S", self.cppHeader.classes) + self.assertIn("PS", self.cppHeader.typedefs) + self.assertEqual("x", self.cppHeader.variables[0]["name"]) + self.assertEqual("f", self.cppHeader.functions[0]["name"]) + self.assertIn("AS", self.cppHeader.classes) + + +class EnumWithTemplates_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +enum { + IsRandomAccess = std::is_base_of::value, + IsBidirectional = std::is_base_of::value, + }; +""", + "string", + ) + + def test_values(self): + e = self.cppHeader.enums[0] + v0 = e["values"][0] + self.assertEqual( + v0["value"], + "std :: is_base_of < std :: random_access_iterator_tag , IteratorCategoryT > :: value", + ) + + v1 = e["values"][1] + self.assertEqual( + v1["value"], + "std :: is_base_of < std :: bidirectional_iterator_tag , IteratorCategoryT > :: value", + ) + + +class FreeTemplates_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ + +template +StringRef copy(Allocator &A) const { + // Don't request a length 0 copy from the allocator. + if (empty()) + return StringRef(); + char *S = A.template Allocate(Length); + std::copy(begin(), end(), S); + return StringRef(S, Length); +} + +""", + "string", + ) + + def test_fn(self): + fn = self.cppHeader.functions[0] + self.assertEqual("copy", fn["name"]) + + +class MessedUpDoxygen_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ + +/// fn comment +void +fn(); + +/// var comment +int +v1 = 0; + +int +v2 = 0; /// var2 comment + +/// cls comment +class +C {}; + +/// template comment +template +class +C2 {}; + +/// hasattr comment +[[nodiscard]] +int hasattr(); + +""", + "string", + ) + + def test_fn(self): + fn = self.cppHeader.functions[0] + self.assertEqual("fn", fn["name"]) + self.assertEqual("/// fn comment", fn["doxygen"]) + + def test_var1(self): + v = self.cppHeader.variables[0] + self.assertEqual("v1", v["name"]) + self.assertEqual("/// var comment", v["doxygen"]) + + def test_var2(self): + v = self.cppHeader.variables[1] + self.assertEqual("v2", v["name"]) + self.assertEqual("/// var2 comment", v["doxygen"]) + + def test_cls(self): + c = self.cppHeader.classes["C"] + self.assertEqual("C", c["name"]) + self.assertEqual("/// cls comment", c["doxygen"]) + + def test_cls2(self): + c = self.cppHeader.classes["C2"] + self.assertEqual("C2", c["name"]) + self.assertEqual("/// template comment", c["doxygen"]) + + def test_hasattr(self): + fn = self.cppHeader.functions[1] + self.assertEqual("hasattr", fn["name"]) + self.assertEqual("/// hasattr comment", fn["doxygen"]) + + +class EnumParameter_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +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 +} + +""", + "string", + ) + + def test_enum_param(self): + fn = self.cppHeader.functions[0] + self.assertEqual("fn_with_enum_param1", fn["name"]) + self.assertEqual(1, len(fn["parameters"])) + + p1 = fn["parameters"][0] + self.assertEqual("e", p1["name"]) + self.assertEqual("const enum E", p1["type"]) + self.assertEqual("int", p1["raw_type"]) + + fn = self.cppHeader.functions[1] + self.assertEqual("fn_with_enum_param2", fn["name"]) + self.assertEqual(1, len(fn["parameters"])) + + p1 = fn["parameters"][0] + self.assertEqual("e", p1["name"]) + self.assertEqual("const enum E", p1["type"]) + self.assertEqual("int", p1["raw_type"]) + + def test_enum_retval(self): + fn = self.cppHeader.functions[2] + self.assertEqual("fn_with_enum_retval1", fn["name"]) + self.assertEqual(0, len(fn["parameters"])) + self.assertEqual("enum E", fn["rtnType"]) + + fn = self.cppHeader.functions[3] + self.assertEqual("fn_with_enum_retval2", fn["name"]) + self.assertEqual(0, len(fn["parameters"])) + self.assertEqual("enum E", fn["rtnType"]) + + +class StaticAssert_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +static_assert(sizeof(int) == 4, + "integer size is wrong" + "for some reason"); +""", + "string", + ) + + def test_nothing(self): + self.assertEqual(self.cppHeader.functions, []) + + +class InitializerWithInitializerList_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +struct ComplexInit : SomeBase { + ComplexInit(int i) : + m_stuff{i,2} + { + auto i = something(); + } + + void fn(); + + std::vector m_stuff; +}; + +template +class future final { +public: + template + future(future&& oth) noexcept + : future(oth.then([](R&& val) -> T { return val; })) {} +}; + + +""", + "string", + ) + + def test_cls_props(self): + c = self.cppHeader.classes["ComplexInit"] + self.assertEqual(2, len(c["methods"]["public"])) + self.assertEqual(0, len(c["methods"]["private"])) + self.assertEqual(0, len(c["methods"]["private"])) + self.assertEqual(1, len(c["properties"]["public"])) + self.assertEqual(0, len(c["properties"]["private"])) + self.assertEqual(0, len(c["properties"]["protected"])) + + self.assertEqual(c["methods"]["public"][0]["name"], "ComplexInit") + self.assertEqual(c["methods"]["public"][1]["name"], "fn") + + self.assertEqual(c["properties"]["public"][0]["name"], "m_stuff") + + def test_future(self): + c = self.cppHeader.classes["future"] + self.assertEqual(1, len(c["methods"]["public"])) + self.assertEqual(0, len(c["methods"]["private"])) + self.assertEqual(0, len(c["methods"]["private"])) + self.assertEqual(0, len(c["properties"]["public"])) + self.assertEqual(0, len(c["properties"]["private"])) + self.assertEqual(0, len(c["properties"]["protected"])) + self.assertEqual(c["methods"]["public"][0]["name"], "future") + + +class EnumClass_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +enum class MyEnum { + V = 1 +}; + +""", + "string", + ) + + def test_enum(self): + self.assertEqual(self.cppHeader.classes, {}) + self.assertEqual(len(self.cppHeader.enums), 1) + e = self.cppHeader.enums[0] + + self.assertEqual(e["name"], "MyEnum") + self.assertEqual( + e["values"], + [{"name": "V", "value": 1}], + ) + self.assertTrue(e["isclass"]) + + +class NestedResolving_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +struct A { + + enum { ANON }; + + struct B {}; + enum C { X }; + + B fnested(B b); + C fenum(C c); +}; + +""", + "string", + ) + + def test_nothing(self): + c = self.cppHeader.classes["A"] + fn = c["methods"]["public"][0] + self.assertEqual(fn["name"], "fnested") + self.assertEqual(fn["rtnType"], "A::B") + self.assertEqual(len(fn["parameters"]), 1) + self.assertEqual(fn["parameters"][0]["raw_type"], "A::B") + + fn = c["methods"]["public"][1] + self.assertEqual(fn["name"], "fenum") + self.assertEqual(fn["rtnType"], "A::C") + self.assertEqual(len(fn["parameters"]), 1) + self.assertEqual(fn["parameters"][0]["enum"], "A::C") + + +class EnumCrash_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +enum HAL_Type { + HAL_UNASSIGNED = 0, +}; + +struct HAL_Value { + union { + HAL_Bool v_boolean; + } data; + enum HAL_Type type; +}; + +""", + "string", + ) + + def test_nothing(self): + pass + + +class ExternInline_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +extern "C++" { +inline HAL_Value HAL_GetSimValue(HAL_SimValueHandle handle) { + HAL_Value v; + return v; +} +} // extern "C++" + +""", + "string", + ) + + def test_fn(self): + self.assertEqual(self.cppHeader.variables, []) + self.assertEqual(len(self.cppHeader.functions), 1) + fn = self.cppHeader.functions[0] + self.assertEqual(fn["name"], "HAL_GetSimValue") + self.assertEqual( + filter_pameters(fn["parameters"], ["namespace", "raw_type"]), + [ + { + "type": "HAL_SimValueHandle", + "name": "handle", + "desc": None, + "namespace": "", + "raw_type": "HAL_SimValueHandle", + }, + ], + ) + self.assertEqual(fn["rtnType"], "HAL_Value") + + +class PointerTemplate_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ + +std::vector * fn(std::vector * ps); + +""", + "string", + ) + + def test_fn(self): + self.assertEqual(len(self.cppHeader.functions), 1) + fn = self.cppHeader.functions[0] + self.assertEqual(fn["name"], "fn") + self.assertEqual( + filter_pameters(fn["parameters"], ["namespace", "raw_type"]), + [ + { + "type": "std::vector *", + "name": "ps", + "desc": None, + "namespace": None, + "raw_type": "std::vector", + }, + ], + ) + self.assertEqual(fn["rtnType"], "std::vector *") + + +class ParamWithInitializer_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +template +void fn(something s = something{1,2,3}); +""", + "string", + ) + + def test_fn(self): + self.assertEqual(len(self.cppHeader.functions), 1) + fn = self.cppHeader.functions[0] + self.assertEqual(fn["name"], "fn") + self.assertEqual( + filter_pameters(fn["parameters"], ["namespace", "raw_type", "default"]), + [ + { + "type": "something", + "name": "s", + "desc": None, + "namespace": "", + "raw_type": "something", + "default": "something{ 1, 2, 3}", + }, + ], + ) + self.assertEqual(fn["rtnType"], "void") + + +class NestedClassAccess_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +class Outer { + struct Inner { + void fn(); + }; + + void ofn(); +}; +""", + "string", + ) + + def test_fn(self): + self.assertEqual(len(self.cppHeader.functions), 0) + + outer = self.cppHeader.classes["Outer"] + self.assertEqual(outer["parent"], None) + + self.assertEqual(0, len(outer["methods"]["public"])) + self.assertEqual(0, len(outer["methods"]["protected"])) + self.assertEqual(1, len(outer["methods"]["private"])) + self.assertEqual("ofn", outer["methods"]["private"][0]["name"]) + + inner = self.cppHeader.classes["Outer::Inner"] + self.assertIs(inner["parent"], outer) + self.assertEqual(inner["access_in_parent"], "private") + + self.assertEqual(1, len(inner["methods"]["public"])) + self.assertEqual(0, len(inner["methods"]["protected"])) + self.assertEqual(0, len(inner["methods"]["private"])) + self.assertEqual("fn", inner["methods"]["public"][0]["name"]) + + +class AnonUnion_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +struct Outer { + union { + int x; + int y; + }; + int z; +}; +""", + "string", + ) + + def test_fn(self): + self.assertEqual(len(self.cppHeader.functions), 0) + + outer = self.cppHeader.classes["Outer"] + self.assertEqual(outer["parent"], None) + + inner = self.cppHeader.classes["Outer::"] + self.assertIs(inner["parent"], outer) + + self.assertEqual(2, len(outer["properties"]["public"])) + self.assertEqual(0, len(outer["properties"]["protected"])) + self.assertEqual(0, len(outer["properties"]["private"])) + + props = outer["properties"]["public"] + self.assertEqual(props[0]["name"], "") + self.assertEqual(props[1]["name"], "z") + + self.assertEqual(2, len(outer["properties"]["public"])) + self.assertEqual(0, len(outer["properties"]["protected"])) + self.assertEqual(0, len(outer["properties"]["private"])) + + props = inner["properties"]["public"] + self.assertEqual(props[0]["name"], "x") + self.assertEqual(props[1]["name"], "y") + + +class Deleted_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +class A { +public: + A() = delete; +}; +""", + "string", + ) + + def test_fn(self): + m = self.cppHeader.classes["A"]["methods"]["public"][0] + self.assertEqual(m["constructor"], True) + self.assertEqual(m["deleted"], True) + + +class BaseTemplateNs_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +class A : public B::C {}; +""", + "string", + ) + + def test_fn(self): + c = self.cppHeader.classes["A"] + self.assertEqual("A", c["name"]) + self.assertEqual( + [ + { + "access": "public", + "class": "B::C", + "decl_name": "B::C", + "virtual": False, + "...": False, + "decltype": False, + } + ], + c["inherits"], + ) + + +class NestedTypedef(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +template class A { + public: + typedef B C; + + A(); + + protected: + C aCInstance; +}; +""", + "string", + ) + + def test_fn(self): + c = self.cppHeader.classes["A"] + self.assertEqual("A", c["name"]) + + self.assertEqual(0, len(c["properties"]["public"])) + self.assertEqual(1, len(c["properties"]["protected"])) + self.assertEqual(0, len(c["properties"]["private"])) + + c = c["properties"]["protected"][0] + self.assertEqual(c["name"], "aCInstance") + self.assertEqual(c["type"], "C") + + +class MoreTypedef(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +typedef C A; + +class B { +public: + A aMethod(); +}; +""", + "string", + ) + + def test_fn(self): + c = self.cppHeader.classes["B"] + self.assertEqual("B", c["name"]) + + m = c["methods"]["public"][0] + self.assertEqual(m["name"], "aMethod") + self.assertEqual(m["rtnType"], "A") + + self.assertEqual(self.cppHeader.typedefs["A"], "C") + + +class InlineVirtual(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +class B { +public: + virtual inline int aMethod(); +}; +""", + "string", + ) + + def test_fn(self): + c = self.cppHeader.classes["B"] + self.assertEqual("B", c["name"]) + + m = c["methods"]["public"][0] + self.assertEqual(m["name"], "aMethod") + self.assertEqual(m["rtnType"], "int") + self.assertEqual(m["returns"], "int") + + +class ForwardDeclResolve(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +namespace n1 { + +class A; + +namespace n2 { + +class B { +public: + explicit B(const A &a); +}; + +} +""", + "string", + ) + + def test_fn(self): + c = self.cppHeader.classes["B"] + self.assertEqual("B", c["name"]) + + m = c["methods"]["public"][0] + self.assertEqual(m["name"], "B") + self.assertEqual(m["parameters"][0]["forward_declared"], "A") + self.assertEqual(m["parameters"][0]["namespace"], "n1::") + self.assertEqual(m["parameters"][0]["name"], "a") + self.assertEqual(m["parameters"][0]["raw_type"], "n1::A") + + +class CompoundNS(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +namespace N1::N2 { +class B {}; +}; +""", + "string", + ) + + def test_fn(self): + c = self.cppHeader.classes["B"] + self.assertEqual("B", c["name"]) + self.assertEqual("N1::N2", c["namespace"]) + + +class TemplateMustBeCleared(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +template class LinearPlantInversionFeedforward { +public: + template + LinearPlantInversionFeedforward( + const LinearSystem &plant, units::second_t dt) + : LinearPlantInversionFeedforward(plant.A(), plant.B(), dt) {} + + LinearPlantInversionFeedforward( + const Eigen::Matrix &A, + const Eigen::Matrix &B, units::second_t dt) + : m_dt(dt) { + DiscretizeAB(A, B, dt, &m_A, &m_B); + + m_r.setZero(); + Reset(m_r); + } +}; +""", + "string", + ) + + def test_fn(self): + c = self.cppHeader.classes["LinearPlantInversionFeedforward"] + self.assertEqual("LinearPlantInversionFeedforward", c["name"]) + self.assertEqual("template", c["methods"]["public"][0]["template"]) + self.assertEqual(False, c["methods"]["public"][1]["template"]) + + +class UsingTypename(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +template class P { +using A = typename f::TP::A; +public: + using State = typename f::TP::S; + P(State st); +}; +""", + "string", + ) + + def test_fn(self): + c = self.cppHeader.classes["P"] + self.assertEqual("P", c["name"]) + self.assertEqual(len(c["using"]), 2) + state = c["using"]["State"] + self.assertEqual(state["raw_type"], "typename f::TP::S") + self.assertEqual(state["type"], "typename TP::S") + self.assertEqual(state["access"], "public") + private = c["using"]["A"] + self.assertEqual(private["raw_type"], "typename f::TP::A") + self.assertEqual(private["type"], "typename TP::A") + self.assertEqual(private["access"], "private") + + m = c["methods"]["public"][0] + self.assertEqual(m["name"], "P") + self.assertEqual(m["parameters"][0]["namespace"], "f::") + self.assertEqual(m["parameters"][0]["name"], "st") + self.assertEqual(m["parameters"][0]["raw_type"], "typename f::TP::S") + self.assertEqual(m["parameters"][0]["type"], "typename TP::S") + + +class FunctionPointerParse(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +typedef int U32; +typedef unsigned int( * p )(int, int); +typedef int( * mmmmp )(int, int) ; +""", + "string", + ) + + def test_fn(self): + c = self.cppHeader + self.assertEqual(c.typedefs["U32"], "int") + self.assertEqual(c.typedefs["p"], "typedef unsigned int ( * ) ( int , int )") + self.assertEqual(c.typedefs["mmmmp"], "typedef int ( * ) ( int , int )") + + +class ExternTemplateTest(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +extern template class MyClass<1,2>; +extern template class __attribute__(("something")) MyClass<3,4>; + +namespace foo { +extern template class MyClass<5,6>; +}; + +""", + "string", + ) + + def test_fn(self): + c = self.cppHeader + et0, et1, et2 = c.extern_templates + + self.assertEqual(et0["name"], "MyClass") + self.assertEqual(et0["namespace"], "") + self.assertEqual(et0["params"], "<1, 2>") + + self.assertEqual(et1["name"], "MyClass") + self.assertEqual(et1["namespace"], "") + self.assertEqual(et1["params"], "<3, 4>") + + self.assertEqual(et2["name"], "MyClass") + self.assertEqual(et2["namespace"], "foo") + self.assertEqual(et2["params"], "<5, 6>") + + +class UsingTemplateTest(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +class X { + template + using TT = U; +}; + +""", + "string", + ) + + def test_fn(self): + u = self.cppHeader.classes["X"]["using"] + self.assertEqual(len(u), 1) + tt = u["TT"] + + self.assertEqual(tt["access"], "private") + self.assertEqual(tt["raw_type"], "U") + self.assertEqual(tt["type"], "U") + self.assertEqual(tt["typealias"], "TT") + self.assertEqual(tt["template"], "template") + + +class RefQualifierTest(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +struct X { + void fn0(); + void fn1() &; + void fn2() &&; + void fn3() && = 0; +}; + +""", + "string", + ) + + def test_fn0(self): + fn = self.cppHeader.classes["X"]["methods"]["public"][0] + self.assertEqual(fn["name"], "fn0") + self.assertEqual(fn["ref_qualifiers"], "") + + def test_fn1(self): + fn = self.cppHeader.classes["X"]["methods"]["public"][1] + self.assertEqual(fn["name"], "fn1") + self.assertEqual(fn["ref_qualifiers"], "&") + + def test_fn1(self): + fn = self.cppHeader.classes["X"]["methods"]["public"][2] + self.assertEqual(fn["name"], "fn2") + self.assertEqual(fn["ref_qualifiers"], "&&") + + def test_fn3(self): + fn = self.cppHeader.classes["X"]["methods"]["public"][3] + self.assertEqual(fn["name"], "fn3") + self.assertEqual(fn["ref_qualifiers"], "&&") + self.assertEqual(fn["pure_virtual"], True) + + +class ExternCQuirk(unittest.TestCase): + # bug where extern "C" reset the namespace + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +namespace cs { +extern "C" { + struct InCSAndExtern {}; + void FnInCSAndExtern(InCSAndExtern *n); +} + +class InCS {}; + +} + +void FnNotInCSOrExtern(); + +""", + "string", + ) + + def test_fn(self): + # NotCS should be in namespace cs, extern C + c = self.cppHeader.classes["InCSAndExtern"] + self.assertEqual(c["namespace"], "cs") + self.assertEqual(c["linkage"], "C") + + # FnNotCS should be in namespace cs, extern C + fn = self.cppHeader.functions[0] + self.assertEqual(fn["name"], "FnInCSAndExtern") + self.assertEqual(fn["namespace"], "cs::") + self.assertEqual(fn["linkage"], "C") + + # InCS should be in namespace cs + c = self.cppHeader.classes["InCS"] + self.assertEqual(c["namespace"], "cs") + self.assertEqual(c["linkage"], "") + + # FnNotCS should not in namespace cs nor extern C + fn = self.cppHeader.functions[1] + self.assertEqual(fn["name"], "FnNotInCSOrExtern") + self.assertEqual(fn["namespace"], "") + self.assertEqual(fn["linkage"], "") + + +# Github PR 85 +class ContainerOfArray_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +class ContainerOfArray { +public: + std::unique_ptr variable; + std::unique_ptr function(std::unique_ptr param1); +}; +""", + "string", + ) + + def test_rtntype(self): + self.assertEqual( + self.cppHeader.classes["ContainerOfArray"]["methods"]["public"][0][ + "rtnType" + ], + "std::unique_ptr", + ) + + def test_parameters(self): + self.assertEqual( + filter_pameters( + self.cppHeader.classes["ContainerOfArray"]["methods"]["public"][0][ + "parameters" + ] + ), + [{"name": "param1", "desc": None, "type": "std::unique_ptr"}], + ) + + def test_member(self): + self.assertEqual( + self.cppHeader.classes["ContainerOfArray"]["properties"]["public"][0][ + "name" + ], + "variable", + ) + self.assertEqual( + self.cppHeader.classes["ContainerOfArray"]["properties"]["public"][0][ + "type" + ], + "std::unique_ptr", + ) + + +class InitBracket_TestCase(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +class InitBracket { +public: + int variable{10}; + std::shared_ptr variable2 {std::make_shared(150)}; +}; +""", + "string", + ) + + def test_member(self): + self.assertEqual( + self.cppHeader.classes["InitBracket"]["properties"]["public"][0]["name"], + "variable", + ) + self.assertEqual( + self.cppHeader.classes["InitBracket"]["properties"]["public"][0][ + "defaultValue" + ], + "10", + ) + self.assertEqual( + self.cppHeader.classes["InitBracket"]["properties"]["public"][1]["name"], + "variable2", + ) + self.assertEqual( + self.cppHeader.classes["InitBracket"]["properties"]["public"][1][ + "defaultValue" + ], + "std::make_shared ( 150 )", + ) + + +if __name__ == "__main__": + unittest.main()