public CXChildVisitResult Visit(CXCursor cursor, CXCursor parent) { if (!cursor.Location.IsFromMainFile) { return(CXChildVisitResult.CXChildVisit_Continue); } CXCursorKind curKind = cursor.Kind; if (curKind == CXCursorKind.CXCursor_TypedefDecl) { var nativeName = cursor.Spelling.CString; 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); } CXType type = cursor.TypedefDeclUnderlyingType.CanonicalType; // we handle enums and records in struct and enum visitors with forward declarations also if (type.kind == CXTypeKind.CXType_Record || type.kind == CXTypeKind.CXType_Enum) { return(CXChildVisitResult.CXChildVisit_Continue); } if (type.kind == CXTypeKind.CXType_Pointer) { var pointee = type.PointeeType; if (pointee.kind == CXTypeKind.CXType_Record || pointee.kind == CXTypeKind.CXType_Void) { var types = Handles.CreateSafeHandle(clrName, this.generator).ToArray(); this.generator.AddType(nativeName, types[0]); for (int i = 1; i < types.Length; i++) { this.generator.AddType(types[i].Name, types[i]); } return(CXChildVisitResult.CXChildVisit_Continue); } if (pointee.kind == CXTypeKind.CXType_FunctionProto) { var functionType = cursor.TypedefDeclUnderlyingType; var pt = functionType.PointeeType; CodeTypeDelegate delegateType = pt.ToDelegate(nativeName, cursor, this.generator); this.generator.AddType(nativeName, new CodeDomGeneratedType(delegateType)); return(CXChildVisitResult.CXChildVisit_Continue); } } return(CXChildVisitResult.CXChildVisit_Continue); } return(CXChildVisitResult.CXChildVisit_Recurse); }
public ChildVisitResult Visit(Cursor cursor, Cursor parent) { if (!cursor.GetLocation().IsFromMainFile()) { return(ChildVisitResult.Continue); } CursorKind curKind = cursor.Kind; if (curKind == CursorKind.TypedefDecl) { var nativeName = cursor.GetSpelling(); var clrName = NameConversions.ToClrName(nativeName, NameConversion.Type); // if we've printed these previously, skip them if (this.generator.NameMapping.ContainsKey(nativeName)) { return(ChildVisitResult.Continue); } TypeInfo type = cursor.GetTypedefDeclUnderlyingType().GetCanonicalType(); // we handle enums and records in struct and enum visitors with forward declarations also if (type.Kind == TypeKind.Record || type.Kind == TypeKind.Enum) { return(ChildVisitResult.Continue); } if (type.Kind == TypeKind.Pointer) { var pointee = type.GetPointeeType(); if (pointee.Kind == TypeKind.Record || pointee.Kind == TypeKind.Void) { var types = Handles.CreateSafeHandle(clrName, this.generator).ToArray(); this.generator.AddType(nativeName, types[0]); for (int i = 1; i < types.Length; i++) { this.generator.AddType(types[i].Name, types[i]); } return(ChildVisitResult.Continue); } if (pointee.Kind == TypeKind.FunctionProto) { var functionType = cursor.GetTypedefDeclUnderlyingType(); var pt = functionType.GetPointeeType(); CodeTypeDelegate delegateType = pt.ToDelegate(nativeName, cursor, this.generator); this.generator.AddType(nativeName, delegateType); return(ChildVisitResult.Continue); } } return(ChildVisitResult.Continue); } return(ChildVisitResult.Recurse); }
public static CodeTypeDelegate ToDelegate(this TypeInfo type, string nativeName, Cursor cursor, ModuleGenerator generator) { if (type.Kind != TypeKind.FunctionProto && type.Kind != TypeKind.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.GetResultType().ToClrType()); uint argumentCounter = 0; var cursorVisitor = new DelegatingCursorVisitor( delegate(Cursor c, Cursor parent1) { if (c.Kind == CursorKind.ParmDecl) { delegateType.Parameters.Add(Argument.GenerateArgument(generator, type, c, argumentCounter++, FunctionType.Delegate)); } return(ChildVisitResult.Continue); }); cursorVisitor.VisitChildren(cursor); return(delegateType); }
public 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(clang.getResultType(type).ToClrType()); uint argumentCounter = 0; clang.visitChildren( cursor, delegate(CXCursor cxCursor, CXCursor parent1, IntPtr ptr) { if (cxCursor.kind == CXCursorKind.CXCursor_ParmDecl) { delegateType.Parameters.Add(Argument.GenerateArgument(generator, type, cxCursor, argumentCounter++, FunctionType.Delegate)); } return(CXChildVisitResult.CXChildVisit_Continue); }, new CXClientData(IntPtr.Zero)); return(delegateType); }
public static CodeParameterDeclarationExpression GenerateArgument(this ModuleGenerator generator, CXType functionType, CXCursor paramCXCursor, uint index, FunctionType functionKind) { var numArgTypes = functionType.NumArgTypes; var type = functionType.GetArgType(index); var cursorType = paramCXCursor.Type; var name = paramCXCursor.Spelling.CString; if (string.IsNullOrEmpty(name)) { name = "param" + index; } name = NameConversions.ToClrName(name, NameConversion.Parameter); CodeParameterDeclarationExpression parameter = new CodeParameterDeclarationExpression(); parameter.Name = name; bool isPointer = false; if (functionKind != FunctionType.Free && functionKind != FunctionType.Delegate && type.IsDoubleCharPointer() && !name.Contains("data") && name != "appids") { parameter.Type = new CodeTypeReference(typeof(string)); parameter.Direction = FieldDirection.Out; parameter.CustomAttributes.Add(MarshalAsUtf8String()); } else if (functionKind != FunctionType.Delegate && type.IsTripleCharPointer() && generator.StringArrayMarshalerType != null) { parameter.Type = new CodeTypeReference(typeof(ReadOnlyCollection <string>)); parameter.Direction = FieldDirection.Out; parameter.CustomAttributes.Add(MarshalAsDeclaration(UnmanagedType.CustomMarshaler, new CodeTypeReference(generator.StringArrayMarshalerType.Name))); } else if (functionKind != FunctionType.Delegate && (type.IsArrayOfCharPointers() || type.IsDoublePtrToConstChar())) { parameter.Type = new CodeTypeReference(typeof(ReadOnlyCollection <string>)); parameter.Direction = FieldDirection.In; parameter.CustomAttributes.Add(MarshalAsUtf8StringArray()); } else { switch (type.kind) { case CXTypeKind.CXType_Pointer: var pointee = type.PointeeType; switch (pointee.kind) { case CXTypeKind.CXType_Pointer: parameter.Type = new CodeTypeReference(typeof(IntPtr)); isPointer = true; break; case CXTypeKind.CXType_FunctionProto: parameter.Type = new CodeTypeReference(cursorType.ToClrType()); break; case CXTypeKind.CXType_Void: parameter.Type = new CodeTypeReference(typeof(IntPtr)); break; case CXTypeKind.CXType_Char_S: // In some of the read/write functions, const char is also used to represent data -- in that // case, it maps to a byte[] array or just an IntPtr. if (functionKind != FunctionType.PInvoke && type.IsPtrToConstChar()) { if (!name.Contains("data") && name != "signature") { parameter.Type = new CodeTypeReference(typeof(string)); parameter.CustomAttributes.Add(MarshalAsDeclaration(UnmanagedType.LPStr)); } else { parameter.Type = new CodeTypeReference(typeof(byte[])); } } else if (functionKind != FunctionType.PInvoke && functionKind != FunctionType.Delegate && type.IsPtrToChar() && name.Contains("data")) { parameter.Type = new CodeTypeReference(typeof(byte[])); } else { // if it's not a const, it's best to go with IntPtr parameter.Type = new CodeTypeReference(typeof(IntPtr)); } break; case CXTypeKind.CXType_WChar: if (type.IsPtrToConstChar()) { parameter.Type = new CodeTypeReference(typeof(string)); parameter.CustomAttributes.Add(MarshalAsDeclaration(UnmanagedType.LPWStr)); } else { parameter.Type = new CodeTypeReference(typeof(IntPtr)); } break; case CXTypeKind.CXType_Record: if (functionKind != FunctionType.Delegate) { var recordTypeCXCursor = pointee.Declaration; var recordType = recordTypeCXCursor.Type; // Get the CLR name for the record var clrName = generator.NameMapping[recordType.Spelling.CString.ToString()]; parameter.Type = new CodeTypeReference(clrName); isPointer = true; } else { // if it's not a const, it's best to go with IntPtr parameter.Type = new CodeTypeReference(typeof(IntPtr)); isPointer = true; } break; default: parameter.Type = pointee.ToCodeTypeReference(paramCXCursor, generator); isPointer = true; break; } break; default: if (generator.NameMapping.ContainsKey(type.Spelling.CString.ToString())) { if (functionKind != FunctionType.Delegate) { parameter.Type = type.ToCodeTypeReference(paramCXCursor, generator); } else { parameter.Type = new CodeTypeReference(typeof(IntPtr)); } } else { parameter.Type = type.ToCodeTypeReference(paramCXCursor, generator); } break; } } if (functionKind == FunctionType.Delegate && parameter.Type.BaseType.EndsWith("Handle")) { // Use a custom marshaler parameter.CustomAttributes.Add( MarshalAsDeclaration( UnmanagedType.CustomMarshaler, new CodeTypeReference(parameter.Type.BaseType + "DelegateMarshaler"))); } if (isPointer) { switch (functionKind) { case FunctionType.None: case FunctionType.Delegate: if (parameter.Type.BaseType.EndsWith("Handle")) { // Handles are always out parameters parameter.Direction = FieldDirection.Out; } else { // For IntPtrs, we don't know - so we play on the safe side. parameter.Direction = FieldDirection.Ref; } break; case FunctionType.New: case FunctionType.PInvoke: parameter.Direction = FieldDirection.Out; break; case FunctionType.Free: parameter.Direction = FieldDirection.In; break; default: throw new InvalidOperationException(); } } return(parameter); }
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 type = cursor.GetEnumDeclIntegerType().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); forwardDeclaringVisitor.VisitChildren(cursor.GetLexicalParent()); nativeName = forwardDeclaringVisitor.ForwardDeclarationCursor.GetSpelling(); 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(ChildVisitResult.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 DelegatingCursorVisitor visitor = new DelegatingCursorVisitor( (c, vistor) => { var field = new CodeMemberField() { Name = NameConversions.ToClrName(c.GetSpelling(), NameConversion.Field), InitExpression = new CodePrimitiveExpression(c.GetEnumConstantDeclValue()) }; var fieldComment = this.GetComment(c, forType: true); if (fieldComment != null) { field.Comments.Add(fieldComment); } enumDeclaration.Members.Add(field); return(ChildVisitResult.Continue); }); visitor.VisitChildren(cursor); this.generator.AddType(nativeName, new CodeDomGeneratedType(enumDeclaration)); } return(ChildVisitResult.Recurse); }
public ChildVisitResult Visit(Cursor cursor, Cursor parent) { if (!cursor.GetLocation().IsFromMainFile()) { 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); 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, 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 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*? :) } this.fieldPosition++; foreach (var member in cursor.ToCodeTypeMember(fieldName, this.generator)) { this.current.Members.Add(member); } return(ChildVisitResult.Continue); } return(ChildVisitResult.Recurse); }
public CXChildVisitResult Visit(CXCursor cursor, CXCursor parent, IntPtr data) { if (clang.Location_isFromMainFile(clang.getCursorLocation(cursor)) == 0) { return(CXChildVisitResult.CXChildVisit_Continue); } CXCursorKind curKind = clang.getCursorKind(cursor); if (curKind == CXCursorKind.CXCursor_StructDecl) { this.fieldPosition = 0; var nativeName = clang.getCursorSpelling(cursor).ToString(); // struct names can be empty, and so we visit its sibling to find the name if (string.IsNullOrEmpty(nativeName)) { var forwardDeclaringVisitor = new ForwardDeclarationVisitor(cursor); clang.visitChildren(clang.getCursorSemanticParent(cursor), forwardDeclaringVisitor.Visit, new CXClientData(IntPtr.Zero)); nativeName = clang.getCursorSpelling(forwardDeclaringVisitor.ForwardDeclarationCursor).ToString(); 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, 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); clang.visitChildren(cursor, this.Visit, new CXClientData(IntPtr.Zero)); } return(CXChildVisitResult.CXChildVisit_Continue); } if (curKind == CXCursorKind.CXCursor_FieldDecl) { var fieldName = clang.getCursorSpelling(cursor).ToString(); 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); }
public CXChildVisitResult Visit(CXCursor cursor, CXCursor parent, IntPtr data) { if (clang.Location_isFromMainFile(clang.getCursorLocation(cursor)) == 0) { return(CXChildVisitResult.CXChildVisit_Continue); } CXCursorKind curKind = clang.getCursorKind(cursor); if (curKind == CXCursorKind.CXCursor_EnumDecl) { var nativeName = clang.getCursorSpelling(cursor).ToString(); var type = clang.getEnumDeclIntegerType(cursor).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); clang.visitChildren(clang.getCursorLexicalParent(cursor), forwardDeclaringVisitor.Visit, new CXClientData(IntPtr.Zero)); nativeName = clang.getCursorSpelling(forwardDeclaringVisitor.ForwardDeclarationCursor).ToString(); 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 clang.visitChildren( cursor, (cxCursor, vistor, clientData) => { var field = new CodeMemberField() { Name = NameConversions.ToClrName(clang.getCursorSpelling(cxCursor).ToString(), NameConversion.Field), InitExpression = new CodePrimitiveExpression(clang.getEnumConstantDeclValue(cxCursor)) }; var fieldComment = this.GetComment(cxCursor, forType: false); if (fieldComment != null) { field.Comments.Add(fieldComment); } enumDeclaration.Members.Add(field); return(CXChildVisitResult.CXChildVisit_Continue); }, new CXClientData(IntPtr.Zero)); this.generator.AddType(nativeName, enumDeclaration); } return(CXChildVisitResult.CXChildVisit_Recurse); }