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 @@ - - -Python: module CppHeaderParser - - - - - -
 
- 
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 @@ - - - - - - - - - - -

- - -
-

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() pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy