Ejemplo n.º 1
0
        public ChildVisitResult Visit(Cursor cursor, Cursor parent)
        {
            if (!cursor.GetLocation().IsFromMainFile())
            {
                return(ChildVisitResult.Continue);
            }

            if (parent.Kind == CursorKind.UnionDecl)
            {
                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);

                this.current = new Struct()
                {
                    Name        = clrName,
                    Description = GetComment(cursor)
                };

                // This is a lazy attempt to handle forward declarations. A better way would be as described here:
                // https://joshpeterson.github.io/identifying-a-forward-declaration-with-libclang
                // but libclang doesn't expose clang_getNullCursor (yet)
                current = this.generator.AddType(nativeName, current) as Struct;

                // If the struct is in use as a 'handle', this AddType would have returned an Handle and the 'as Struct'
                // statement would have cast it to null. In that case, we don't create an explicit struct.
                if (current != null)
                {
                    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*? :)
                }
                else
                {
                    fieldName = NameConversions.ToClrName(fieldName, NameConversion.Field);
                }

                this.fieldPosition++;

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

                return(ChildVisitResult.Continue);
            }

            return(ChildVisitResult.Recurse);
        }
Ejemplo n.º 2
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 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);

                Enum enumDeclaration = new Enum()
                {
                    Name        = clrName,
                    Description = enumComment,
                    BaseType    = "byte"
                };

                // Most enums maps to bytes, with these exceptiosn
                if (nativeName == "libusb_error" || nativeName == "libusb_capability")
                {
                    enumDeclaration.BaseType = "int";
                }

                // Normally the enum values are prefixed with the enum name, e.g.
                // enum log_level => LOG_LEVEL_DEBUG = 1
                //
                // However, this is not always consistent, e.g.
                // enum libusb_capability => LIBUSB_CAP_HAS_CAPABILITY = 1
                //
                // Patch the prefix where required.
                var prefix = nativeName;

                var mappings = new Dictionary <string, string>();
                mappings.Add("libusb_capability", "libusb_cap");
                mappings.Add("libusb_class_code", "libusb_class");
                mappings.Add("libusb_descriptor_type", "libusb_dt");
                mappings.Add("libusb_endpoint_direction", "libusb_endpoint");
                mappings.Add("libusb_hotplug_flag", "libusb_hotplug");
                mappings.Add("libusb_request_recipient", "libusb_recipient");
                mappings.Add("libusb_standard_request", "libusb_request");
                mappings.Add("libusb_transfer_flags", "libusb_transfer");
                mappings.Add("libusb_transfer_status", "libusb_transfer");
                mappings.Add("libusb_bos_type", "libusb_bt");

                if (mappings.ContainsKey(prefix))
                {
                    prefix = mappings[prefix];
                }

                // visit all the enum values
                DelegatingCursorVisitor visitor = new DelegatingCursorVisitor(
                    (c, vistor) =>
                {
                    var value = c.GetEnumConstantDeclValue();

                    var field =
                        new EnumValue()
                    {
                        Name  = NameConversions.ToClrName(c.GetSpelling(), prefix, NameConversion.Enum),
                        Value = value > 0 ? $"0x{(int)c.GetEnumConstantDeclValue():X}" : $"{value}"
                    };

                    field.Description = this.GetComment(c, forType: true);

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

                // Add a missing 'None' value
                if (nativeName == "libusb_transfer_flags")
                {
                    enumDeclaration.Values.Add(new EnumValue()
                    {
                        Name  = "None",
                        Value = "0x0"
                    });
                }

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

            return(ChildVisitResult.Recurse);
        }