Пример #1
0
        public static Primitives.Delegate ToDelegate(this TypeInfo type, string nativeName, Cursor cursor, Generator generator)
        {
            if (type.Kind != TypeKind.FunctionProto && type.Kind != TypeKind.Unexposed)
            {
                throw new InvalidOperationException();
            }

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

            var delegateType = new Primitives.Delegate()
            {
                Name       = clrName,
                ReturnType = type.GetResultType().ToClrType()
            };

            var cursorVisitor = new DelegatingCursorVisitor(
                delegate(Cursor c, Cursor parent1)
            {
                if (c.Kind == CursorKind.ParmDecl)
                {
                    delegateType.Arguments.Add(new Primitives.Argument()
                    {
                        Name       = NameConversions.ToClrName(c.GetDisplayName(), NameConversion.Parameter),
                        NativeName = c.GetDisplayName(),
                        Type       = c.GetTypeInfo().ToClrType()
                    });
                }

                return(ChildVisitResult.Continue);
            });

            cursorVisitor.VisitChildren(cursor);

            return(delegateType);
        }
Пример #2
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);
        }
Пример #3
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);
        }
Пример #4
0
        public void GenerateTypes()
        {
            string[] arguments =
            {
                // Use the C++ backend
                "-x",
                "c++",

                // Parse the doxygen comments
                "-Wdocumentation",
            };

            arguments = arguments.Concat(this.IncludeDirectories.Select(x => "-I" + x)).ToArray();

            using (var createIndex = new Index(false, true))
                using (var translationUnit = createIndex.ParseTranslationUnit(this.InputFile, arguments))
                {
                    StringWriter errorWriter    = new StringWriter();
                    var          set            = DiagnosticSet.FromTranslationUnit(translationUnit);
                    var          numDiagnostics = set.GetNumDiagnostics();

                    bool hasError   = false;
                    bool hasWarning = false;

                    for (uint i = 0; i < numDiagnostics; ++i)
                    {
                        Diagnostic diagnostic = set.GetDiagnostic(i);
                        var        severity   = diagnostic.GetSeverity();

                        switch (severity)
                        {
                        case DiagnosticSeverity.Error:
                        case DiagnosticSeverity.Fatal:
                            hasError = true;
                            break;

                        case DiagnosticSeverity.Warning:
                            hasWarning = true;
                            break;
                        }

                        var location = diagnostic.GetLocation();
                        var fileName = location.SourceFile;
                        var line     = location.Line;

                        var message = diagnostic.GetSpelling();
                        errorWriter.WriteLine($"{severity}: {fileName}:{line} {message}");
                    }

                    if (hasError)
                    {
                        throw new Exception(errorWriter.ToString());
                    }

                    if (hasWarning)
                    {
                        // Dump the warnings to the console output.
                        Console.WriteLine(errorWriter.ToString());
                    }

                    // Creates enums
                    var enumVisitor     = new EnumVisitor(this);
                    var realEnumVisitor = new DelegatingCursorVisitor(enumVisitor.Visit);
                    realEnumVisitor.VisitChildren(translationUnit.GetCursor());

                    // Creates handles
                    var typeDefVisitor     = new TypeDefVisitor(this);
                    var realTypeDefVisitor = new DelegatingCursorVisitor(typeDefVisitor.Visit);
                    realTypeDefVisitor.VisitChildren(translationUnit.GetCursor());

                    // Creates C# methods for C functions
                    var functionVisitor     = new FunctionVisitor(this);
                    var realFunctionVisitor = new DelegatingCursorVisitor(functionVisitor.Visit);
                    realFunctionVisitor.VisitChildren(translationUnit.GetCursor());

                    // Creates C# strucs for C structs
                    var structVisitor     = new StructVisitor(this);
                    var realStructVisitor = new DelegatingCursorVisitor(structVisitor.Visit);
                    realStructVisitor.VisitChildren(translationUnit.GetCursor());
                }
        }