mirror of https://github.com/icsharpcode/ILSpy.git
39 changed files with 799 additions and 148 deletions
@ -0,0 +1,140 @@
@@ -0,0 +1,140 @@
|
||||
using System; |
||||
using System.Text; |
||||
|
||||
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty |
||||
{ |
||||
public class FunctionPointerAddressOf |
||||
{ |
||||
public static void Overloaded() |
||||
{ |
||||
} |
||||
public static void Overloaded(int a) |
||||
{ |
||||
} |
||||
|
||||
public unsafe delegate*<void> GetAddress() |
||||
{ |
||||
return &Overloaded; |
||||
} |
||||
|
||||
public unsafe IntPtr GetAddressAsIntPtr() |
||||
{ |
||||
return (IntPtr)(delegate*<void>)(&Overloaded); |
||||
} |
||||
|
||||
public unsafe void* GetAddressAsVoidPtr() |
||||
{ |
||||
return (delegate*<int, void>)(&Overloaded); |
||||
} |
||||
|
||||
public static string VarianceTest(object o) |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
public unsafe delegate*<StringBuilder, object> Variance() |
||||
{ |
||||
return (delegate*<object, string>)(&VarianceTest); |
||||
} |
||||
|
||||
#if TODO
|
||||
public unsafe delegate*<void> AddressOfLocalFunction() |
||||
{ |
||||
return &LocalFunction; |
||||
|
||||
static void LocalFunction() |
||||
{ |
||||
|
||||
} |
||||
} |
||||
#endif
|
||||
} |
||||
|
||||
internal class FunctionPointersWithDynamicTypes |
||||
{ |
||||
public class D<T, U> |
||||
{ |
||||
} |
||||
public class A<T> |
||||
{ |
||||
public class B<U> |
||||
{ |
||||
} |
||||
} |
||||
|
||||
public unsafe delegate*<dynamic, dynamic, dynamic> F1; |
||||
public unsafe delegate*<object, object, dynamic> F2; |
||||
public unsafe delegate*<dynamic, object, object> F3; |
||||
public unsafe delegate*<object, dynamic, object> F4; |
||||
public unsafe delegate*<object, object, object> F5; |
||||
public unsafe delegate*<object, object, ref dynamic> F6; |
||||
public unsafe delegate*<ref dynamic, object, object> F7; |
||||
public unsafe delegate*<object, ref dynamic, object> F8; |
||||
public unsafe delegate*<ref object, ref object, dynamic> F9; |
||||
public unsafe delegate*<dynamic, ref object, ref object> F10; |
||||
public unsafe delegate*<ref object, dynamic, ref object> F11; |
||||
public unsafe delegate*<object, ref readonly dynamic> F12; |
||||
public unsafe delegate*<in dynamic, object> F13; |
||||
public unsafe delegate*<out dynamic, object> F14; |
||||
public unsafe D<delegate*<dynamic>[], dynamic> F15; |
||||
public unsafe delegate*<A<object>.B<dynamic>> F16; |
||||
} |
||||
|
||||
internal class FunctionPointersWithNativeIntegerTypes |
||||
{ |
||||
public unsafe delegate*<nint, nint, nint> F1; |
||||
public unsafe delegate*<IntPtr, IntPtr, nint> F2; |
||||
public unsafe delegate*<nint, IntPtr, IntPtr> F3; |
||||
public unsafe delegate*<IntPtr, nint, IntPtr> F4; |
||||
public unsafe delegate*<delegate*<IntPtr, IntPtr, IntPtr>, nint> F5; |
||||
public unsafe delegate*<nint, delegate*<IntPtr, IntPtr, IntPtr>> F6; |
||||
public unsafe delegate*<delegate*<IntPtr, IntPtr, nint>, IntPtr> F7; |
||||
public unsafe delegate*<IntPtr, delegate*<IntPtr, nint, IntPtr>> F8; |
||||
} |
||||
|
||||
internal class FunctionPointersWithRefParams |
||||
{ |
||||
public unsafe delegate*<in byte, ref char, out float, ref readonly int> F1; |
||||
public unsafe delegate*<ref char, out float, ref int> F2; |
||||
|
||||
// TODO: re-enable test after https://github.com/dotnet/roslyn/issues/47487 is fixed
|
||||
//public unsafe int CallF1(byte b, char c, out float f)
|
||||
//{
|
||||
// return F1(1, ref c, out f);
|
||||
//}
|
||||
|
||||
public unsafe void CallF2(byte b, char c, out float f) |
||||
{ |
||||
F2(ref c, out f) = b; |
||||
} |
||||
} |
||||
|
||||
// TODO: the new calling convention syntax isn't yet available in the released Roslyn version
|
||||
//internal unsafe class FunctionPointersWithCallingConvention
|
||||
//{
|
||||
// public delegate*<void> managed;
|
||||
// public delegate* unmanaged<void> unmanaged;
|
||||
// public delegate* unmanaged[Cdecl]<void> cdecl;
|
||||
//}
|
||||
|
||||
internal class FunctionPointerTypeInference |
||||
{ |
||||
private static char Test(int i) |
||||
{ |
||||
return (char)i; |
||||
} |
||||
|
||||
public unsafe R GenericMethod<T, R>(delegate*<T, R> f, T arg) |
||||
{ |
||||
return f(arg); |
||||
} |
||||
|
||||
public unsafe void Call() |
||||
{ |
||||
delegate*<int, char> f = &Test; |
||||
GenericMethod(f, 0); |
||||
GenericMethod((delegate*<int, char>)(&Test), 1); |
||||
GenericMethod<int, char>(null, 2); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,185 @@
@@ -0,0 +1,185 @@
|
||||
// Copyright (c) 2020 Daniel Grunwald
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using System.Collections.Immutable; |
||||
using System.Diagnostics; |
||||
using System.Linq; |
||||
using System.Reflection.Metadata; |
||||
|
||||
using ICSharpCode.Decompiler.TypeSystem.Implementation; |
||||
using ICSharpCode.Decompiler.Util; |
||||
|
||||
namespace ICSharpCode.Decompiler.TypeSystem |
||||
{ |
||||
public class FunctionPointerType : AbstractType |
||||
{ |
||||
public static FunctionPointerType FromSignature(MethodSignature<IType> signature, MetadataModule module) |
||||
{ |
||||
IType returnType = signature.ReturnType; |
||||
bool returnIsRefReadOnly = false; |
||||
if (returnType is ModifiedType modReturn && modReturn.Modifier.IsKnownType(KnownAttribute.In)) |
||||
{ |
||||
returnType = modReturn.ElementType; |
||||
returnIsRefReadOnly = true; |
||||
} |
||||
var parameterTypes = ImmutableArray.CreateBuilder<IType>(signature.ParameterTypes.Length); |
||||
var parameterReferenceKinds = ImmutableArray.CreateBuilder<ReferenceKind>(signature.ParameterTypes.Length); |
||||
foreach (var p in signature.ParameterTypes) |
||||
{ |
||||
IType paramType = p; |
||||
ReferenceKind kind = ReferenceKind.None; |
||||
if (p is ModifiedType modreq) |
||||
{ |
||||
if (modreq.Modifier.IsKnownType(KnownAttribute.In)) |
||||
{ |
||||
kind = ReferenceKind.In; |
||||
paramType = modreq.ElementType; |
||||
} |
||||
else if (modreq.Modifier.IsKnownType(KnownAttribute.Out)) |
||||
{ |
||||
kind = ReferenceKind.Out; |
||||
paramType = modreq.ElementType; |
||||
} |
||||
} |
||||
if (paramType.Kind == TypeKind.ByReference) |
||||
{ |
||||
if (kind == ReferenceKind.None) |
||||
kind = ReferenceKind.Ref; |
||||
} |
||||
else |
||||
{ |
||||
kind = ReferenceKind.None; |
||||
} |
||||
parameterTypes.Add(paramType); |
||||
parameterReferenceKinds.Add(kind); |
||||
} |
||||
return new FunctionPointerType( |
||||
module, signature.Header.CallingConvention, |
||||
returnType, returnIsRefReadOnly, |
||||
parameterTypes.MoveToImmutable(), parameterReferenceKinds.MoveToImmutable()); |
||||
} |
||||
|
||||
private readonly MetadataModule module; |
||||
public readonly SignatureCallingConvention CallingConvention; |
||||
public readonly IType ReturnType; |
||||
public readonly bool ReturnIsRefReadOnly; |
||||
public readonly ImmutableArray<IType> ParameterTypes; |
||||
public readonly ImmutableArray<ReferenceKind> ParameterReferenceKinds; |
||||
|
||||
public FunctionPointerType(MetadataModule module, SignatureCallingConvention callingConvention, |
||||
IType returnType, bool returnIsRefReadOnly, |
||||
ImmutableArray<IType> parameterTypes, ImmutableArray<ReferenceKind> parameterReferenceKinds) |
||||
{ |
||||
this.module = module; |
||||
this.CallingConvention = callingConvention; |
||||
this.ReturnType = returnType; |
||||
this.ReturnIsRefReadOnly = returnIsRefReadOnly; |
||||
this.ParameterTypes = parameterTypes; |
||||
this.ParameterReferenceKinds = parameterReferenceKinds; |
||||
Debug.Assert(parameterTypes.Length == parameterReferenceKinds.Length); |
||||
} |
||||
|
||||
public override string Name => "delegate*"; |
||||
|
||||
public override bool? IsReferenceType => false; |
||||
|
||||
public override TypeKind Kind => ((module.TypeSystemOptions & TypeSystemOptions.FunctionPointers) != 0) ? TypeKind.FunctionPointer : TypeKind.Struct; |
||||
|
||||
public override ITypeDefinition GetDefinition() |
||||
{ |
||||
if ((module.TypeSystemOptions & TypeSystemOptions.FunctionPointers) != 0) |
||||
{ |
||||
return null; |
||||
} |
||||
else |
||||
{ |
||||
// If FunctionPointers are not enabled in the TS, we still use FunctionPointerType instances;
|
||||
// but have them act as if they were aliases for UIntPtr.
|
||||
return module.Compilation.FindType(KnownTypeCode.UIntPtr).GetDefinition(); |
||||
} |
||||
} |
||||
|
||||
public override IType AcceptVisitor(TypeVisitor visitor) |
||||
{ |
||||
return visitor.VisitFunctionPointerType(this); |
||||
} |
||||
|
||||
public override IType VisitChildren(TypeVisitor visitor) |
||||
{ |
||||
IType r = ReturnType.AcceptVisitor(visitor); |
||||
// Keep ta == null as long as no elements changed, allocate the array only if necessary.
|
||||
IType[] pt = (r != ReturnType) ? new IType[ParameterTypes.Length] : null; |
||||
for (int i = 0; i < ParameterTypes.Length; i++) |
||||
{ |
||||
IType p = ParameterTypes[i].AcceptVisitor(visitor); |
||||
if (p == null) |
||||
throw new NullReferenceException("TypeVisitor.Visit-method returned null"); |
||||
if (pt == null && p != ParameterTypes[i]) |
||||
{ |
||||
// we found a difference, so we need to allocate the array
|
||||
pt = new IType[ParameterTypes.Length]; |
||||
for (int j = 0; j < i; j++) |
||||
{ |
||||
pt[j] = ParameterTypes[j]; |
||||
} |
||||
} |
||||
if (pt != null) |
||||
pt[i] = p; |
||||
} |
||||
if (pt == null) |
||||
return this; |
||||
else |
||||
return new FunctionPointerType( |
||||
module, CallingConvention, |
||||
r, ReturnIsRefReadOnly, |
||||
pt != null ? pt.ToImmutableArray() : ParameterTypes, |
||||
ParameterReferenceKinds); |
||||
} |
||||
|
||||
public override bool Equals(IType other) |
||||
{ |
||||
return other is FunctionPointerType fpt |
||||
&& CallingConvention == fpt.CallingConvention |
||||
&& ReturnType.Equals(fpt.ReturnType) |
||||
&& ReturnIsRefReadOnly == fpt.ReturnIsRefReadOnly |
||||
&& ParameterTypes.SequenceEqual(fpt.ParameterTypes) |
||||
&& ParameterReferenceKinds.SequenceEqual(fpt.ParameterReferenceKinds); |
||||
} |
||||
|
||||
public override int GetHashCode() |
||||
{ |
||||
unchecked |
||||
{ |
||||
int hash = ReturnType.GetHashCode(); |
||||
foreach (var (p, k) in ParameterTypes.Zip(ParameterReferenceKinds)) |
||||
{ |
||||
hash ^= p.GetHashCode() ^ k.GetHashCode(); |
||||
hash *= 8310859; |
||||
} |
||||
return hash; |
||||
} |
||||
} |
||||
|
||||
internal IType WithSignature(IType returnType, ImmutableArray<IType> parameterTypes) |
||||
{ |
||||
return new FunctionPointerType(this.module, this.CallingConvention, returnType, |
||||
this.ReturnIsRefReadOnly, parameterTypes, this.ParameterReferenceKinds); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue