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); }
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); }