Browse Source

Add support for constant slices of InlineArrays

feature/inlinearrays
Siegfried Pammer 3 weeks ago
parent
commit
101ddf8783
  1. 17
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineArrayTests.cs
  2. 21
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  3. 7
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  4. 4
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs
  5. 16
      ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

17
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineArrayTests.cs

@ -77,6 +77,23 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -77,6 +77,23 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return array[GetIndex()] = value;
}
public void Slice(Byte16 array)
{
Receiver(array[..8]);
Receiver((ReadOnlySpan<byte>)array[..8]);
ReceiverSpan(array[..8]);
ReceiverReadOnlySpan(array[..8]);
}
// TODO
//public void Slice(Byte16 array, int end)
//{
// Receiver(array[..end]);
// Receiver((ReadOnlySpan<byte>)array[..end]);
// ReceiverSpan(array[..end]);
// ReceiverReadOnlySpan(array[..end]);
//}
public byte VariableSplitting(Byte16 array, byte value)
{
return array[GetIndex()] = (array[GetIndex() + 1] = value);

21
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -468,16 +468,35 @@ namespace ICSharpCode.Decompiler.CSharp @@ -468,16 +468,35 @@ namespace ICSharpCode.Decompiler.CSharp
&& argumentList.Length == 2)
{
argumentList.CheckNoNamedOrOptionalArguments();
var arrayType = method.TypeArguments[0];
var arrayLength = arrayType.GetInlineArrayLength();
var arrayElementType = arrayType.GetInlineArrayElementType();
var argument = argumentList.Arguments[0];
var spanLengthExpr = argumentList.Arguments[1];
var targetType = method.ReturnType;
var spanType = typeSystem.FindType(KnownTypeCode.SpanOfT);
if (argument.Expression is DirectionExpression { FieldDirection: FieldDirection.In or FieldDirection.Ref, Expression: var lvalueExpr })
{
// `(TargetType)(in arg)` is invalid syntax.
// Also, `f(in arg)` is invalid when there's an implicit conversion involved.
argument = argument.UnwrapChild(lvalueExpr);
}
return new CastExpression(expressionBuilder.ConvertType(targetType), argument.Expression)
if (spanLengthExpr.ResolveResult.ConstantValue is int spanLength && spanLength <= arrayLength)
{
if (spanLength < arrayLength)
{
argument = new IndexerExpression(argument.Expression, new BinaryOperatorExpression {
Operator = BinaryOperatorType.Range,
Right = spanLengthExpr.Expression
}).WithRR(new ResolveResult(new ParameterizedType(spanType, arrayElementType))).WithoutILInstruction();
if (targetType.IsKnownType(KnownTypeCode.SpanOfT))
{
return argument;
}
}
return new CastExpression(expressionBuilder.ConvertType(targetType), argument.Expression)
.WithRR(new ConversionResolveResult(targetType, argument.ResolveResult, Conversion.InlineArrayConversion));
}
}
if (settings.LiftNullables && method.Name == "GetValueOrDefault"

7
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -3138,18 +3138,13 @@ namespace ICSharpCode.Decompiler.CSharp @@ -3138,18 +3138,13 @@ namespace ICSharpCode.Decompiler.CSharp
memberStatic: false,
memberDeclaringType: inst.Type
);
var inlineArrayElementType = GetInlineArrayElementType(inst.Type);
var inlineArrayElementType = inst.Type.GetInlineArrayElementType();
IndexerExpression indexerExpr = new IndexerExpression(
arrayExpr, inst.Indices.Select(i => TranslateArrayIndex(i).Expression)
);
TranslatedExpression expr = indexerExpr.WithILInstruction(inst).WithRR(new ResolveResult(inlineArrayElementType));
return new DirectionExpression(FieldDirection.Ref, expr)
.WithoutILInstruction().WithRR(new ByReferenceResolveResult(expr.ResolveResult, ReferenceKind.Ref));
IType GetInlineArrayElementType(IType arrayType)
{
return arrayType?.GetFields(f => !f.IsStatic).SingleOrDefault()?.Type ?? SpecialType.UnknownType;
}
}
TranslatedExpression TranslateArrayIndex(ILInstruction i)

4
ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs

@ -233,9 +233,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -233,9 +233,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
if ((toType.IsKnownType(KnownTypeCode.SpanOfT) || toType.IsKnownType(KnownTypeCode.ReadOnlySpanOfT))
&& fromType.IsInlineArrayType())
{
var @field = fromType.GetFields(f => !f.IsStatic, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
var elementType = fromType.GetInlineArrayElementType();
var spanElementType = toType.TypeArguments[0];
if (field != null && IdentityConversion(field.ReturnType, spanElementType))
if (IdentityConversion(elementType, spanElementType))
return Conversion.InlineArrayConversion;
}
return Conversion.None;

16
ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

@ -316,6 +316,22 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -316,6 +316,22 @@ namespace ICSharpCode.Decompiler.TypeSystem
return td.HasAttribute(KnownAttribute.InlineArray);
}
public static int? GetInlineArrayLength(this IType type)
{
if (type.Kind != TypeKind.Struct)
return null;
var td = type.GetDefinition();
if (td == null)
return null;
var attr = td.GetAttribute(KnownAttribute.InlineArray);
return attr?.FixedArguments.FirstOrDefault().Value as int?;
}
public static IType GetInlineArrayElementType(this IType arrayType)
{
return arrayType?.GetFields(f => !f.IsStatic).SingleOrDefault()?.Type ?? SpecialType.UnknownType;
}
/// <summary>
/// Gets whether the type is the specified known type.
/// For generic known types, this returns true for any parameterization of the type (and also for the definition itself).

Loading…
Cancel
Save