diff --git a/src/Microsoft.Cci.Extensions/Extensions/CSharp/CSharpCciExtensions.cs b/src/Microsoft.Cci.Extensions/Extensions/CSharp/CSharpCciExtensions.cs index 4f9c86e6045..44461e0f7c7 100644 --- a/src/Microsoft.Cci.Extensions/Extensions/CSharp/CSharpCciExtensions.cs +++ b/src/Microsoft.Cci.Extensions/Extensions/CSharp/CSharpCciExtensions.cs @@ -155,8 +155,7 @@ public static bool IsOrContainsReferenceType(this ITypeReference type) if (resolvedType.IsReferenceType) return true; - // ByReference is a special type understood by runtime to hold a ref T. - if (resolvedType.AreGenericTypeEquivalent(ByReferenceFullName)) + if (resolvedType.IsByRef()) return true; foreach (var field in resolvedType.Fields.Where(f => !f.IsStatic)) @@ -189,7 +188,7 @@ public static bool IsOrContainsNonEmptyStruct(this ITypeReference type) if (typeToCheck.TypeCode != PrimitiveTypeCode.NotPrimitive && typeToCheck.TypeCode != PrimitiveTypeCode.Invalid) return true; - if (resolvedType is Dummy || resolvedType.IsReferenceType || resolvedType.AreGenericTypeEquivalent(ByReferenceFullName)) + if (resolvedType is Dummy || resolvedType.IsReferenceType || resolvedType.IsByRef()) { if (node == 0) { @@ -394,6 +393,13 @@ public static bool IsUnsafeType(this ITypeReference type) return type.TypeCode == PrimitiveTypeCode.Pointer; } + public static bool IsByRef(this ITypeReference type) + { + // ByReference is a special type understood by runtime to hold a ref T. + // ByReference was removed in .NET 7 since support for ref T in C# 11 was introduced. + return type.TypeCode == PrimitiveTypeCode.Reference || type.AreGenericTypeEquivalent(ByReferenceFullName); + } + public static bool IsMethodUnsafe(this IMethodDefinition method) { foreach (var p in method.Parameters) diff --git a/src/Microsoft.Cci.Extensions/Extensions/TypeExtensions.cs b/src/Microsoft.Cci.Extensions/Extensions/TypeExtensions.cs index be42d38ad3f..1b48f016b2f 100644 --- a/src/Microsoft.Cci.Extensions/Extensions/TypeExtensions.cs +++ b/src/Microsoft.Cci.Extensions/Extensions/TypeExtensions.cs @@ -413,7 +413,8 @@ public static ITypeReference UnWrap(this ITypeReference reference) || reference is INamespaceTypeReference || reference is IGenericTypeParameterReference || reference is IGenericMethodParameterReference - || reference is IFunctionPointerTypeReference, + || reference is IFunctionPointerTypeReference + || reference is IManagedPointerType, string.Format("Unexpected type reference that we may need to unwrap {0}", (reference != null ? reference.GetType().FullName : "null"))); return reference; diff --git a/src/Microsoft.Cci.Extensions/Writers/CSharp/CSDeclarationWriter.Properties.cs b/src/Microsoft.Cci.Extensions/Writers/CSharp/CSDeclarationWriter.Properties.cs index 4e4cd170b5b..c68e02ba585 100644 --- a/src/Microsoft.Cci.Extensions/Writers/CSharp/CSDeclarationWriter.Properties.cs +++ b/src/Microsoft.Cci.Extensions/Writers/CSharp/CSDeclarationWriter.Properties.cs @@ -104,7 +104,7 @@ private void WritePropertyDefinition(IPropertyDefinition property) WriteKeyword("readonly"); } - WriteTypeName(property.Type, attributes: property.Attributes); + WriteTypeName(property.Type, property.Attributes); if (property.IsExplicitInterfaceProperty() && _forCompilationIncludeGlobalprefix) Write("global::"); diff --git a/src/Microsoft.Cci.Extensions/Writers/CSharp/CSDeclarationWriter.cs b/src/Microsoft.Cci.Extensions/Writers/CSharp/CSDeclarationWriter.cs index eee1bc96170..53fbe66caf4 100644 --- a/src/Microsoft.Cci.Extensions/Writers/CSharp/CSDeclarationWriter.cs +++ b/src/Microsoft.Cci.Extensions/Writers/CSharp/CSDeclarationWriter.cs @@ -6,7 +6,6 @@ using Microsoft.Cci.Filters; using Microsoft.Cci.Writers.Syntax; using System; -using System.Collections; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; @@ -282,13 +281,20 @@ private bool IsDynamicType(object dynamicAttributeArgument, int arrayIndex) } return (bool)dynamicAttributeArgument; + } + private ref struct TypeNameRecursiveState + { + public object DynamicAttributeArgument; + public object NullableAttributeArgument; + public IEnumerable Attributes; } private int WriteTypeNameRecursive(ITypeReference type, NameFormattingOptions namingOptions, - string[] valueTupleNames, ref int valueTupleNameIndex, ref int nullableIndex, object nullableAttributeArgument, object dynamicAttributeArgument, + string[] valueTupleNames, ref int valueTupleNameIndex, ref int nullableIndex, ref TypeNameRecursiveState state, int typeDepth = 0, int genericParameterIndex = 0, bool isValueTupleParameter = false) { + object dynamicAttributeArgument = state.DynamicAttributeArgument; void WriteTypeNameInner(ITypeReference typeReference) { if (IsDynamicType(dynamicAttributeArgument, typeDepth)) @@ -386,7 +392,7 @@ void WriteTypeNameInner(ITypeReference typeReference) string valueTupleName = isValueTuple ? valueTupleNames?[valueTupleLocalIndex + i] : null; int destinationTypeDepth = typeDepth + i + genericArgumentsInChildTypes + 1; - genericArgumentsInChildTypes += WriteTypeNameRecursive(parameter, namingOptions, valueTupleNames, ref valueTupleNameIndex, ref nullableIndex, nullableAttributeArgument, dynamicAttributeArgument, destinationTypeDepth, i, isValueTuple); + genericArgumentsInChildTypes += WriteTypeNameRecursive(parameter, namingOptions, valueTupleNames, ref valueTupleNameIndex, ref nullableIndex, ref state, destinationTypeDepth, i, isValueTuple); if (valueTupleName != null) { @@ -426,7 +432,7 @@ void WriteTypeNameInner(ITypeReference typeReference) nullableIndex++; WriteTypeNameRecursive(arrayType.ElementType, namingOptions, valueTupleNames, ref valueTupleNameIndex, ref nullableIndex, - nullableAttributeArgument, dynamicAttributeArgument, typeDepth + 1); + ref state, typeDepth + 1); WriteSymbol("["); uint arrayDimension = arrayType.Rank - 1; @@ -437,6 +443,15 @@ void WriteTypeNameInner(ITypeReference typeReference) WriteSymbol("]"); } + else if (type.IsByRef()) + { + WriteSymbol("ref", addSpace: true); + + if (state.Attributes.HasIsReadOnlyAttribute()) + WriteSymbol("readonly", addSpace: true); + + WriteTypeNameInner(((IManagedPointerType)type).TargetType); + } else { WriteTypeNameInner(type); @@ -448,7 +463,7 @@ void WriteTypeNameInner(ITypeReference typeReference) } else if (!type.IsValueType) { - WriteNullableSymbolForReferenceType(nullableAttributeArgument, nullableLocalIndex); + WriteNullableSymbolForReferenceType(state.NullableAttributeArgument, nullableLocalIndex); } return genericArgumentsCount; @@ -466,13 +481,13 @@ private void WriteTypeName(ITypeReference type, IEnumerable at object dynamicAttributeArgument = dynamicAttribute.GetAttributeArgumentValue(defaultValue: hasDynamicAttribute); - WriteTypeName(type, noSpace, useTypeKeywords, omitGenericTypeList, nullableAttributeArgument, dynamicAttributeArgument, attributes?.GetValueTupleNames()); + WriteTypeName(type, noSpace, useTypeKeywords, omitGenericTypeList, nullableAttributeArgument, dynamicAttributeArgument, attributes); } private void WriteTypeName(ITypeReference type, bool noSpace = false, bool useTypeKeywords = true, - bool omitGenericTypeList = false, object nullableAttributeArgument = null, object dynamicAttributeArgument = null, string[] valueTupleNames = null) + bool omitGenericTypeList = false, object nullableAttributeArgument = null, object dynamicAttributeArgument = null, IEnumerable attributes = null) { - NameFormattingOptions namingOptions = NameFormattingOptions.TypeParameters | NameFormattingOptions.ContractNullable | NameFormattingOptions.OmitTypeArguments; ; + NameFormattingOptions namingOptions = NameFormattingOptions.TypeParameters | NameFormattingOptions.ContractNullable | NameFormattingOptions.OmitTypeArguments; if (useTypeKeywords) namingOptions |= NameFormattingOptions.UseTypeKeywords; @@ -488,7 +503,13 @@ private void WriteTypeName(ITypeReference type, bool noSpace = false, bool useTy int valueTupleNameIndex = 0; int nullableIndex = 0; - WriteTypeNameRecursive(type, namingOptions, valueTupleNames, ref valueTupleNameIndex, ref nullableIndex, nullableAttributeArgument, dynamicAttributeArgument); + var state = new TypeNameRecursiveState() + { + DynamicAttributeArgument = dynamicAttributeArgument, + NullableAttributeArgument = nullableAttributeArgument, + Attributes = attributes, + }; + WriteTypeNameRecursive(type, namingOptions, attributes?.GetValueTupleNames(), ref valueTupleNameIndex, ref nullableIndex, ref state); if (!noSpace) WriteSpace(); } diff --git a/src/Microsoft.Cci.Extensions/Writers/CSharp/CSharpWriter.cs b/src/Microsoft.Cci.Extensions/Writers/CSharp/CSharpWriter.cs index 5ebc9c33ec1..337fad3bdf4 100644 --- a/src/Microsoft.Cci.Extensions/Writers/CSharp/CSharpWriter.cs +++ b/src/Microsoft.Cci.Extensions/Writers/CSharp/CSharpWriter.cs @@ -159,7 +159,7 @@ public override void Visit(ITypeDefinition parentType, IEnumerable