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