private CSharpElement ConvertTypedef(CSharpConverter converter, CppTypedef cppTypedef, CSharpElement context) { var elementType = cppTypedef.ElementType; if (DefaultFunctionTypeConverter.IsFunctionType(elementType, out var cppFunctionType)) { return(DefaultFunctionTypeConverter.ConvertNamedFunctionType(converter, cppFunctionType, context, cppTypedef)); } var isFromSystemIncludes = converter.IsFromSystemIncludes(cppTypedef); var csElementType = converter.GetCSharpType(elementType, context, true); var noWrap = converter.Options.TypedefCodeGenKind == CppTypedefCodeGenKind.NoWrap && !converter.Options.TypedefWrapWhiteList.Contains(cppTypedef.Name); // If: // - the typedef is from system includes and the underlying type is not a pointer // - or the typedef mode is "no-wrap" and is not in the whitelist // then we bypass entirely the typedef and return immediately the element type bool is_size_t = isFromSystemIncludes && cppTypedef.Name == "size_t"; if (noWrap || (isFromSystemIncludes && elementType.TypeKind != CppTypeKind.Pointer && !is_size_t)) { return(csElementType); } // Otherwise we generate a small wrapper struct var csStructName = converter.GetCSharpName(cppTypedef, context); var csStruct = new CSharpStruct(csStructName) { CppElement = cppTypedef, }; var container = converter.GetCSharpContainer(cppTypedef, context); converter.ApplyDefaultVisibility(csStruct, container); container.Members.Add(csStruct); csStruct.Comment = converter.GetCSharpComment(cppTypedef, csStruct); // Requires System.Runtime.InteropServices csStruct.Attributes.Add(new CSharpStructLayoutAttribute(LayoutKind.Sequential) { CharSet = converter.Options.DefaultCharSet }); // Required by StructLayout converter.AddUsing(container, "System.Runtime.InteropServices"); var name = csStruct.Name; csStruct.Modifiers |= CSharpModifiers.ReadOnly; csStruct.BaseTypes.Add(new CSharpFreeType($"IEquatable<{name}>")); // Dump the type name and attached attributes for the element type var attachedAttributes = string.Empty; var csElementTypeName = is_size_t ? "IntPtr" : converter.ConvertTypeReferenceToString(csElementType, out attachedAttributes); csStruct.Members.Add(new CSharpLineElement($"public {name}({csElementTypeName} value) => this.Value = value;")); csStruct.Members.Add(new CSharpLineElement($"{attachedAttributes}public readonly {csElementTypeName} Value;")); csStruct.Members.Add(new CSharpLineElement($"public bool Equals({name} other) => Value.Equals(other.Value);")); csStruct.Members.Add(new CSharpLineElement($"public override bool Equals(object obj) => obj is {name} other && Equals(other);")); csStruct.Members.Add(new CSharpLineElement("public override int GetHashCode() => Value.GetHashCode();")); csStruct.Members.Add(new CSharpLineElement("public override string ToString() => Value.ToString();")); csStruct.Members.Add(new CSharpLineElement($"public static implicit operator {csElementTypeName}({name} from) => from.Value;")); csStruct.Members.Add(new CSharpLineElement($"public static implicit operator {name}({csElementTypeName} from) => new {name}(from);")); csStruct.Members.Add(new CSharpLineElement($"public static bool operator ==({name} left, {name} right) => left.Equals(right);")); csStruct.Members.Add(new CSharpLineElement($"public static bool operator !=({name} left, {name} right) => !left.Equals(right);")); return(csStruct); }
private void AfterPreprocessing(CSharpConverter converter, CppCompilation cppCompilation, StringBuilder additionalHeaders) { var cachedRules = GetCachedRules(converter); var macroRules = cachedRules.MacroRules; if (macroRules.Count > 0) { var matches = new List <ICppElementMatch>(); var enumToMacros = new Dictionary <CppMacroToEnumMappingRule, StringBuilder>(); foreach (var cppMacro in cppCompilation.Macros) { if (cppMacro.Parameters != null) { continue; } foreach (var cppMacroRule in macroRules) { matches.Clear(); if (cppMacroRule.Match(cppMacro, matches)) { var regexMatch = matches.FindMatch <CppElementRegexMatch>(); if (cppMacroRule is CppMacroToConstMappingRule macroToConst) { AppendPragmaLine(cppMacroRule, additionalHeaders); var macroName = cppMacro.Name; if (regexMatch != null && macroToConst.ConstFieldName != null) { macroName = Regex.Replace(regexMatch.RegexInput, regexMatch.RegexPattern, macroToConst.ConstFieldName); } foreach (var token in cppMacro.Tokens) { if (token.Kind == CppTokenKind.Comment && !string.IsNullOrEmpty(token.Text)) { additionalHeaders.AppendLine(token.Text); } } if (macroToConst.ExplicitCast) { additionalHeaders.AppendLine($"const {macroToConst.ConstFieldTypeName} {cachedRules.Prefix}{macroName} = ({macroToConst.ConstFieldTypeName}){cppMacro.Value};"); } else { additionalHeaders.AppendLine($"const {macroToConst.ConstFieldTypeName} {cachedRules.Prefix}{macroName} = {cppMacro.Value};"); } } else if (cppMacroRule is CppMacroToEnumMappingRule macroToEnum) { if (!enumToMacros.TryGetValue(macroToEnum, out var macrosAsEnumText)) { macrosAsEnumText = new StringBuilder(); var enumTypeName = macroToEnum.CppEnumTypeName; AppendPragmaLine(cppMacroRule, macrosAsEnumText); macrosAsEnumText.Append($"enum {enumTypeName}"); if (macroToEnum.CppIntegerTypeName != "int") { macrosAsEnumText.Append(" : ").Append(macroToEnum.CppIntegerTypeName); } macrosAsEnumText.AppendLine(); macrosAsEnumText.AppendLine("{"); enumToMacros.Add(macroToEnum, macrosAsEnumText); } var enumItemName = macroToEnum.CppEnumItemName; if (regexMatch != null) { enumItemName = Regex.Replace(regexMatch.RegexInput, regexMatch.RegexPattern, enumItemName); } AppendPragmaLine(cppMacroRule, macrosAsEnumText); if (macroToEnum.ExplicitCast) { macrosAsEnumText.AppendLine($" {cachedRules.Prefix}{enumItemName} = ({macroToEnum.CppIntegerTypeName}){cppMacro.Value},"); } else { macrosAsEnumText.AppendLine($" {cachedRules.Prefix}{enumItemName} = {cppMacro.Value},"); } } } } } foreach (var enumToMacroPair in enumToMacros) { var enumDeclarationText = enumToMacroPair.Value.AppendLine("};"); additionalHeaders.AppendLine(enumDeclarationText.ToString()); } } if (cachedRules.TypesToCompile.Count > 0) { for (var i = 0; i < cachedRules.TypesToCompile.Count; i++) { var rule = cachedRules.TypesToCompile[i]; AppendPragmaLine(rule, additionalHeaders); if (rule.TypeRemapArraySize.HasValue) { var value = rule.TypeRemapArraySize.Value; additionalHeaders.AppendLine($"typedef {rule.TypeRemap} {cachedRules.Prefix}{i}_typedef[{(value < 0 ? string.Empty : value.ToString(CultureInfo.InvariantCulture))}];"); } else { additionalHeaders.AppendLine($"typedef {rule.TypeRemap} {cachedRules.Prefix}{i}_typedef;"); } } } }
public void Register(CSharpConverter converter, CSharpConverterPipeline pipeline) { pipeline.FunctionTypeConverters.Add(ConvertAnonymousFunctionType); }
/// <inheritdoc /> public void Register(CSharpConverter converter, CSharpConverterPipeline pipeline) { pipeline.TypedefConverters.Add(ConvertTypedef); }
public void Register(CSharpConverter converter, CSharpConverterPipeline pipeline) { pipeline.ClassConverters.Add(ConvertClass); }
public void Register(CSharpConverter converter, CSharpConverterPipeline pipeline) { pipeline.GetCSharpContainerResolvers.Add(GetSharpContainer); }
/// <inheritdoc /> public void Register(CSharpConverter converter, CSharpConverterPipeline pipeline) { pipeline.FunctionConverters.Add(ConvertFunction); }
public void Register(CSharpConverter converter, CSharpConverterPipeline pipeline) { pipeline.Converted.Add(AddDefaultDllImport); }
/// <inheritdoc /> public void Register(CSharpConverter converter, CSharpConverterPipeline pipeline) { pipeline.GetCSharpTypeResolvers.Add(GetCSharpType); }
public static CSharpType GetCSharpType(CSharpConverter converter, CppType cppType, CSharpElement context, bool nested) { // Early exit for primitive types if (cppType is CppPrimitiveType cppPrimitiveType) { // Special case for bool return(cppPrimitiveType.Kind == CppPrimitiveKind.Bool ? GetBoolType(converter) : CSharpHelper.GetCSharpPrimitive(cppPrimitiveType)); } // Check if a particular CppType has been already converted var csType = converter.FindCSharpType(cppType); if (csType != null) { return(csType); } // Pre-decode the type by extracting any const/pointer and get the element type directly DecodeSimpleType(cppType, out var isConst, out var isPointer, out var elementType); if (isPointer) { if (isConst && elementType.Equals(CppPrimitiveType.Char)) { // const char* => string (with marshal) csType = GetStringType(converter); } else { var pointedCSharpType = converter.GetCSharpType(elementType, context, true); var isParam = context is CSharpParameter; var isReturn = context is CSharpMethod; if (!nested && (isParam || isReturn)) { switch (elementType.TypeKind) { case CppTypeKind.Array: break; case CppTypeKind.Reference: break; case CppTypeKind.Qualified: var qualifiedType = (CppQualifiedType)elementType; csType = new CSharpRefType(qualifiedType.Qualifier == CppTypeQualifier.Const ? (isParam ? CSharpRefKind.In : CSharpRefKind.RefReadOnly) : CSharpRefKind.Ref, converter.GetCSharpType(qualifiedType.ElementType, context, true)); break; case CppTypeKind.Function: csType = pointedCSharpType; break; case CppTypeKind.Typedef: csType = new CSharpRefType(CSharpRefKind.Ref, pointedCSharpType); break; case CppTypeKind.StructOrClass: // Is the struct is an opaque definition (which can is transformed into passing the struct directly as // the struct contains the pointer) if (pointedCSharpType is CSharpStruct csStruct && csStruct.IsOpaque) { csType = csStruct; } else { csType = new CSharpRefType(isConst ? (isParam ? CSharpRefKind.In : CSharpRefKind.RefReadOnly) : CSharpRefKind.Ref, pointedCSharpType); } break;
public static CSharpComment ConvertComment(CSharpConverter converter, CppElement element, CSharpElement context) { if (!(element is ICppDeclaration cppDecl)) { return(null); } var comment = cppDecl.Comment; if (comment?.Children == null) { return(null); } var csFullComment = new CSharpFullComment(); CSharpXmlComment csRemarks = null; for (var i = 0; i < comment.Children.Count; i++) { var childComment = comment.Children[i]; if (i == 0) { var summary = new CSharpXmlComment("summary"); summary.Children.Add(GetAsCSharpComment(childComment)); csFullComment.Children.Add(summary); continue; } switch (childComment.Kind) { case CppCommentKind.ParamCommand: var paramComment = (CppCommentParamCommand)childComment; var csParamComment = new CSharpParamComment(paramComment.ParamName); csParamComment.Children.Add(GetChildAsCSharpComment(paramComment)); csFullComment.Children.Add(csParamComment); break; case CppCommentKind.BlockCommand: var blockCommand = (CppCommentBlockCommand)childComment; if (blockCommand.CommandName == "return") { var returnComment = new CSharpReturnComment(); returnComment.Children.Add(GetChildAsCSharpComment(blockCommand)); csFullComment.Children.Add(returnComment); } else if (blockCommand.CommandName == "see") { var seealso = new CSharpXmlComment("seealso") { IsSelfClosing = true }; seealso.Attributes.Add(new CSharpXmlAttribute("cref", GetChildAsText(childComment))); csFullComment.Children.Add(seealso); } else { if (csRemarks == null) { csRemarks = new CSharpXmlComment("remarks"); } AddComment(csRemarks, childComment); } break; default: if (csRemarks == null) { csRemarks = new CSharpXmlComment("remarks"); } AddComment(csRemarks, childComment); break; } } if (csRemarks != null && csRemarks.Children.Count > 0) { csFullComment.Children.Add(csRemarks); } return(csFullComment); }
/// <inheritdoc /> public void Register(CSharpConverter converter, CSharpConverterPipeline pipeline) { pipeline.CommentConverters.Add(ConvertComment); }
public void Register(CSharpConverter converter, CSharpConverterPipeline pipeline) { pipeline.ParameterConverters.Add(ConvertParameter); }
public void Register(CSharpConverter converter, CSharpConverterPipeline pipeline) { pipeline.FieldConverters.Add(ConvertField); }
public static CSharpElement ConvertClass(CSharpConverter converter, CppClass cppClass, CSharpElement context) { // This converter supports only plain struct or union if (cppClass.ClassKind == CppClassKind.Class && cppClass.Functions.Any(x => (x.Flags & CppFunctionFlags.Virtual) != 0)) { return(null); } // Register the struct as soon as possible var csStructName = converter.GetCSharpName(cppClass, context); var csStruct = new CSharpStruct(csStructName) { CppElement = cppClass, }; var container = converter.GetCSharpContainer(cppClass, context); converter.ApplyDefaultVisibility(csStruct, container); if (container is CSharpInterface) { container = container.Parent; } container.Members.Add(csStruct); csStruct.Comment = converter.GetCSharpComment(cppClass, csStruct); bool isUnion = cppClass.ClassKind == CppClassKind.Union; // Requires System.Runtime.InteropServices csStruct.Attributes.Add(isUnion ? new CSharpStructLayoutAttribute(LayoutKind.Explicit) { CharSet = converter.Options.DefaultCharSet } : new CSharpStructLayoutAttribute(LayoutKind.Sequential) { CharSet = converter.Options.DefaultCharSet } ); // Required by StructLayout converter.AddUsing(container, "System.Runtime.InteropServices"); if (cppClass.BaseTypes.Count == 1) { var csBaseType = converter.GetCSharpType(cppClass.BaseTypes[0].Type, context, false); csStruct.Members.Add(new CSharpField("@base") { FieldType = csBaseType, Visibility = CSharpVisibility.Public }); } // For opaque type we use a standard representation if (!cppClass.IsDefinition && cppClass.Fields.Count == 0) { csStruct.Modifiers |= CSharpModifiers.ReadOnly; csStruct.BaseTypes.Add(new CSharpFreeType($"IEquatable<{csStruct.Name}>")); csStruct.Members.Add(new CSharpLineElement("private readonly IntPtr _handle;")); csStruct.Members.Add(new CSharpLineElement($"public {csStruct.Name}(IntPtr handle) => _handle = handle;")); csStruct.Members.Add(new CSharpLineElement("public IntPtr Handle => _handle;")); csStruct.Members.Add(new CSharpLineElement($"public bool Equals({csStruct.Name} other) => _handle.Equals(other._handle);")); csStruct.Members.Add(new CSharpLineElement($"public override bool Equals(object obj) => obj is {csStruct.Name} other && Equals(other);")); csStruct.Members.Add(new CSharpLineElement($"public override int GetHashCode() => _handle.GetHashCode();")); csStruct.Members.Add(new CSharpLineElement($"public override string ToString() => \"0x\" + (IntPtr.Size == 8 ? _handle.ToString(\"X16\") : _handle.ToString(\"X8\"));")); csStruct.Members.Add(new CSharpLineElement($"public static bool operator ==({csStruct.Name} left, {csStruct.Name} right) => left.Equals(right);")); csStruct.Members.Add(new CSharpLineElement($"public static bool operator !=({csStruct.Name} left, {csStruct.Name} right) => !left.Equals(right);")); } // If we have any anonymous structs/unions for a field type // try to compute a name for them before processing them foreach (var cppField in cppClass.Fields) { var fieldType = cppField.Type; if (fieldType is CppClass cppFieldTypeClass && cppFieldTypeClass.IsAnonymous && string.IsNullOrEmpty(cppFieldTypeClass.Name)) { var parentName = string.Empty; if (cppFieldTypeClass.Parent is CppClass cppParentClass) { parentName = cppParentClass.Name; } if (cppFieldTypeClass.ClassKind == CppClassKind.Union) { parentName = parentName == string.Empty ? "union" : parentName + "_union"; } cppFieldTypeClass.Name = $"{parentName}_{cppField.Name}"; } } return(csStruct); }
public static CSharpElement ConvertField(CSharpConverter converter, CppField cppField, CSharpElement context) { // Early exit if this is a global variable (we don't handle dllexport) bool isConst = cppField.Type is CppQualifiedType qualifiedType && qualifiedType.Qualifier == CppTypeQualifier.Const; var isGlobalVariable = (!(cppField.Parent is CppClass) && !isConst) || cppField.StorageQualifier == CppStorageQualifier.Static; if (isGlobalVariable) { return null; } var isParentClass = cppField.Parent is CppClass; var csContainer = converter.GetCSharpContainer(cppField, context); var isUnion = ((cppField.Parent as CppClass)?.ClassKind ?? CppClassKind.Struct) == CppClassKind.Union; var csFieldName = converter.GetCSharpName(cppField, (CSharpElement)csContainer); if (cppField.IsBitField) { CSharpBitField csBitFieldStorage = null; for (var index = csContainer.Members.Count - 1; index >= 0; index--) { var member = csContainer.Members[index]; if (member is CSharpField csPreviousField) { csBitFieldStorage = csPreviousField as CSharpBitField; break; } } if (csBitFieldStorage == null || (csBitFieldStorage.CurrentBitWidth + cppField.BitFieldWidth) > csBitFieldStorage.MaxBitWidth) { var canonicalType = (CppPrimitiveType)cppField.Type.GetCanonicalType(); csBitFieldStorage = new CSharpBitField(BitFieldName + csContainer.Members.Count) { Visibility = CSharpVisibility.Private, }; switch (canonicalType.Kind) { case CppPrimitiveKind.Bool: csBitFieldStorage.FieldType = CSharpPrimitiveType.Byte; csBitFieldStorage.MaxBitWidth = 8; break; case CppPrimitiveKind.WChar: csBitFieldStorage.FieldType = CSharpPrimitiveType.UShort; csBitFieldStorage.MaxBitWidth = 16; break; case CppPrimitiveKind.Char: csBitFieldStorage.FieldType = CSharpPrimitiveType.Byte; csBitFieldStorage.MaxBitWidth = 8; break; case CppPrimitiveKind.Short: csBitFieldStorage.FieldType = CSharpPrimitiveType.Short; csBitFieldStorage.MaxBitWidth = 16; break; case CppPrimitiveKind.Int: csBitFieldStorage.FieldType = CSharpPrimitiveType.Int; csBitFieldStorage.MaxBitWidth = 32; break; case CppPrimitiveKind.LongLong: csBitFieldStorage.FieldType = CSharpPrimitiveType.Long; csBitFieldStorage.MaxBitWidth = 64; break; case CppPrimitiveKind.UnsignedChar: csBitFieldStorage.FieldType = CSharpPrimitiveType.Byte; csBitFieldStorage.MaxBitWidth = 8; break; case CppPrimitiveKind.UnsignedShort: csBitFieldStorage.FieldType = CSharpPrimitiveType.UShort; csBitFieldStorage.MaxBitWidth = 16; break; case CppPrimitiveKind.UnsignedInt: csBitFieldStorage.FieldType = CSharpPrimitiveType.UInt; csBitFieldStorage.MaxBitWidth = 32; break; case CppPrimitiveKind.UnsignedLongLong: csBitFieldStorage.FieldType = CSharpPrimitiveType.ULong; csBitFieldStorage.MaxBitWidth = 64; break; default: csBitFieldStorage.FieldType = new CSharpFreeType("unsupported_bitfield_type_" + canonicalType); csBitFieldStorage.MaxBitWidth = 128; break; } csContainer.Members.Add(csBitFieldStorage); } int currentBitOffset = csBitFieldStorage.CurrentBitWidth; csBitFieldStorage.CurrentBitWidth += cppField.BitFieldWidth; var csProperty = new CSharpProperty(csFieldName) { CppElement = cppField, LinkedField = csBitFieldStorage, }; converter.ApplyDefaultVisibility(csProperty, csContainer); csProperty.Comment = converter.GetCSharpComment(cppField, csProperty); var bitmask = (1L << cppField.BitFieldWidth) - 1; var bitmaskStr = $"0b{Convert.ToString(bitmask, 2)}"; var notBitMaskStr = Convert.ToString(~(bitmask << currentBitOffset), 2); if (notBitMaskStr.Length > csBitFieldStorage.MaxBitWidth) { notBitMaskStr = notBitMaskStr.Substring(notBitMaskStr.Length - csBitFieldStorage.MaxBitWidth); } csProperty.ReturnType = converter.GetCSharpType(cppField.Type, csProperty); csProperty.GetBody = (writer, element) => { writer.Write($"return unchecked(("); csProperty.ReturnType.DumpReferenceTo(writer); writer.Write(")"); writer.Write($"(({csBitFieldStorage.Name} >> {currentBitOffset}) & {bitmaskStr})"); writer.Write(");"); writer.WriteLine(); }; csProperty.SetBody = (writer, element) => { writer.Write($"{csBitFieldStorage.Name} = ({csBitFieldStorage.Name} & unchecked(("); csBitFieldStorage.FieldType.DumpReferenceTo(writer); writer.Write($")0b{notBitMaskStr})) | (((("); csBitFieldStorage.FieldType.DumpReferenceTo(writer); writer.Write(")value) & (unchecked(("); csBitFieldStorage.FieldType.DumpReferenceTo(writer); writer.Write($"){bitmaskStr})) << {currentBitOffset}));"); writer.WriteLine(); }; csContainer.Members.Add(csProperty); return csProperty; } else { var parentName = cppField.Parent is CppClass cppClass ? cppClass.Name : string.Empty; var csField = new CSharpField(csFieldName) { CppElement = cppField }; converter.ApplyDefaultVisibility(csField, csContainer); if (isConst) { if (isParentClass) { csField.Modifiers |= CSharpModifiers.ReadOnly; } else { csField.Modifiers |= CSharpModifiers.Const; } } csContainer.Members.Add(csField); csField.Comment = converter.GetCSharpComment(cppField, csField); if (isUnion) { csField.Attributes.Add(new CSharpFreeAttribute("FieldOffset(0)")); converter.AddUsing(csContainer, "System.Runtime.InteropServices"); } csField.FieldType = converter.GetCSharpType(cppField.Type, csField); if (cppField.InitExpression != null) { if (cppField.InitExpression.Kind == CppExpressionKind.Unexposed) { csField.InitValue = cppField.InitValue?.Value?.ToString(); } else { csField.InitValue = converter.ConvertExpression(cppField.InitExpression, context, csField.FieldType); } } return csField; } }
/// <inheritdoc /> public void Register(CSharpConverter converter, CSharpConverterPipeline pipeline) { pipeline.GetCSharpNameResolvers.Add(DefaultGetCSharpName); }