void ICSharpContainer.ValidateMember(CSharpElement element) { if (!(element is CSharpGeneratedFile)) { throw new ArgumentException("Only instance of CSharpGeneratedFile can be added to members of a CSharpCompilation"); } }
public void ValidateMember(CSharpElement element) { if (element is CSharpCompilation || element is CSharpGeneratedFile || element is CSharpNamespace) { throw new ArgumentException($"Cannot add a {element.GetType().Name} to members of a {this.GetType().Name}"); } }
public static void DumpContextualAttributesTo(this CSharpElement element, CodeWriter writer, bool inline = false, CSharpAttributeScope?scopeOverride = null) { if (!(element is ICSharpContextualAttributesProvider provider)) { return; } var mode = writer.Mode; if (mode == CodeWriterMode.Simple) { return; } if (inline) { bool isFirst = true; foreach (var attr in provider.GetContextualAttributes()) { if (isFirst) { writer.Write("["); isFirst = false; } else { writer.Write("] ["); } if (scopeOverride.HasValue) { attr.DumpTo(writer, scopeOverride.Value); } else { attr.DumpTo(writer); } writer.Write("] "); } } else { foreach (var attr in provider.GetContextualAttributes()) { writer.Write("["); if (scopeOverride.HasValue) { attr.DumpTo(writer, scopeOverride.Value); } else { attr.DumpTo(writer); } writer.Write("]"); writer.WriteLine(); } } }
public static void AddDefaultDllImport(CSharpConverter converter, CSharpElement element, CSharpElement context) { if (!(element is CSharpMethod method) || (method.Modifiers & CSharpModifiers.Extern) == 0 || method.Attributes.OfType <CSharpDllImportAttribute>().Any()) { return; } var callingConvention = (method.CppElement as CppFunction)?.CallingConvention ?? CppCallingConvention.Default; var csCallingConvention = callingConvention.GetCSharpCallingConvention(); var name = converter.Options.DefaultDllImportNameAndArguments ?? "LibNativeName"; method.Attributes.Add(new CSharpDllImportAttribute(name) { CallingConvention = csCallingConvention }); }
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); }
public static CSharpElement ConvertClass(CSharpConverter converter, CppClass cppClass, CSharpElement context) { if (cppClass.ClassKind != CppClassKind.Class) { return(null); } if (cppClass.Functions.All(x => (x.Flags & CppFunctionFlags.Virtual) == 0)) { return(null); } // Register the struct as soon as possible var csInterfaceName = converter.GetCSharpName(cppClass, context); var csInterface = new CSharpInterface(csInterfaceName) { CppElement = cppClass, }; var container = converter.GetCSharpContainer(cppClass, context); converter.ApplyDefaultVisibility(csInterface, container); container.Members.Add(csInterface); if (cppClass.BaseTypes.Count > 0) { var csType = converter.GetCSharpType(cppClass.BaseTypes[0].Type, context); csInterface.BaseTypes.Add(csType); } csInterface.Comment = converter.GetCSharpComment(cppClass, csInterface); return(csInterface); }
public static string DefaultGetCSharpName(CSharpConverter converter, CppElement element, CSharpElement context) { var name = string.Empty; // Try to get the name directly from the CppElement if (element is ICppMember member) { name = member.Name; } // If it is null, try to get a contextual name from the context if (string.IsNullOrEmpty(name)) { var contextName = string.Empty; if (context is ICSharpMember csMember) { contextName = csMember.Name; } if (!string.IsNullOrEmpty(contextName)) { name = contextName; } } // If the name is null, we create an anonymous type name that includes the type, file name, and file offset if (string.IsNullOrEmpty(name)) { var fileName = Path.GetFileNameWithoutExtension(element.Span.Start.File); name = $"__Anonymous{element.GetType().Name}_{fileName}_{element.Span.Start.Offset}"; } else if (element is CppType cppType && (!(element is ICppMember cppMember) || string.IsNullOrEmpty(cppMember.Name))) { switch (cppType) { case CppClass cppClass: name = CSharpHelper.AppendWithCasing(name, CSharpHelper.GetCSharpCasingKind(name), cppClass.ClassKind.ToString().ToLowerInvariant(), CSharpCasingKind.Lower); break; case CppFunctionType cppFunctionType: name = CSharpHelper.AppendWithCasing(name, CSharpHelper.GetCSharpCasingKind(name), "delegate", CSharpCasingKind.Lower); break; } } return(name); }
public static CSharpElement ConvertParameter(CSharpConverter converter, CppParameter cppParam, int index, CSharpElement context) { var parent = ((CSharpElement)(context as CSharpMethod) ?? (context as CSharpDelegate)); var parameters = (context as CSharpMethod)?.Parameters ?? (context as CSharpDelegate)?.Parameters; if (parameters == null) { return(null); } var csParamName = string.IsNullOrEmpty(cppParam.Name) ? "arg" + index : converter.GetCSharpName(cppParam, context); var csParam = new CSharpParameter(csParamName) { CppElement = cppParam, Parent = parent }; parameters.Add(csParam); var csParamType = converter.GetCSharpType(cppParam.Type, csParam); csParam.Index = index; csParam.ParameterType = csParamType; return(csParam); }
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; } }
private static void ProcessCSharpElementMappingRules(CSharpConverter converter, CSharpElement element, CSharpElement context) { if (element.CppElement == null) { return; } var cachedRules = GetCachedRules(converter); if (cachedRules.ElementToMatches.TryGetValue(element.CppElement, out var rules)) { foreach (var rule in rules) { foreach (var action in rule.Rule.CSharpElementActions) { action(converter, element, rule.Matches); } } // TODO: better try to cache the underlying object cachedRules.ElementToMatches.Remove(element.CppElement); } }
private static void ProcessCppElementMappingRules(CSharpConverter converter, CppElement cppElement, CSharpElement context) { var cachedRules = GetCachedRules(converter); var rules = cachedRules.StandardRules; // If a CppElement starts with a Prefix, it was generated by AfterPreprocessing and need to be removed // entirely if (cppElement is ICppMember member && member.Name.StartsWith(cachedRules.Prefix)) { member.Name = member.Name.Substring(cachedRules.Prefix.Length); } var matches = new List <ICppElementMatch>(); foreach (var rule in rules) { matches.Clear(); if (rule.Match(cppElement, matches)) { if (rule.CSharpElementActions.Count > 0) { // save the match for later List <CppElementMatch> listCppElementMatch; if (!cachedRules.ElementToMatches.TryGetValue(cppElement, out listCppElementMatch)) { listCppElementMatch = new List <CppElementMatch>(); cachedRules.ElementToMatches.Add(cppElement, listCppElementMatch); } listCppElementMatch.Add(new CppElementMatch(rule, new List <ICppElementMatch>(matches))); } foreach (var action in rule.CppElementActions) { action(converter, cppElement, context, matches); } } } }
public static ICSharpContainer GetSharpContainer(CSharpConverter converter, CppElement element, CSharpElement context) { var cacheContainer = converter.GetTagValueOrDefault <CacheContainer>(CacheContainerKey); if (cacheContainer == null) { cacheContainer = new CacheContainer { DefaultClass = CreateClassLib(converter) }; converter.Tags[CacheContainerKey] = cacheContainer; } if (converter.Options.DispatchOutputPerInclude) { var isFromSystemIncludes = converter.IsFromSystemIncludes(element); if (!isFromSystemIncludes) { var fileName = Path.GetFileNameWithoutExtension(element.Span.Start.File); if (fileName != null) { if (cacheContainer.IncludeToClass.TryGetValue(fileName, out var csClassLib)) { return(csClassLib); } csClassLib = CreateClassLib(converter, UPath.Combine(UPath.Root, fileName + ".generated.cs")); cacheContainer.IncludeToClass.Add(fileName, csClassLib); return(csClassLib); } } } return(cacheContainer.DefaultClass); }
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 ConvertFunction(CSharpConverter converter, CppFunction cppFunction, CSharpElement context) { // We process only public export functions if (!cppFunction.IsPublicExport() || ((cppFunction.Flags & (CppFunctionFlags.Inline | CppFunctionFlags.Method | CppFunctionFlags.Constructor | CppFunctionFlags.Destructor)) != 0 && (cppFunction.Flags & CppFunctionFlags.Virtual) == 0)) { return(null); } // Register the struct as soon as possible var csFunction = new CSharpMethod() { CppElement = cppFunction }; var container = converter.GetCSharpContainer(cppFunction, context); converter.ApplyDefaultVisibility(csFunction, container); container.Members.Add(csFunction); converter.AddUsing(container, "System.Runtime.InteropServices"); if ((cppFunction.Flags & CppFunctionFlags.Virtual) == 0) { csFunction.Modifiers |= CSharpModifiers.Static | CSharpModifiers.Extern; } else { csFunction.Visibility = CSharpVisibility.None; } csFunction.Name = converter.GetCSharpName(cppFunction, csFunction); csFunction.Comment = converter.GetCSharpComment(cppFunction, csFunction); csFunction.ReturnType = converter.GetCSharpType(cppFunction.ReturnType, csFunction); return(csFunction); }
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); }