Cursor.ChildVisitResult ClassVisitor(Cursor cursor, Cursor parent)
        {
            if (cursor.Kind == CursorKind.CxxAccessSpecifier)
            {
                currentMemberAccess = cursor.AccessSpecifier;
                return Cursor.ChildVisitResult.Continue;
            }
            else if (cursor.Kind == CursorKind.CxxBaseSpecifier)
            {
                currentClass.BaseClass = new TypeRefDefinition(cursor.Type);
                return Cursor.ChildVisitResult.Continue;
            }

            if (currentMemberAccess != AccessSpecifier.Public)
            {
                return Cursor.ChildVisitResult.Continue;
            }

            if ((cursor.Kind == CursorKind.ClassDecl || cursor.Kind == CursorKind.StructDecl ||
                cursor.Kind == CursorKind.ClassTemplate || cursor.Kind == CursorKind.TypedefDecl ||
                cursor.Kind == CursorKind.EnumDecl) && cursor.IsDefinition)
            {
                ParseClassCursor(cursor);
            }
            else if (cursor.Kind == CursorKind.CxxMethod || cursor.Kind == CursorKind.Constructor)
            {
                string methodName = cursor.Spelling;
                if (excludedMethods.ContainsKey(methodName))
                {
                    return Cursor.ChildVisitResult.Continue;
                }

                currentMethod = new MethodDefinition(methodName, currentClass, cursor.NumArguments);
                currentMethod.ReturnType = new TypeRefDefinition(cursor.ResultType);
                currentMethod.IsStatic = cursor.IsStaticCxxMethod;
                currentMethod.IsConstructor = cursor.Kind == CursorKind.Constructor;

                if (cursor.IsVirtualCxxMethod)
                {
                    currentMethod.IsVirtual = true;
                    if (cursor.IsPureVirtualCxxMethod)
                    {
                        currentMethod.IsAbstract = true;
                        currentClass.IsAbstract = true;
                    }
                }

                // Check if the return type is a template
                cursor.VisitChildren(MethodTemplateTypeVisitor);

                // Parse arguments
                for (uint i = 0; i < cursor.NumArguments; i++)
                {
                    Cursor arg = cursor.GetArgument(i);

                    string parameterName = arg.Spelling;
                    if (parameterName.Length == 0)
                    {
                        parameterName = "__unnamed" + i;
                    }
                    currentParameter = new ParameterDefinition(parameterName, new TypeRefDefinition(arg.Type));
                    currentMethod.Parameters[i] = currentParameter;
                    arg.VisitChildren(MethodTemplateTypeVisitor);
                    currentParameter = null;

                    // Check if it's a const or optional parameter
                    IEnumerable<Token> argTokens = currentTU.Tokenize(arg.Extent);
                    foreach (Token token in argTokens)
                    {
                        if (token.Spelling.Equals("="))
                        {
                            currentMethod.Parameters[i].IsOptional = true;
                        }
                    }
                }

                currentMethod = null;
            }
            else if (cursor.Kind == CursorKind.FieldDecl)
            {
                currentField = new FieldDefinition(cursor.Spelling,
                    new TypeRefDefinition(cursor.Type), currentClass);
                currentFieldHasSpecializedParameter = false;
                cursor.VisitChildren(FieldTemplateTypeVisitor);
                currentField = null;
            }
            else if (cursor.Kind == CursorKind.UnionDecl)
            {
                return Cursor.ChildVisitResult.Recurse;
            }
            else
            {
                //Console.WriteLine(cursor.Spelling);
            }
            return Cursor.ChildVisitResult.Continue;
        }
        private void ParseMethodCursor(Cursor cursor)
        {
            string methodName = cursor.Spelling;
            if (excludedMethods.Contains(methodName)) return;

            var existingMethodsMatch = _context.Class.Methods.Where(
                m => !m.IsParsed && methodName.Equals(m.Name) &&
                     m.Parameters.Length == cursor.NumArguments);
            int existingCount = existingMethodsMatch.Count();
            if (existingCount == 1)
            {
                // TODO: check method parameter types if given
                _context.Method = existingMethodsMatch.First();
            }
            else if (existingCount >= 2)
            {
                Console.WriteLine("Ambiguous method in project: " + methodName);
            }

            if (_context.Method == null)
            {
                _context.Method = new MethodDefinition(methodName, _context.Class, cursor.NumArguments);
            }

            _context.Method.ReturnType = new TypeRefDefinition(cursor.ResultType, cursor);
            _context.Method.IsStatic = cursor.IsStaticCxxMethod;
            _context.Method.IsVirtual = cursor.IsVirtualCxxMethod;
            _context.Method.IsAbstract = cursor.IsPureVirtualCxxMethod;
            _context.Method.Access = cursor.AccessSpecifier;
            _context.Method.IsConstructor = cursor.Kind == CursorKind.Constructor;

            // Parse arguments
            for (uint i = 0; i < cursor.NumArguments; i++)
            {
                Cursor arg = cursor.GetArgument(i);

                if (_context.Method.Parameters[i] == null)
                {
                    _context.Parameter = new ParameterDefinition(arg.Spelling, new TypeRefDefinition(arg.Type, arg));
                    _context.Method.Parameters[i] = _context.Parameter;
                }
                else
                {
                    _context.Parameter = _context.Method.Parameters[i];
                    _context.Parameter.Type = new TypeRefDefinition(arg.Type);
                }

                // Check for a default value (optional parameter)
                var argTokens = _context.TranslationUnit.Tokenize(arg.Extent);
                if (argTokens.Any(a => a.Spelling.Equals("=")))
                {
                    _context.Parameter.IsOptional = true;
                }

                // Get marshalling direction
                if (_context.Parameter.MarshalDirection == MarshalDirection.Default)
                {
                    _context.Parameter.MarshalDirection = _context.Parameter.Type.GetDefaultMarshalDirection();
                }

                _context.Parameter = null;
            }

            // Discard any private/protected virtual method unless it
            // implements a public abstract method
            if (_context.MemberAccess != AccessSpecifier.Public && !_context.Method.IsConstructor)
            {
                if (_context.Method.Parent.BaseClass == null ||
                    !_context.Method.Parent.BaseClass.AbstractMethods.Contains(_context.Method))
                {
                    _context.Method.Parent.Methods.Remove(_context.Method);
                }
            }

            _context.Method.IsParsed = true;
            _context.Method = null;
        }
        Cursor.ChildVisitResult ClassVisitor(Cursor cursor, Cursor parent)
        {
            switch (cursor.Kind)
            {
                case CursorKind.CxxAccessSpecifier:
                    _context.MemberAccess = cursor.AccessSpecifier;
                    return Cursor.ChildVisitResult.Continue;
                case CursorKind.CxxBaseSpecifier:
                    string baseName = TypeRefDefinition.GetFullyQualifiedName(cursor.Type);
                    ClassDefinition baseClass;
                    if (!project.ClassDefinitions.TryGetValue(baseName, out baseClass))
                    {
                        Console.WriteLine("Base {0} for {1} not found! Missing header?", baseName, _context.Class.Name);
                        return Cursor.ChildVisitResult.Continue;
                    }
                    _context.Class.BaseClass = baseClass;
                    return Cursor.ChildVisitResult.Continue;
                case CursorKind.TemplateTypeParameter:
                    var classTemplate = _context.Class as ClassTemplateDefinition;
                    if (classTemplate.TemplateTypeParameters == null)
                    {
                        classTemplate.TemplateTypeParameters = new List<string>();
                    }
                    classTemplate.TemplateTypeParameters.Add(cursor.Spelling);
                    return Cursor.ChildVisitResult.Continue;
            }

            // We only care about public members
            if (_context.MemberAccess != AccessSpecifier.Public)
            {
                // And also private/protected virtual methods that override public abstract methods,
                // necessary for checking whether a class is abstract or not.
                if (cursor.IsPureVirtualCxxMethod || !cursor.IsVirtualCxxMethod)
                {
                    return Cursor.ChildVisitResult.Continue;
                }
            }

            if ((cursor.Kind == CursorKind.ClassDecl || cursor.Kind == CursorKind.StructDecl ||
                cursor.Kind == CursorKind.ClassTemplate || cursor.Kind == CursorKind.TypedefDecl ||
                cursor.Kind == CursorKind.EnumDecl) && cursor.IsDefinition)
            {
                ParseClassCursor(cursor);
            }
            else if (cursor.Kind == CursorKind.CxxMethod || cursor.Kind == CursorKind.Constructor)
            {
                string methodName = cursor.Spelling;
                if (excludedMethods.Contains(methodName))
                {
                    return Cursor.ChildVisitResult.Continue;
                }

                var existingMethodsMatch = _context.Class.Methods.Where(
                    m => !m.IsParsed && methodName.Equals(m.Name) &&
                         m.Parameters.Length == cursor.NumArguments);
                int existingCount = existingMethodsMatch.Count();
                if (existingCount == 1)
                {
                    // TODO: check method parameter types if given
                    _context.Method = existingMethodsMatch.First();
                }
                else if (existingCount >= 2)
                {
                    Console.WriteLine("Ambiguous method in project: " + methodName);
                }

                if (_context.Method == null)
                {
                    _context.Method = new MethodDefinition(methodName, _context.Class, cursor.NumArguments);
                }

                _context.Method.ReturnType = new TypeRefDefinition(cursor.ResultType);
                _context.Method.IsConstructor = cursor.Kind == CursorKind.Constructor;
                _context.Method.IsStatic = cursor.IsStaticCxxMethod;
                _context.Method.IsVirtual = cursor.IsVirtualCxxMethod;
                _context.Method.IsAbstract = cursor.IsPureVirtualCxxMethod;

                // Check if the return type is a template
                cursor.VisitChildren(MethodTemplateTypeVisitor);

                // Parse arguments
                for (uint i = 0; i < cursor.NumArguments; i++)
                {
                    Cursor arg = cursor.GetArgument(i);

                    string parameterName = arg.Spelling;
                    if (parameterName.Length == 0)
                    {
                        parameterName = "__unnamed" + i;
                    }

                    if (_context.Method.Parameters[i] == null)
                    {
                        _context.Parameter = new ParameterDefinition(parameterName, new TypeRefDefinition(arg.Type));
                        _context.Method.Parameters[i] = _context.Parameter;
                    }
                    else
                    {
                        _context.Parameter = _context.Method.Parameters[i];
                        _context.Parameter.Type = new TypeRefDefinition(arg.Type);
                    }
                    arg.VisitChildren(MethodTemplateTypeVisitor);

                    // Check for a default value (optional parameter)
                    var argTokens = _context.TranslationUnit.Tokenize(arg.Extent);
                    if (argTokens.Any(a => a.Spelling.Equals("=")))
                    {
                        _context.Parameter.IsOptional = true;
                    }

                    // Get marshalling direction
                    if (_context.Parameter.Type.IsPointer || _context.Parameter.Type.IsReference)
                    {
                        if (_context.Parameter.MarshalDirection != MarshalDirection.Out &&
                            !_context.TranslationUnit.Tokenize(arg.Extent).Any(a => a.Spelling.Equals("const")))
                        {
                            _context.Parameter.MarshalDirection = MarshalDirection.InOut;
                        }
                    }

                    _context.Parameter = null;
                }

                // Discard any private/protected virtual method unless it
                // implements a public abstract method
                if (_context.MemberAccess != AccessSpecifier.Public)
                {
                    if (_context.Method.Parent.BaseClass == null ||
                        !_context.Method.Parent.BaseClass.AbstractMethods.Contains(_context.Method))
                    {
                        _context.Method.Parent.Methods.Remove(_context.Method);
                    }
                }

                _context.Method.IsParsed = true;
                _context.Method = null;
            }
            else if (cursor.Kind == CursorKind.FieldDecl)
            {
                _context.Field = new FieldDefinition(cursor.Spelling,
                    new TypeRefDefinition(cursor.Type), _context.Class);
                if (!cursor.Type.Declaration.SpecializedCursorTemplate.IsInvalid)
                {
                    if (cursor.Children[0].Kind != CursorKind.TemplateRef)
                    {
                        throw new InvalidOperationException();
                    }
                    if (cursor.Children.Count == 1)
                    {
                        string displayName = cursor.Type.Declaration.DisplayName;
                        int typeStart = displayName.IndexOf('<') + 1;
                        int typeEnd = displayName.LastIndexOf('>');
                        displayName = displayName.Substring(typeStart, typeEnd - typeStart);
                        var specializationTypeRef = new TypeRefDefinition
                        {
                            IsBasic = true,
                            Name = displayName
                        };
                        _context.Field.Type.SpecializedTemplateType = specializationTypeRef;
                    }
                    if (cursor.Children.Count == 2)
                    {
                        if (cursor.Children[1].Type.TypeKind != ClangSharp.Type.Kind.Invalid)
                        {
                            _context.Field.Type.SpecializedTemplateType = new TypeRefDefinition(cursor.Children[1].Type);
                        }
                        else
                        {
                            // TODO
                        }
                    }
                }
                //cursor.VisitChildren(FieldTemplateTypeVisitor);
                _context.Field = null;
            }
            else if (cursor.Kind == CursorKind.UnionDecl)
            {
                return Cursor.ChildVisitResult.Recurse;
            }
            else
            {
                //Console.WriteLine(cursor.Spelling);
            }
            return Cursor.ChildVisitResult.Continue;
        }