Example #1
0
        public CXChildVisitResult Visit(CXCursor cursor, CXCursor parent)
        {
            if (!cursor.Location.IsFromMainFile)
            {
                return(CXChildVisitResult.CXChildVisit_Continue);
            }

            CXCursorKind curKind = cursor.Kind;

            if (curKind == CXCursorKind.CXCursor_TypedefDecl)
            {
                var nativeName = cursor.Spelling.CString;
                var clrName    = NameConversions.ToClrName(nativeName, NameConversion.Type);

                // if we've printed these previously, skip them
                if (this.generator.NameMapping.ContainsKey(nativeName))
                {
                    return(CXChildVisitResult.CXChildVisit_Continue);
                }

                CXType type = cursor.TypedefDeclUnderlyingType.CanonicalType;

                // we handle enums and records in struct and enum visitors with forward declarations also
                if (type.kind == CXTypeKind.CXType_Record || type.kind == CXTypeKind.CXType_Enum)
                {
                    return(CXChildVisitResult.CXChildVisit_Continue);
                }

                if (type.kind == CXTypeKind.CXType_Pointer)
                {
                    var pointee = type.PointeeType;
                    if (pointee.kind == CXTypeKind.CXType_Record || pointee.kind == CXTypeKind.CXType_Void)
                    {
                        var types = Handles.CreateSafeHandle(clrName, this.generator).ToArray();
                        this.generator.AddType(nativeName, types[0]);

                        for (int i = 1; i < types.Length; i++)
                        {
                            this.generator.AddType(types[i].Name, types[i]);
                        }

                        return(CXChildVisitResult.CXChildVisit_Continue);
                    }

                    if (pointee.kind == CXTypeKind.CXType_FunctionProto)
                    {
                        var functionType = cursor.TypedefDeclUnderlyingType;
                        var pt           = functionType.PointeeType;
                        CodeTypeDelegate delegateType = pt.ToDelegate(nativeName, cursor, this.generator);
                        this.generator.AddType(nativeName, new CodeDomGeneratedType(delegateType));

                        return(CXChildVisitResult.CXChildVisit_Continue);
                    }
                }

                return(CXChildVisitResult.CXChildVisit_Continue);
            }

            return(CXChildVisitResult.CXChildVisit_Recurse);
        }
Example #2
0
        public ChildVisitResult Visit(Cursor cursor, Cursor parent)
        {
            if (!cursor.GetLocation().IsFromMainFile())
            {
                return(ChildVisitResult.Continue);
            }

            CursorKind curKind = cursor.Kind;

            if (curKind == CursorKind.TypedefDecl)
            {
                var nativeName = cursor.GetSpelling();
                var clrName    = NameConversions.ToClrName(nativeName, NameConversion.Type);

                // if we've printed these previously, skip them
                if (this.generator.NameMapping.ContainsKey(nativeName))
                {
                    return(ChildVisitResult.Continue);
                }

                TypeInfo type = cursor.GetTypedefDeclUnderlyingType().GetCanonicalType();

                // we handle enums and records in struct and enum visitors with forward declarations also
                if (type.Kind == TypeKind.Record || type.Kind == TypeKind.Enum)
                {
                    return(ChildVisitResult.Continue);
                }

                if (type.Kind == TypeKind.Pointer)
                {
                    var pointee = type.GetPointeeType();
                    if (pointee.Kind == TypeKind.Record || pointee.Kind == TypeKind.Void)
                    {
                        var types = Handles.CreateSafeHandle(clrName, this.generator).ToArray();
                        this.generator.AddType(nativeName, types[0]);

                        for (int i = 1; i < types.Length; i++)
                        {
                            this.generator.AddType(types[i].Name, types[i]);
                        }

                        return(ChildVisitResult.Continue);
                    }

                    if (pointee.Kind == TypeKind.FunctionProto)
                    {
                        var functionType = cursor.GetTypedefDeclUnderlyingType();
                        var pt           = functionType.GetPointeeType();
                        CodeTypeDelegate delegateType = pt.ToDelegate(nativeName, cursor, this.generator);
                        this.generator.AddType(nativeName, delegateType);

                        return(ChildVisitResult.Continue);
                    }
                }

                return(ChildVisitResult.Continue);
            }

            return(ChildVisitResult.Recurse);
        }
        public static CodeTypeDelegate ToDelegate(this TypeInfo type, string nativeName, Cursor cursor, ModuleGenerator generator)
        {
            if (type.Kind != TypeKind.FunctionProto &&
                type.Kind != TypeKind.Unexposed)
            {
                throw new InvalidOperationException();
            }

            var clrName = NameConversions.ToClrName(nativeName, NameConversion.Type);

            CodeTypeDelegate delegateType = new CodeTypeDelegate();

            delegateType.CustomAttributes.Add(
                new CodeAttributeDeclaration(
                    new CodeTypeReference(typeof(UnmanagedFunctionPointerAttribute)),
                    new CodeAttributeArgument(
                        new CodePropertyReferenceExpression(
                            new CodeTypeReferenceExpression(typeof(CallingConvention)),
                            type.GetCallingConvention().ToString()))));

            delegateType.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            delegateType.Name       = clrName;
            delegateType.ReturnType = new CodeTypeReference(type.GetResultType().ToClrType());

            uint argumentCounter = 0;

            var cursorVisitor = new DelegatingCursorVisitor(
                delegate(Cursor c, Cursor parent1)
            {
                if (c.Kind == CursorKind.ParmDecl)
                {
                    delegateType.Parameters.Add(Argument.GenerateArgument(generator, type, c, argumentCounter++, FunctionType.Delegate));
                }

                return(ChildVisitResult.Continue);
            });

            cursorVisitor.VisitChildren(cursor);

            return(delegateType);
        }
Example #4
0
        public static CodeTypeDelegate ToDelegate(this CXType type, string nativeName, CXCursor cursor, ModuleGenerator generator)
        {
            if (type.kind != CXTypeKind.CXType_FunctionProto &&
                type.kind != CXTypeKind.CXType_Unexposed)
            {
                throw new InvalidOperationException();
            }

            var clrName = NameConversions.ToClrName(nativeName, NameConversion.Type);

            CodeTypeDelegate delegateType = new CodeTypeDelegate();

            delegateType.CustomAttributes.Add(
                new CodeAttributeDeclaration(
                    new CodeTypeReference(typeof(UnmanagedFunctionPointerAttribute)),
                    new CodeAttributeArgument(
                        new CodePropertyReferenceExpression(
                            new CodeTypeReferenceExpression(typeof(CallingConvention)),
                            type.GetCallingConvention().ToString()))));

            delegateType.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            delegateType.Name       = clrName;
            delegateType.ReturnType = new CodeTypeReference(clang.getResultType(type).ToClrType());

            uint argumentCounter = 0;

            clang.visitChildren(
                cursor,
                delegate(CXCursor cxCursor, CXCursor parent1, IntPtr ptr)
            {
                if (cxCursor.kind == CXCursorKind.CXCursor_ParmDecl)
                {
                    delegateType.Parameters.Add(Argument.GenerateArgument(generator, type, cxCursor, argumentCounter++, FunctionType.Delegate));
                }

                return(CXChildVisitResult.CXChildVisit_Continue);
            },
                new CXClientData(IntPtr.Zero));

            return(delegateType);
        }
Example #5
0
        public static CodeParameterDeclarationExpression GenerateArgument(this ModuleGenerator generator, CXType functionType, CXCursor paramCXCursor, uint index, FunctionType functionKind)
        {
            var numArgTypes = functionType.NumArgTypes;
            var type        = functionType.GetArgType(index);
            var cursorType  = paramCXCursor.Type;

            var name = paramCXCursor.Spelling.CString;

            if (string.IsNullOrEmpty(name))
            {
                name = "param" + index;
            }

            name = NameConversions.ToClrName(name, NameConversion.Parameter);

            CodeParameterDeclarationExpression parameter = new CodeParameterDeclarationExpression();

            parameter.Name = name;

            bool isPointer = false;

            if (functionKind != FunctionType.Free &&
                functionKind != FunctionType.Delegate &&
                type.IsDoubleCharPointer() &&
                !name.Contains("data") &&
                name != "appids")
            {
                parameter.Type      = new CodeTypeReference(typeof(string));
                parameter.Direction = FieldDirection.Out;

                parameter.CustomAttributes.Add(MarshalAsUtf8String());
            }
            else if (functionKind != FunctionType.Delegate && type.IsTripleCharPointer() && generator.StringArrayMarshalerType != null)
            {
                parameter.Type      = new CodeTypeReference(typeof(ReadOnlyCollection <string>));
                parameter.Direction = FieldDirection.Out;

                parameter.CustomAttributes.Add(MarshalAsDeclaration(UnmanagedType.CustomMarshaler, new CodeTypeReference(generator.StringArrayMarshalerType.Name)));
            }
            else if (functionKind != FunctionType.Delegate && (type.IsArrayOfCharPointers() || type.IsDoublePtrToConstChar()))
            {
                parameter.Type      = new CodeTypeReference(typeof(ReadOnlyCollection <string>));
                parameter.Direction = FieldDirection.In;

                parameter.CustomAttributes.Add(MarshalAsUtf8StringArray());
            }
            else
            {
                switch (type.kind)
                {
                case CXTypeKind.CXType_Pointer:
                    var pointee = type.PointeeType;
                    switch (pointee.kind)
                    {
                    case CXTypeKind.CXType_Pointer:
                        parameter.Type = new CodeTypeReference(typeof(IntPtr));
                        isPointer      = true;
                        break;

                    case CXTypeKind.CXType_FunctionProto:
                        parameter.Type = new CodeTypeReference(cursorType.ToClrType());
                        break;

                    case CXTypeKind.CXType_Void:
                        parameter.Type = new CodeTypeReference(typeof(IntPtr));
                        break;

                    case CXTypeKind.CXType_Char_S:
                        // In some of the read/write functions, const char is also used to represent data -- in that
                        // case, it maps to a byte[] array or just an IntPtr.
                        if (functionKind != FunctionType.PInvoke && type.IsPtrToConstChar())
                        {
                            if (!name.Contains("data") && name != "signature")
                            {
                                parameter.Type = new CodeTypeReference(typeof(string));
                                parameter.CustomAttributes.Add(MarshalAsDeclaration(UnmanagedType.LPStr));
                            }
                            else
                            {
                                parameter.Type = new CodeTypeReference(typeof(byte[]));
                            }
                        }
                        else if (functionKind != FunctionType.PInvoke && functionKind != FunctionType.Delegate && type.IsPtrToChar() && name.Contains("data"))
                        {
                            parameter.Type = new CodeTypeReference(typeof(byte[]));
                        }
                        else
                        {
                            // if it's not a const, it's best to go with IntPtr
                            parameter.Type = new CodeTypeReference(typeof(IntPtr));
                        }

                        break;

                    case CXTypeKind.CXType_WChar:
                        if (type.IsPtrToConstChar())
                        {
                            parameter.Type = new CodeTypeReference(typeof(string));
                            parameter.CustomAttributes.Add(MarshalAsDeclaration(UnmanagedType.LPWStr));
                        }
                        else
                        {
                            parameter.Type = new CodeTypeReference(typeof(IntPtr));
                        }

                        break;

                    case CXTypeKind.CXType_Record:
                        if (functionKind != FunctionType.Delegate)
                        {
                            var recordTypeCXCursor = pointee.Declaration;
                            var recordType         = recordTypeCXCursor.Type;

                            // Get the CLR name for the record
                            var clrName = generator.NameMapping[recordType.Spelling.CString.ToString()];
                            parameter.Type = new CodeTypeReference(clrName);
                            isPointer      = true;
                        }
                        else
                        {
                            // if it's not a const, it's best to go with IntPtr
                            parameter.Type = new CodeTypeReference(typeof(IntPtr));
                            isPointer      = true;
                        }

                        break;

                    default:
                        parameter.Type = pointee.ToCodeTypeReference(paramCXCursor, generator);
                        isPointer      = true;
                        break;
                    }

                    break;

                default:
                    if (generator.NameMapping.ContainsKey(type.Spelling.CString.ToString()))
                    {
                        if (functionKind != FunctionType.Delegate)
                        {
                            parameter.Type = type.ToCodeTypeReference(paramCXCursor, generator);
                        }
                        else
                        {
                            parameter.Type = new CodeTypeReference(typeof(IntPtr));
                        }
                    }
                    else
                    {
                        parameter.Type = type.ToCodeTypeReference(paramCXCursor, generator);
                    }

                    break;
                }
            }

            if (functionKind == FunctionType.Delegate && parameter.Type.BaseType.EndsWith("Handle"))
            {
                // Use a custom marshaler
                parameter.CustomAttributes.Add(
                    MarshalAsDeclaration(
                        UnmanagedType.CustomMarshaler,
                        new CodeTypeReference(parameter.Type.BaseType + "DelegateMarshaler")));
            }

            if (isPointer)
            {
                switch (functionKind)
                {
                case FunctionType.None:
                case FunctionType.Delegate:
                    if (parameter.Type.BaseType.EndsWith("Handle"))
                    {
                        // Handles are always out parameters
                        parameter.Direction = FieldDirection.Out;
                    }
                    else
                    {
                        // For IntPtrs, we don't know - so we play on the safe side.
                        parameter.Direction = FieldDirection.Ref;
                    }

                    break;

                case FunctionType.New:
                case FunctionType.PInvoke:
                    parameter.Direction = FieldDirection.Out;
                    break;

                case FunctionType.Free:
                    parameter.Direction = FieldDirection.In;
                    break;

                default:
                    throw new InvalidOperationException();
                }
            }

            return(parameter);
        }
Example #6
0
        public ChildVisitResult Visit(Cursor cursor, Cursor parent)
        {
            if (!cursor.GetLocation().IsFromMainFile())
            {
                return(ChildVisitResult.Continue);
            }

            CursorKind curKind = cursor.Kind;

            if (curKind == CursorKind.EnumDecl)
            {
                var nativeName  = cursor.GetSpelling();
                var type        = cursor.GetEnumDeclIntegerType().ToClrType();
                var enumComment = this.GetComment(cursor, forType: true);

                // enumName can be empty because of typedef enum { .. } enumName;
                // so we have to find the sibling, and this is the only way I've found
                // to do with libclang, maybe there is a better way?
                if (string.IsNullOrEmpty(nativeName))
                {
                    var forwardDeclaringVisitor = new ForwardDeclarationVisitor(cursor, skipSystemHeaderCheck: true);
                    forwardDeclaringVisitor.VisitChildren(cursor.GetLexicalParent());
                    nativeName = forwardDeclaringVisitor.ForwardDeclarationCursor.GetSpelling();

                    if (string.IsNullOrEmpty(nativeName))
                    {
                        nativeName = "_";
                    }
                }

                var clrName = NameConversions.ToClrName(nativeName, NameConversion.Type);

                // if we've printed these previously, skip them
                if (this.generator.NameMapping.ContainsKey(nativeName))
                {
                    return(ChildVisitResult.Continue);
                }

                CodeTypeDeclaration enumDeclaration = new CodeTypeDeclaration();
                enumDeclaration.Attributes = MemberAttributes.Public;
                enumDeclaration.IsEnum     = true;
                enumDeclaration.Name       = clrName;
                enumDeclaration.BaseTypes.Add(type);

                if (enumComment != null)
                {
                    enumDeclaration.Comments.Add(enumComment);
                }

                // visit all the enum values
                DelegatingCursorVisitor visitor = new DelegatingCursorVisitor(
                    (c, vistor) =>
                {
                    var field =
                        new CodeMemberField()
                    {
                        Name           = NameConversions.ToClrName(c.GetSpelling(), NameConversion.Field),
                        InitExpression = new CodePrimitiveExpression(c.GetEnumConstantDeclValue())
                    };

                    var fieldComment = this.GetComment(c, forType: true);
                    if (fieldComment != null)
                    {
                        field.Comments.Add(fieldComment);
                    }

                    enumDeclaration.Members.Add(field);
                    return(ChildVisitResult.Continue);
                });
                visitor.VisitChildren(cursor);

                this.generator.AddType(nativeName, new CodeDomGeneratedType(enumDeclaration));
            }

            return(ChildVisitResult.Recurse);
        }
        public ChildVisitResult Visit(Cursor cursor, Cursor parent)
        {
            if (!cursor.GetLocation().IsFromMainFile())
            {
                return(ChildVisitResult.Continue);
            }

            CursorKind curKind = cursor.Kind;

            if (curKind == CursorKind.StructDecl)
            {
                this.fieldPosition = 0;
                var nativeName = cursor.GetSpelling();

                // struct names can be empty, and so we visit its sibling to find the name
                if (string.IsNullOrEmpty(nativeName))
                {
                    var forwardDeclaringVisitor = new ForwardDeclarationVisitor(cursor, skipSystemHeaderCheck: true);
                    forwardDeclaringVisitor.VisitChildren(cursor.GetSemanticParent());
                    nativeName = forwardDeclaringVisitor.ForwardDeclarationCursor.GetSpelling();

                    if (string.IsNullOrEmpty(nativeName))
                    {
                        nativeName = "_";
                    }
                }

                var clrName = NameConversions.ToClrName(nativeName, NameConversion.Type);

                if (!this.generator.NameMapping.ContainsKey(nativeName))
                {
                    this.current            = new CodeTypeDeclaration(clrName);
                    this.current.IsStruct   = true;
                    this.current.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                    this.generator.AddType(nativeName, this.current);

                    var layoutAttribute =
                        new CodeAttributeDeclaration(
                            new CodeTypeReference(typeof(StructLayoutAttribute)),
                            new CodeAttributeArgument(
                                new CodePropertyReferenceExpression(
                                    new CodeTypeReferenceExpression(typeof(LayoutKind)),
                                    nameof(LayoutKind.Sequential))));

                    this.current.CustomAttributes.Add(layoutAttribute);

                    var visitor = new DelegatingCursorVisitor(this.Visit);
                    visitor.VisitChildren(cursor);
                }

                return(ChildVisitResult.Continue);
            }

            if (curKind == CursorKind.FieldDecl)
            {
                var fieldName = cursor.GetSpelling();
                if (string.IsNullOrEmpty(fieldName))
                {
                    fieldName = "field" + this.fieldPosition; // what if they have fields called field*? :)
                }

                this.fieldPosition++;

                foreach (var member in cursor.ToCodeTypeMember(fieldName, this.generator))
                {
                    this.current.Members.Add(member);
                }

                return(ChildVisitResult.Continue);
            }

            return(ChildVisitResult.Recurse);
        }
Example #8
0
        public CXChildVisitResult Visit(CXCursor cursor, CXCursor parent, IntPtr data)
        {
            if (clang.Location_isFromMainFile(clang.getCursorLocation(cursor)) == 0)
            {
                return(CXChildVisitResult.CXChildVisit_Continue);
            }

            CXCursorKind curKind = clang.getCursorKind(cursor);

            if (curKind == CXCursorKind.CXCursor_StructDecl)
            {
                this.fieldPosition = 0;
                var nativeName = clang.getCursorSpelling(cursor).ToString();

                // struct names can be empty, and so we visit its sibling to find the name
                if (string.IsNullOrEmpty(nativeName))
                {
                    var forwardDeclaringVisitor = new ForwardDeclarationVisitor(cursor);
                    clang.visitChildren(clang.getCursorSemanticParent(cursor), forwardDeclaringVisitor.Visit, new CXClientData(IntPtr.Zero));
                    nativeName = clang.getCursorSpelling(forwardDeclaringVisitor.ForwardDeclarationCursor).ToString();

                    if (string.IsNullOrEmpty(nativeName))
                    {
                        nativeName = "_";
                    }
                }

                var clrName = NameConversions.ToClrName(nativeName, NameConversion.Type);

                if (!this.generator.NameMapping.ContainsKey(nativeName))
                {
                    this.current            = new CodeTypeDeclaration(clrName);
                    this.current.IsStruct   = true;
                    this.current.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                    this.generator.AddType(nativeName, this.current);

                    var layoutAttribute =
                        new CodeAttributeDeclaration(
                            new CodeTypeReference(typeof(StructLayoutAttribute)),
                            new CodeAttributeArgument(
                                new CodePropertyReferenceExpression(
                                    new CodeTypeReferenceExpression(typeof(LayoutKind)),
                                    nameof(LayoutKind.Sequential))));

                    this.current.CustomAttributes.Add(layoutAttribute);

                    clang.visitChildren(cursor, this.Visit, new CXClientData(IntPtr.Zero));
                }

                return(CXChildVisitResult.CXChildVisit_Continue);
            }

            if (curKind == CXCursorKind.CXCursor_FieldDecl)
            {
                var fieldName = clang.getCursorSpelling(cursor).ToString();
                if (string.IsNullOrEmpty(fieldName))
                {
                    fieldName = "field" + this.fieldPosition; // what if they have fields called field*? :)
                }

                this.fieldPosition++;

                foreach (var member in cursor.ToCodeTypeMember(fieldName, this.generator))
                {
                    this.current.Members.Add(member);
                }

                return(CXChildVisitResult.CXChildVisit_Continue);
            }

            return(CXChildVisitResult.CXChildVisit_Recurse);
        }
        public CXChildVisitResult Visit(CXCursor cursor, CXCursor parent, IntPtr data)
        {
            if (clang.Location_isFromMainFile(clang.getCursorLocation(cursor)) == 0)
            {
                return(CXChildVisitResult.CXChildVisit_Continue);
            }

            CXCursorKind curKind = clang.getCursorKind(cursor);

            if (curKind == CXCursorKind.CXCursor_EnumDecl)
            {
                var nativeName  = clang.getCursorSpelling(cursor).ToString();
                var type        = clang.getEnumDeclIntegerType(cursor).ToClrType();
                var enumComment = this.GetComment(cursor, forType: true);

                // enumName can be empty because of typedef enum { .. } enumName;
                // so we have to find the sibling, and this is the only way I've found
                // to do with libclang, maybe there is a better way?
                if (string.IsNullOrEmpty(nativeName))
                {
                    var forwardDeclaringVisitor = new ForwardDeclarationVisitor(cursor);
                    clang.visitChildren(clang.getCursorLexicalParent(cursor), forwardDeclaringVisitor.Visit, new CXClientData(IntPtr.Zero));
                    nativeName = clang.getCursorSpelling(forwardDeclaringVisitor.ForwardDeclarationCursor).ToString();

                    if (string.IsNullOrEmpty(nativeName))
                    {
                        nativeName = "_";
                    }
                }

                var clrName = NameConversions.ToClrName(nativeName, NameConversion.Type);

                // if we've printed these previously, skip them
                if (this.generator.NameMapping.ContainsKey(nativeName))
                {
                    return(CXChildVisitResult.CXChildVisit_Continue);
                }

                CodeTypeDeclaration enumDeclaration = new CodeTypeDeclaration();
                enumDeclaration.Attributes = MemberAttributes.Public;
                enumDeclaration.IsEnum     = true;
                enumDeclaration.Name       = clrName;
                enumDeclaration.BaseTypes.Add(type);

                if (enumComment != null)
                {
                    enumDeclaration.Comments.Add(enumComment);
                }

                // visit all the enum values
                clang.visitChildren(
                    cursor,
                    (cxCursor, vistor, clientData) =>
                {
                    var field =
                        new CodeMemberField()
                    {
                        Name           = NameConversions.ToClrName(clang.getCursorSpelling(cxCursor).ToString(), NameConversion.Field),
                        InitExpression = new CodePrimitiveExpression(clang.getEnumConstantDeclValue(cxCursor))
                    };

                    var fieldComment = this.GetComment(cxCursor, forType: false);
                    if (fieldComment != null)
                    {
                        field.Comments.Add(fieldComment);
                    }

                    enumDeclaration.Members.Add(field);
                    return(CXChildVisitResult.CXChildVisit_Continue);
                },
                    new CXClientData(IntPtr.Zero));

                this.generator.AddType(nativeName, enumDeclaration);
            }

            return(CXChildVisitResult.CXChildVisit_Recurse);
        }