public unsafe 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(type.ResultType.ToClrType()); uint argumentCounter = 0; var cursorVisitor = new DelegatingCXCursorVisitor( delegate(CXCursor c, CXCursor parent1) { if (c.Kind == CXCursorKind.CXCursor_ParmDecl) { delegateType.Parameters.Add(Argument.GenerateArgument(generator, type, c, argumentCounter++, FunctionType.Delegate)); } return(CXChildVisitResult.CXChildVisit_Continue); }); cursor.VisitChildren(cursorVisitor.Visit, new CXClientData()); return(delegateType); }
public unsafe void GenerateTypes(string libraryName = "imobiledevice") { string[] arguments = { // Use the C++ backend "-x", "c++", // Parse the doxygen comments "-Wdocumentation", // Target 32-bit OS "-m32" }; arguments = arguments.Concat(this.IncludeDirectories.Select(x => "-I" + x)).ToArray(); FunctionVisitor functionVisitor; using (var createIndex = ClangSharp.Index.Create(false, true)) using (var translationUnit = CXTranslationUnit.Parse(createIndex.Handle, this.InputFile, arguments, null, CXTranslationUnit_Flags.CXTranslationUnit_None)) { StringWriter errorWriter = new StringWriter(); var set = translationUnit.DiagnosticSet; var numDiagnostics = set.NumDiagnostics; bool hasError = false; bool hasWarning = false; for (uint i = 0; i < numDiagnostics; ++i) { CXDiagnostic diagnostic = set.GetDiagnostic(i); var severity = diagnostic.Severity; switch (severity) { case CXDiagnosticSeverity.CXDiagnostic_Error: case CXDiagnosticSeverity.CXDiagnostic_Fatal: hasError = true; break; case CXDiagnosticSeverity.CXDiagnostic_Warning: hasWarning = true; break; } var location = diagnostic.Location; location.GetFileLocation(out CXFile file, out uint line, out _, out _); var fileName = file.Name.CString; var message = diagnostic.Spelling.CString; 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()); } // Generate the marhaler types for string arrays (char **) var arrayMarshalerGenerator = new ArrayMarshalerGenerator(this); arrayMarshalerGenerator.Generate(); // Creates enums var enumVisitor = new EnumVisitor(this); var realEnumVisitor = new DelegatingCXCursorVisitor(enumVisitor.Visit); translationUnit.Cursor.VisitChildren(realEnumVisitor.Visit, new CXClientData()); // Creates structs var structVisitor = new StructVisitor(this); var realStructVisitor = new DelegatingCXCursorVisitor(structVisitor.Visit); translationUnit.Cursor.VisitChildren(realStructVisitor.Visit, new CXClientData()); // Creates safe handles & delegates var typeDefVisitor = new TypeDefVisitor(this); var realTypeDefVisitor = new DelegatingCXCursorVisitor(typeDefVisitor.Visit); translationUnit.Cursor.VisitChildren(realTypeDefVisitor.Visit, new CXClientData()); // Creates functions in a NativeMethods class functionVisitor = new FunctionVisitor(this, libraryName); var realFunctionVisitor = new DelegatingCXCursorVisitor(functionVisitor.Visit); translationUnit.Cursor.VisitChildren(realFunctionVisitor.Visit, new CXClientData()); createIndex.Dispose(); } // Update the SafeHandle to call the _free method var handles = this.Types.Where(t => t.Name.EndsWith("Handle")); foreach (var handle in handles) { var freeMethod = functionVisitor.NativeMethods.Members .OfType <CodeMemberMethod>() .Where(m => (m.Name.EndsWith("_free") || m.Name.EndsWith("_disconnect")) && m.Parameters.Count == 1 && m.Parameters[0].Type.BaseType == handle.Name) .SingleOrDefault(); if (freeMethod == null) { continue; } var type = (HandleType)((NustacheGeneratedType)handle).Type; type.ReleaseMethodName = freeMethod.Name; type.ReleaseMethodReturnsValue = freeMethod.ReturnType.BaseType != "System.Void"; // Directly pass the IntPtr, becuase the handle itself will already be in the 'closed' state // when this method is called. freeMethod.Parameters[0].Type = new CodeTypeReference(typeof(IntPtr)); freeMethod.Parameters[0].Direction = FieldDirection.In; } // Extract the API interface and class, as well as the Exception class. Used for DI. ApiExtractor extractor = new ApiExtractor(this, functionVisitor); extractor.Generate(); // Add the 'Error' extension IsError and ThrowOnError extension methods var extensionsExtractor = new ErrorExtensionExtractor(this, functionVisitor); extensionsExtractor.Generate(); // Patch the native methods to be compatible with .NET Core - basically, // do the marshalling ourselves NativeMethodOverloadGenerator.Generate(this); }
public unsafe CXChildVisitResult Visit(CXCursor cursor, CXCursor parent) { if (!cursor.Location.IsFromMainFile) { return(CXChildVisitResult.CXChildVisit_Continue); } CXCursorKind curKind = cursor.Kind; if (curKind == CXCursorKind.CXCursor_EnumDecl) { var nativeName = cursor.Spelling.CString; var type = cursor.EnumDecl_IntegerType.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); cursor.LexicalParent.VisitChildren(forwardDeclaringVisitor.Visit, new CXClientData()); nativeName = forwardDeclaringVisitor.ForwardDeclarationCXCursor.Spelling.CString; 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 DelegatingCXCursorVisitor visitor = new DelegatingCXCursorVisitor( (c, vistor) => { var field = new CodeMemberField() { Name = NameConversions.ToClrName(c.Spelling.CString, NameConversion.Field), InitExpression = new CodePrimitiveExpression(c.EnumConstantDeclValue) }; var fieldComment = this.GetComment(c, forType: true); if (fieldComment != null) { field.Comments.Add(fieldComment); } enumDeclaration.Members.Add(field); return(CXChildVisitResult.CXChildVisit_Continue); }); cursor.VisitChildren(visitor.Visit, new CXClientData()); this.generator.AddType(nativeName, new CodeDomGeneratedType(enumDeclaration)); } return(CXChildVisitResult.CXChildVisit_Recurse); }
public unsafe CXChildVisitResult Visit(CXCursor cursor, CXCursor parent) { if (!cursor.Location.IsFromMainFile) { return(CXChildVisitResult.CXChildVisit_Continue); } CXCursorKind curKind = cursor.Kind; if (curKind == CXCursorKind.CXCursor_StructDecl) { this.fieldPosition = 0; var nativeName = cursor.Spelling.CString; // 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); cursor.SemanticParent.VisitChildren(forwardDeclaringVisitor.Visit, new CXClientData()); nativeName = forwardDeclaringVisitor.ForwardDeclarationCXCursor.Spelling.CString; 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, new CodeDomGeneratedType(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 DelegatingCXCursorVisitor(this.Visit); cursor.VisitChildren(visitor.Visit, new CXClientData()); } return(CXChildVisitResult.CXChildVisit_Continue); } if (curKind == CXCursorKind.CXCursor_FieldDecl) { var fieldName = cursor.Spelling.CString; 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); }