private ParameterInfo ResolveParameter(CXType originalType, string name = null, int index = 0)
        {
            string renamed;
            var    type = originalType;

            if (type.kind == CXTypeKind.CXType_FunctionProto)
            {
                throw new NotImplementedException();
            }
            if (type.kind == CXTypeKind.CXType_FunctionNoProto)
            {
                throw new NotImplementedException();
            }
            var typeKind = CanonizeType(ref type, out var typeDeclCursor);

            if (typeKind == CXTypeKind.CXType_Pointer)
            {
                var pointeeType = clang.getPointeeType(type);
                if (clang.getFunctionTypeCallingConv(pointeeType) != CXCallingConv.CXCallingConv_Invalid)
                {
                    var delegateTypeName     = originalType.ToString();
                    var possibleDelegateType = Module.GetType(delegateTypeName);
                    if (possibleDelegateType != null)
                    {
                        return(new ParameterInfo(name, possibleDelegateType, index));
                    }

                    return(new ParameterInfo(name,
                                             IncompleteTypeReference.Get(Module, null, delegateTypeName), index));
                }
                var resolvedParameter = ResolveParameter(pointeeType);
                return(new ParameterInfo(name,
                                         resolvedParameter.Type.MakePointerType(), index));
            }
            if (typeKind == CXTypeKind.CXType_DependentSizedArray)
            {
                throw new NotImplementedException();
            }
            if (typeKind == CXTypeKind.CXType_ConstantArray)
            {
                var arraySize         = (int)clang.getArraySize(type);
                var elementType       = clang.getArrayElementType(type);
                var resolvedParameter = ResolveParameter(elementType, name);
                var clrElementType    = resolvedParameter.Type;
                if (clrElementType.IsPointer)
                {
                    clrElementType = Module.TypeSystem.IntPtr;
                }
                var arrayType = resolvedParameter.Type.MakeArrayType();

                if (!PrimitiveUnmanagedTypeMap.TryGetValue(clrElementType.GetRuntimeType(), out var unmanagedType))
                {
                    throw new NotImplementedException();
                }

                return(new ParameterInfo(name,
                                         arrayType, index, ParameterAttributes.None, arraySize));
            }
            if (PrimitiveTypeMap.TryGetValue(typeKind, out var primitiveType))
            {
                if (primitiveType == null)
                {
                    throw new NotImplementedException();
                }
                var originalTypeName = originalType.ToString();
                var typeName         = originalTypeName;

                if (TypeRedirects.TryGetValue(originalTypeName, out renamed))
                {
                    typeName = renamed;
                }
                if (originalType.kind == CXTypeKind.CXType_Typedef)
                {
                    if (KnownTypes.ContainsKey(typeName))
                    {
                        var knownType = Module.GetType(typeName)
                                        ?? Module.GetType(originalTypeName)
                                        ?? throw new NotImplementedException();
                        return(new ParameterInfo(name, knownType, index));
                    }
                }
                else
                {
                    var found = Module.GetType(typeName);
                    if (found != null)
                    {
                        return(new ParameterInfo(name, found, index));
                    }
                }

                return(new ParameterInfo(name, primitiveType.Import(Module), index));
            }

            var typeDeclName = typeDeclCursor.ToString();

            if (TypeRedirects.TryGetValue(typeDeclName, out renamed))
            {
                typeDeclName = renamed;
            }

            var possibleType = Module.GetType(typeDeclName);

            if (possibleType != null)
            {
                return(new ParameterInfo(name, possibleType, index));
            }

            return(new ParameterInfo(name,
                                     IncompleteTypeReference.Get(Module, null, typeDeclName), index));
        }
        private IClangType ParseTypeDef(CXCursor cursor)
        {
            var originalType   = clang.getCursorType(cursor);
            var canonType      = clang.getCanonicalType(originalType);
            var typeDeclCursor = clang.getTypeDeclaration(canonType);

            if (IsCursorInSystemHeader(typeDeclCursor))
            {
                return(null);
            }

            var name = cursor.ToString();

            if (typeDeclCursor.kind == CXCursorKind.CXCursor_NoDeclFound)
            {
                if (canonType.kind != CXTypeKind.CXType_Pointer)
                {
                    // likely simple type alias
                    if (TypeRedirects.TryGetValue(name, out var renamed))
                    {
                        name = renamed;
                    }
                    if (KnownTypes.TryGetValue(name, out var knownType))
                    {
                        if (PrimitiveTypeMap.TryGetValue(canonType.kind, out var primitiveType))
                        {
                            var existingType = Module.GetType(name);
                            if (existingType == null)
                            {
                                throw new NotImplementedException();
                            }

                            switch (knownType)
                            {
                            case KnownType.Bitmask:
                            case KnownType.Enum: {
                                existingType.ChangeUnderlyingType(primitiveType.Import(Module));
                                break;
                            }

                            default:
                                break;
                            }

                            IncrementStatistic("typedefs");
                        }
                        else
                        {
                            throw new NotImplementedException();
                        }
                    }

                    return(null);
                }

                var pointeeType = clang.getPointeeType(canonType);
                var callConv    = clang.getFunctionTypeCallingConv(pointeeType);
                if (callConv == CXCallingConv.CXCallingConv_Invalid)
                {
                    // likely a pointer type alias
                    return(null);
                }

                return(ParseDelegate(cursor, callConv));
            }

            switch (typeDeclCursor.kind)
            {
            case CXCursorKind.CXCursor_UnionDecl:
            case CXCursorKind.CXCursor_StructDecl: {
                var typeName = typeDeclCursor.ToString();
                if (name == typeName)
                {
                    return(null);
                }

                throw new NotImplementedException();
            }

            case CXCursorKind.CXCursor_EnumDecl: {
                if (TypeRedirects.TryGetValue(name, out var renamed))
                {
                    name = renamed;
                }
                if (KnownTypes.TryGetValue(name, out var knownType))
                {
                    var existingType = Module.GetType(name);
                    if (existingType != null)
                    {
                        return(null);
                    }

                    switch (knownType)
                    {
                    case KnownType.Enum: {
                        throw new NotImplementedException();
                    }

                    case KnownType.Bitmask: {
                        throw new NotImplementedException();
                    }

                    default:
                        throw new NotImplementedException();
                    }
                }

                throw new NotImplementedException();
            }
            }

            IncrementStatistic("typedefs");
            throw new NotImplementedException();
        }