Browse Source

Add MetadataMethod.

pull/1198/head
Daniel Grunwald 7 years ago
parent
commit
385433aff4
  1. 2
      ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs
  2. 2
      ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
  3. 2
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  4. 4
      ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs
  5. 8
      ICSharpCode.Decompiler/SRMExtensions.cs
  6. 207
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
  7. 5
      ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs
  8. 9
      ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs
  9. 8
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataField.cs
  10. 416
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs
  11. 73
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs
  12. 125
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeDefinition.cs
  13. 13
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeParameter.cs
  14. 205
      ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs
  15. 3
      ICSharpCode.Decompiler/TypeSystem/TypeProvider.cs

2
ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs

@ -1359,6 +1359,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -1359,6 +1359,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
var f = type.GetFields().Single(x => x.Name == name);
Assert.IsTrue(f.IsConst);
Assert.AreEqual(expected, f.ConstantValue);
Assert.AreEqual(0, f.Attributes.Count);
}
[Test]
@ -1613,6 +1614,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -1613,6 +1614,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{
ITypeDefinition c = compilation.FindType(typeof(void)).GetDefinition();
Assert.IsNotNull(c, "System.Void not found");
Assert.AreEqual(TypeKind.Void, c.Kind);
Assert.AreEqual(0, c.GetMethods().Count());
Assert.AreEqual(0, c.GetProperties().Count());
Assert.AreEqual(0, c.GetEvents().Count());

2
ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -293,7 +293,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -293,7 +293,7 @@ namespace ICSharpCode.Decompiler.Disassembler
}
WriteSecurityDeclarations(module, methodDefinition.GetDeclarativeSecurityAttributes());
if (handle.HasBody(metadata)) {
if (methodDefinition.HasBody()) {
methodBodyDisassembler.Disassemble(module, handle);
}
var declaringType = metadata.GetTypeDefinition(methodDefinition.GetDeclaringType());

2
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -345,7 +345,9 @@ @@ -345,7 +345,9 @@
<Compile Include="TypeSystem\Implementation\FakeMember.cs" />
<Compile Include="TypeSystem\Implementation\KnownAttributes.cs" />
<Compile Include="TypeSystem\Implementation\MetadataField.cs" />
<Compile Include="TypeSystem\Implementation\MetadataMethod.cs" />
<Compile Include="TypeSystem\Implementation\MetadataNamespace.cs" />
<Compile Include="TypeSystem\Implementation\MetadataParameter.cs" />
<Compile Include="TypeSystem\Implementation\MetadataTypeDefinition.cs" />
<Compile Include="TypeSystem\Implementation\MetadataTypeParameter.cs" />
<Compile Include="TypeSystem\Implementation\MetadataTypeReference.cs" />

4
ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs

@ -366,10 +366,12 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -366,10 +366,12 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
{
var typeSystem = context.TypeSystem;
var metadata = typeSystem.GetMetadata();
if (method.IsNil || !method.HasBody(metadata))
if (method.IsNil)
throw new SymbolicAnalysisFailedException();
var methodDef = metadata.GetMethodDefinition(method);
if (!methodDef.HasBody())
throw new SymbolicAnalysisFailedException();
var sdtp = typeSystem as SpecializingDecompilerTypeSystem;
if (sdtp != null) {

8
ICSharpCode.Decompiler/SRMExtensions.cs

@ -92,13 +92,7 @@ namespace ICSharpCode.Decompiler @@ -92,13 +92,7 @@ namespace ICSharpCode.Decompiler
}
return false;
}
public static bool HasBody(this MethodDefinitionHandle handle, MetadataReader reader)
{
var methodDefinition = reader.GetMethodDefinition(handle);
return methodDefinition.HasBody();
}
public static bool HasBody(this MethodDefinition methodDefinition)
{
const MethodAttributes noBodyAttrs = MethodAttributes.Abstract | MethodAttributes.PinvokeImpl;

207
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -237,7 +237,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -237,7 +237,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
#region Resolve Field
public IField ResolveAsField(SRM.EntityHandle fieldReference)
{
if (fieldReference.IsNil)
/*if (fieldReference.IsNil)
throw new ArgumentNullException(nameof(fieldReference));
if (fieldReference.Kind != SRM.HandleKind.FieldDefinition && fieldReference.Kind != SRM.HandleKind.MemberReference)
throw new ArgumentException("HandleKind must be either FieldDefinition or MemberReference", nameof(fieldReference));
@ -248,21 +248,9 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -248,21 +248,9 @@ namespace ICSharpCode.Decompiler.TypeSystem
switch (fieldReference.Kind) {
case SRM.HandleKind.FieldDefinition:
var fieldDefHandle = (SRM.FieldDefinitionHandle)fieldReference;
var fieldDef = metadata.GetFieldDefinition(fieldDefHandle);
declaringType = ResolveDeclaringType(fieldDef.GetDeclaringType());
var declaringTypeDefinition = declaringType.GetDefinition();
if (declaringTypeDefinition != null) {
field = declaringTypeDefinition.GetFields(f => f.MetadataToken == fieldReference, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
} else {
field = null;
}
field = mainAssembly.GetDefinition(fieldDefHandle);
if (field == null) {
field = new FakeField(compilation) {
DeclaringType = declaringType,
Name = metadata.GetString(fieldDef.Name),
ReturnType = FieldTypeReference.Resolve(fieldDefHandle, metadata, context, typeSystemOptions),
IsStatic = (fieldDef.Attributes & System.Reflection.FieldAttributes.Static) != 0,
};
throw new NotImplementedException();
}
break;
case SRM.HandleKind.MemberReference:
@ -281,9 +269,11 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -281,9 +269,11 @@ namespace ICSharpCode.Decompiler.TypeSystem
fieldLookupCache.Add(fieldReference, field);
}
return field;
}
}*/
throw new NotImplementedException();
}
/*
IField FindNonGenericField(SRM.MetadataReader metadata, SRM.MemberReferenceHandle memberRefHandle, IType declaringType)
{
var memberRef = metadata.GetMemberReference(memberRefHandle);
@ -303,196 +293,15 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -303,196 +293,15 @@ namespace ICSharpCode.Decompiler.TypeSystem
ReturnType = returnType
};
}
*/
#endregion
#region Resolve Method
public IMethod ResolveAsMethod(SRM.EntityHandle methodReference)
{
if (methodReference.IsNil)
throw new ArgumentNullException(nameof(methodReference));
if (methodReference.Kind != SRM.HandleKind.MethodDefinition && methodReference.Kind != SRM.HandleKind.MemberReference && methodReference.Kind != SRM.HandleKind.MethodSpecification)
throw new ArgumentException("HandleKind must be either a MethodDefinition, MemberReference or MethodSpecification", nameof(methodReference));
lock (methodLookupCache) {
if (!methodLookupCache.TryGetValue(methodReference, out IMethod method)) {
var metadata = moduleDefinition.Metadata;
switch (methodReference.Kind) {
case SRM.HandleKind.MethodDefinition:
method = ResolveMethodDefinition(metadata, (SRM.MethodDefinitionHandle)methodReference);
break;
case SRM.HandleKind.MemberReference:
method = ResolveMethodReference(metadata, (SRM.MemberReferenceHandle)methodReference);
break;
case SRM.HandleKind.MethodSpecification:
var methodSpec = metadata.GetMethodSpecification((SRM.MethodSpecificationHandle)methodReference);
var methodTypeArgs = methodSpec.DecodeSignature(mainAssembly.TypeProvider, new GenericContext(context));
if (methodSpec.Method.Kind == SRM.HandleKind.MethodDefinition) {
// generic instance of a methoddef (=generic method in non-generic class in current assembly)
method = ResolveMethodDefinition(metadata, (SRM.MethodDefinitionHandle)methodSpec.Method);
method = method.Specialize(new TypeParameterSubstitution(null, methodTypeArgs));
} else {
method = ResolveMethodReference(metadata, (SRM.MemberReferenceHandle)methodSpec.Method, methodTypeArgs);
}
break;
default:
throw new NotSupportedException();
}
methodLookupCache.Add(methodReference, method);
}
return method;
}
}
IMethod ResolveMethodDefinition(SRM.MetadataReader metadata, SRM.MethodDefinitionHandle methodDefHandle, bool expandVarArgs = true)
{
var method = mainAssembly.GetDefinition(methodDefHandle);
if (method == null) {
throw new NotImplementedException();
}
if (expandVarArgs && method.Parameters.LastOrDefault()?.Type.Kind == TypeKind.ArgList) {
method = new VarArgInstanceMethod(method, EmptyList<IType>.Instance);
}
return method;
return MainAssembly.ResolveMethod(methodReference);
}
/// <summary>
/// Resolves a method reference.
/// </summary>
/// <remarks>
/// Class type arguments are provided by the declaring type stored in the memberRef.
/// Method type arguments are provided by the caller.
/// </remarks>
IMethod ResolveMethodReference(SRM.MetadataReader metadata, SRM.MemberReferenceHandle memberRefHandle, IReadOnlyList<IType> methodTypeArguments = null)
{
var memberRef = metadata.GetMemberReference(memberRefHandle);
Debug.Assert(memberRef.GetKind() == SRM.MemberReferenceKind.Method);
SRM.MethodSignature<IType> signature;
IReadOnlyList<IType> classTypeArguments = null;
IMethod method;
if (memberRef.Parent.Kind == SRM.HandleKind.MethodDefinition) {
method = ResolveMethodDefinition(metadata, (SRM.MethodDefinitionHandle)memberRef.Parent, expandVarArgs: false);
signature = memberRef.DecodeMethodSignature(mainAssembly.TypeProvider, new GenericContext(context));
} else {
var declaringType = ResolveDeclaringType(memberRef.Parent);
var declaringTypeDefinition = declaringType.GetDefinition();
if (declaringType.TypeArguments.Count > 0) {
classTypeArguments = declaringType.TypeArguments;
}
// Note: declaringType might be parameterized, but the signature is for the original method definition.
// We'll have to search the member directly on declaringTypeDefinition.
string name = metadata.GetString(memberRef.Name);
signature = memberRef.DecodeMethodSignature(mainAssembly.TypeProvider,
new GenericContext(declaringTypeDefinition?.TypeParameters));
if (declaringTypeDefinition != null) {
// Find the set of overloads to search:
IEnumerable<IMethod> methods;
if (name == ".ctor") {
methods = declaringTypeDefinition.GetConstructors();
} else if (name == ".cctor") {
methods = declaringTypeDefinition.Methods.Where(m => m.IsConstructor && m.IsStatic);
} else {
methods = declaringTypeDefinition.GetMethods(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers)
.Concat(declaringTypeDefinition.GetAccessors(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers));
}
// Determine the expected parameters from the signature:
ImmutableArray<IType> parameterTypes;
if (signature.Header.CallingConvention == SRM.SignatureCallingConvention.VarArgs) {
parameterTypes = signature.ParameterTypes
.Take(signature.RequiredParameterCount)
.Concat(new[] { SpecialType.ArgList })
.ToImmutableArray();
} else {
parameterTypes = signature.ParameterTypes;
}
// Search for the matching method:
method = null;
foreach (var m in methods) {
if (m.TypeParameters.Count != signature.GenericParameterCount)
continue;
if (CompareSignatures(m.Parameters, parameterTypes) && CompareTypes(m.ReturnType, signature.ReturnType)) {
method = m;
break;
}
}
} else {
method = null;
}
if (method == null) {
method = CreateFakeMethod(declaringType, name, signature);
}
}
if (classTypeArguments != null || methodTypeArguments != null) {
method = method.Specialize(new TypeParameterSubstitution(classTypeArguments, methodTypeArguments));
}
if (signature.Header.CallingConvention == SRM.SignatureCallingConvention.VarArgs) {
method = new VarArgInstanceMethod(method, signature.ParameterTypes.Skip(signature.RequiredParameterCount));
}
return method;
}
static readonly NormalizeTypeVisitor normalizeTypeVisitor = new NormalizeTypeVisitor {
ReplaceClassTypeParametersWithDummy = true,
ReplaceMethodTypeParametersWithDummy = true,
};
static bool CompareTypes(IType a, IType b)
{
IType type1 = a.AcceptVisitor(normalizeTypeVisitor);
IType type2 = b.AcceptVisitor(normalizeTypeVisitor);
return type1.Equals(type2);
}
static bool IsVarArgMethod(IMethod method)
{
return method.Parameters.Count > 0 && method.Parameters[method.Parameters.Count - 1].Type.Kind == TypeKind.ArgList;
}
static bool CompareSignatures(IReadOnlyList<IParameter> parameters, ImmutableArray<IType> parameterTypes)
{
if (parameterTypes.Length != parameters.Count)
return false;
for (int i = 0; i < parameterTypes.Length; i++) {
if (!CompareTypes(parameterTypes[i], parameters[i].Type))
return false;
}
return true;
}
/// <summary>
/// Create a dummy IMethod from the specified MethodReference
/// </summary>
IMethod CreateFakeMethod(IType declaringType, string name, SRM.MethodSignature<IType> signature)
{
SymbolKind symbolKind = SymbolKind.Method;
if (name == ".ctor" || name == ".cctor")
symbolKind = SymbolKind.Constructor;
var m = new FakeMethod(compilation, symbolKind);
m.DeclaringType = declaringType;
m.Name = name;
m.ReturnType = signature.ReturnType;
m.IsStatic = !signature.Header.IsInstance;
var metadata = moduleDefinition.Metadata;
TypeParameterSubstitution substitution = null;
if (signature.GenericParameterCount > 0) {
var typeParameters = new List<ITypeParameter>();
for (int i = 0; i < signature.GenericParameterCount; i++) {
typeParameters.Add(new DefaultTypeParameter(m, i));
}
m.TypeParameters = typeParameters;
substitution = new TypeParameterSubstitution(null, typeParameters);
}
var parameters = new List<IParameter>();
for (int i = 0; i < signature.RequiredParameterCount; i++) {
var type = signature.ParameterTypes[i];
if (substitution != null) {
// replace the dummy method type parameters with the owned instances we just created
type = type.AcceptVisitor(substitution);
}
parameters.Add(new DefaultParameter(type, ""));
}
m.Parameters = parameters;
return m;
}
#endregion
#region Resolve Property

5
ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs

@ -89,6 +89,11 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -89,6 +89,11 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
return Implementation.CustomAttribute.MakeNamedArg(assembly.Compilation, attrType, name, rr);
}
internal KeyValuePair<IMember, ResolveResult> MakeNamedArg(IType attrType, string name, bool value)
{
return MakeNamedArg(attrType, name, assembly.Compilation.FindType(KnownTypeCode.Boolean), value);
}
#region MarshalAsAttribute (ConvertMarshalInfo)
internal void AddMarshalInfo(BlobHandle marshalInfo)
{

9
ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs

@ -38,6 +38,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -38,6 +38,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
NonSerialized,
// Method attributes:
DllImport,
PreserveSig,
MethodImpl,
// Parameter attributes:
ParamArray,
@ -70,6 +73,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -70,6 +73,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
// Field attributes:
new TopLevelTypeName("System.Runtime.InteropServices", nameof(FieldOffsetAttribute)),
new TopLevelTypeName("System", nameof(NonSerializedAttribute)),
// Method attributes:
new TopLevelTypeName("System.Runtime.InteropServices", nameof(DllImportAttribute)),
new TopLevelTypeName("System.Runtime.InteropServices", nameof(PreserveSigAttribute)),
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(MethodImplAttribute)),
// Parameter attributes:
new TopLevelTypeName("System", nameof(ParamArrayAttribute)),
// Marshalling attributes:
@ -88,5 +95,5 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -88,5 +95,5 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
{
return compilation.FindType(attrType.GetTypeName());
}
}
}

8
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataField.cs

@ -22,9 +22,7 @@ using System.Diagnostics; @@ -22,9 +22,7 @@ using System.Diagnostics;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.InteropServices;
using System.Threading;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.TypeSystem.Implementation
@ -32,7 +30,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -32,7 +30,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
/// <summary>
/// Field definition backed by System.Reflection.Metadata
/// </summary>
class MetadataField : IField
sealed class MetadataField : IField
{
readonly MetadataAssembly assembly;
readonly FieldDefinitionHandle handle;
@ -149,7 +147,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -149,7 +147,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public string FullName => $"{DeclaringType?.FullName}.{Name}";
public string ReflectionName => $"{DeclaringType?.ReflectionName}.{Name}";
public string Namespace => DeclaringType?.Namespace;
public string Namespace => DeclaringType?.Namespace ?? string.Empty;
public bool IsVolatile {
get {
@ -179,6 +177,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -179,6 +177,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
Volatile.Write(ref this.isVolatile, true);
ty = mod.ElementType;
}
ty = ApplyAttributeTypeVisitor.ApplyAttributesToType(ty, Compilation,
fieldDef.GetCustomAttributes(), metadata, assembly.TypeSystemOptions);
return LazyInit.GetOrSet(ref this.type, ty);
}

416
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs

@ -0,0 +1,416 @@ @@ -0,0 +1,416 @@
// Copyright (c) 2018 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.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.TypeSystem.Implementation
{
sealed class MetadataMethod : IMethod
{
readonly MetadataAssembly assembly;
readonly MethodDefinitionHandle handle;
// eagerly loaded fields:
readonly MethodAttributes attributes;
readonly SymbolKind symbolKind;
readonly ITypeParameter[] typeParameters;
public bool IsExtensionMethod { get; }
// lazy-loaded fields:
ITypeDefinition declaringType;
string name;
IAttribute[] customAttributes;
IAttribute[] returnTypeAttributes;
IParameter[] parameters;
IType returnType;
internal MetadataMethod(MetadataAssembly assembly, MethodDefinitionHandle handle)
{
Debug.Assert(assembly != null);
Debug.Assert(!handle.IsNil);
this.assembly = assembly;
this.handle = handle;
var metadata = assembly.metadata;
var def = metadata.GetMethodDefinition(handle);
this.attributes = def.Attributes;
this.symbolKind = SymbolKind.Method;
if ((attributes & (MethodAttributes.SpecialName | MethodAttributes.RTSpecialName)) != 0) {
string name = this.Name;
if (name == ".cctor" || name == ".ctor")
this.symbolKind = SymbolKind.Constructor;
else if (name.StartsWith("op_", StringComparison.Ordinal))
this.symbolKind = SymbolKind.Operator;
}
this.typeParameters = MetadataTypeParameter.Create(assembly, this, def.GetGenericParameters());
this.IsExtensionMethod = (attributes & MethodAttributes.Static) == MethodAttributes.Static
&& (assembly.TypeSystemOptions & TypeSystemOptions.ExtensionMethods) == TypeSystemOptions.ExtensionMethods
&& def.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.Extension);
}
public EntityHandle MetadataToken => handle;
public override string ToString()
{
return $"{MetadataTokens.GetToken(handle):X8} {DeclaringType?.ReflectionName}.{Name}";
}
public string Name {
get {
string name = LazyInit.VolatileRead(ref this.name);
if (name != null)
return name;
var metadata = assembly.metadata;
var methodDef = metadata.GetMethodDefinition(handle);
return LazyInit.GetOrSet(ref this.name, metadata.GetString(methodDef.Name));
}
}
public IReadOnlyList<ITypeParameter> TypeParameters => typeParameters;
IReadOnlyList<IType> IMethod.TypeArguments => typeParameters;
public SymbolKind SymbolKind => symbolKind;
public bool IsConstructor => symbolKind == SymbolKind.Constructor;
public bool IsDestructor => symbolKind == SymbolKind.Destructor;
public bool IsOperator => symbolKind == SymbolKind.Operator;
public bool IsAccessor => symbolKind == SymbolKind.Accessor;
public bool HasBody => assembly.metadata.GetMethodDefinition(handle).HasBody();
public IMember AccessorOwner => throw new NotImplementedException();
#region Signature (ReturnType + Parameters)
public IReadOnlyList<IParameter> Parameters {
get {
var parameters = LazyInit.VolatileRead(ref this.parameters);
if (parameters != null)
return parameters;
DecodeSignature();
return this.parameters;
}
}
public IType ReturnType {
get {
var returnType = LazyInit.VolatileRead(ref this.returnType);
if (returnType != null)
return returnType;
DecodeSignature();
return this.returnType;
}
}
private void DecodeSignature()
{
var metadata = assembly.metadata;
var methodDef = metadata.GetMethodDefinition(handle);
var genericContext = new GenericContext(DeclaringType.TypeParameters, this.TypeParameters);
var signature = methodDef.DecodeSignature(assembly.TypeProvider, genericContext);
int i = 0;
CustomAttributeHandleCollection? returnTypeAttributes = null;
IParameter[] parameters = new IParameter[signature.RequiredParameterCount
+ (signature.Header.CallingConvention == SignatureCallingConvention.VarArgs ? 1 : 0)];
foreach (var parameterHandle in methodDef.GetParameters()) {
var par = metadata.GetParameter(parameterHandle);
if (par.SequenceNumber == 0) {
// "parameter" holds return type attributes
returnTypeAttributes = par.GetCustomAttributes();
} else if (par.SequenceNumber > 0 && i < signature.RequiredParameterCount) {
Debug.Assert(par.SequenceNumber - 1 == i);
var parameterType = ApplyAttributeTypeVisitor.ApplyAttributesToType(
signature.ParameterTypes[i], Compilation,
par.GetCustomAttributes(), metadata, assembly.TypeSystemOptions);
parameters[i] = new MetadataParameter(assembly, this, parameterType, parameterHandle);
i++;
}
}
while (i < signature.RequiredParameterCount) {
var parameterType = ApplyAttributeTypeVisitor.ApplyAttributesToType(
signature.ParameterTypes[i], Compilation, null, metadata, assembly.TypeSystemOptions);
parameters[i] = new DefaultParameter(parameterType, name: string.Empty, owner: this,
isRef: parameterType.Kind == TypeKind.ByReference);
i++;
}
if (signature.Header.CallingConvention == SignatureCallingConvention.VarArgs) {
parameters[i] = new DefaultParameter(SpecialType.ArgList, name: string.Empty, owner: this);
i++;
}
Debug.Assert(i == parameters.Length);
var returnType = ApplyAttributeTypeVisitor.ApplyAttributesToType(signature.ReturnType,
Compilation, returnTypeAttributes, metadata, assembly.TypeSystemOptions);
LazyInit.GetOrSet(ref this.returnType, returnType);
LazyInit.GetOrSet(ref this.parameters, parameters);
}
#endregion
public IReadOnlyList<IMember> ImplementedInterfaceMembers => throw new NotImplementedException();
public bool IsExplicitInterfaceImplementation => throw new NotImplementedException();
IMember IMember.MemberDefinition => this;
IMethod IMethod.ReducedFrom => this;
TypeParameterSubstitution IMember.Substitution => TypeParameterSubstitution.Identity;
public ITypeDefinition DeclaringTypeDefinition {
get {
var declType = LazyInit.VolatileRead(ref this.declaringType);
if (declType != null) {
return declType;
} else {
var def = assembly.metadata.GetMethodDefinition(handle);
return LazyInit.GetOrSet(ref this.declaringType,
assembly.GetDefinition(def.GetDeclaringType()));
}
}
}
public IType DeclaringType => DeclaringTypeDefinition;
public IAssembly ParentAssembly => assembly;
public ICompilation Compilation => assembly.Compilation;
#region Attributes
public IReadOnlyList<IAttribute> Attributes {
get {
var attr = LazyInit.VolatileRead(ref this.customAttributes);
if (attr != null)
return attr;
return LazyInit.GetOrSet(ref this.customAttributes, DecodeAttributes());
}
}
IType FindInteropType(string name)
{
return assembly.Compilation.FindType(new TopLevelTypeName(
"System.Runtime.InteropServices", name, 0
));
}
IAttribute[] DecodeAttributes()
{
var b = new AttributeListBuilder(assembly);
var metadata = assembly.metadata;
var def = metadata.GetMethodDefinition(handle);
MethodImplAttributes implAttributes = def.ImplAttributes & ~MethodImplAttributes.CodeTypeMask;
#region DllImportAttribute
var info = def.GetImport();
if ((attributes & MethodAttributes.PinvokeImpl) == MethodAttributes.PinvokeImpl && !info.Module.IsNil) {
var dllImportType = assembly.GetAttributeType(KnownAttribute.DllImport);
var positionalArguments = new ResolveResult[] {
new ConstantResolveResult(assembly.Compilation.FindType(KnownTypeCode.String),
metadata.GetString(metadata.GetModuleReference(info.Module).Name))
};
var namedArgs = new List<KeyValuePair<IMember, ResolveResult>>();
var importAttrs = info.Attributes;
if ((importAttrs & MethodImportAttributes.BestFitMappingDisable) == MethodImportAttributes.BestFitMappingDisable)
namedArgs.Add(b.MakeNamedArg(dllImportType, "BestFitMapping", false));
if ((importAttrs & MethodImportAttributes.BestFitMappingEnable) == MethodImportAttributes.BestFitMappingEnable)
namedArgs.Add(b.MakeNamedArg(dllImportType, "BestFitMapping", true));
CallingConvention callingConvention;
switch (info.Attributes & MethodImportAttributes.CallingConventionMask) {
case 0:
Debug.WriteLine($"P/Invoke calling convention not set on: {this}");
callingConvention = 0;
break;
case MethodImportAttributes.CallingConventionCDecl:
callingConvention = CallingConvention.Cdecl;
break;
case MethodImportAttributes.CallingConventionFastCall:
callingConvention = CallingConvention.FastCall;
break;
case MethodImportAttributes.CallingConventionStdCall:
callingConvention = CallingConvention.StdCall;
break;
case MethodImportAttributes.CallingConventionThisCall:
callingConvention = CallingConvention.ThisCall;
break;
case MethodImportAttributes.CallingConventionWinApi:
callingConvention = CallingConvention.Winapi;
break;
default:
throw new NotSupportedException("unknown calling convention");
}
if (callingConvention != CallingConvention.Winapi) {
var callingConventionType = FindInteropType(nameof(CallingConvention));
namedArgs.Add(b.MakeNamedArg(dllImportType, "CallingConvention", callingConventionType, (int)callingConvention));
}
CharSet charSet = CharSet.None;
switch (info.Attributes & MethodImportAttributes.CharSetMask) {
case MethodImportAttributes.CharSetAnsi:
charSet = CharSet.Ansi;
break;
case MethodImportAttributes.CharSetAuto:
charSet = CharSet.Auto;
break;
case MethodImportAttributes.CharSetUnicode:
charSet = CharSet.Unicode;
break;
}
if (charSet != CharSet.None) {
var charSetType = FindInteropType(nameof(CharSet));
namedArgs.Add(b.MakeNamedArg(dllImportType, "CharSet", charSetType, (int)charSet));
}
if (!info.Name.IsNil && info.Name != def.Name) {
namedArgs.Add(b.MakeNamedArg(dllImportType,
"EntryPoint", KnownTypeCode.String, metadata.GetString(info.Name)));
}
if ((info.Attributes & MethodImportAttributes.ExactSpelling) == MethodImportAttributes.ExactSpelling) {
namedArgs.Add(b.MakeNamedArg(dllImportType, "ExactSpelling", true));
}
if ((implAttributes & MethodImplAttributes.PreserveSig) == MethodImplAttributes.PreserveSig) {
implAttributes &= ~MethodImplAttributes.PreserveSig;
} else {
namedArgs.Add(b.MakeNamedArg(dllImportType, "PreserveSig", true));
}
if ((info.Attributes & MethodImportAttributes.SetLastError) == MethodImportAttributes.SetLastError)
namedArgs.Add(b.MakeNamedArg(dllImportType, "SetLastError", true));
if ((info.Attributes & MethodImportAttributes.ThrowOnUnmappableCharDisable) == MethodImportAttributes.ThrowOnUnmappableCharDisable)
namedArgs.Add(b.MakeNamedArg(dllImportType, "ThrowOnUnmappableChar", false));
if ((info.Attributes & MethodImportAttributes.ThrowOnUnmappableCharEnable) == MethodImportAttributes.ThrowOnUnmappableCharEnable)
namedArgs.Add(b.MakeNamedArg(dllImportType, "ThrowOnUnmappableChar", true));
b.Add(new DefaultAttribute(dllImportType, positionalArguments, namedArgs));
}
#endregion
#region PreserveSigAttribute
if (implAttributes == MethodImplAttributes.PreserveSig) {
b.Add(KnownAttribute.PreserveSig);
implAttributes = 0;
}
#endregion
#region MethodImplAttribute
if (implAttributes != 0) {
b.Add(KnownAttribute.MethodImpl, new ConstantResolveResult(
Compilation.FindType(new TopLevelTypeName("System.Runtime.CompilerServices", nameof(MethodImplOptions))),
(int)implAttributes
));
}
#endregion
b.Add(def.GetCustomAttributes());
b.AddSecurityAttributes(def.GetDeclarativeSecurityAttributes());
return b.Build();
}
#endregion
#region Return type attributes
public IReadOnlyList<IAttribute> ReturnTypeAttributes {
get {
var attr = LazyInit.VolatileRead(ref this.returnTypeAttributes);
if (attr != null)
return attr;
return LazyInit.GetOrSet(ref this.returnTypeAttributes, DecodeReturnTypeAttributes());
}
}
private IAttribute[] DecodeReturnTypeAttributes()
{
var b = new AttributeListBuilder(assembly);
var metadata = assembly.metadata;
var methodDefinition = metadata.GetMethodDefinition(handle);
var parameters = methodDefinition.GetParameters();
if (parameters.Count > 0) {
var retParam = metadata.GetParameter(parameters.First());
if (retParam.SequenceNumber == 0) {
b.AddMarshalInfo(retParam.GetMarshallingDescriptor());
b.Add(retParam.GetCustomAttributes());
}
}
return b.Build();
}
#endregion
public Accessibility Accessibility => GetAccessibility(attributes);
internal static Accessibility GetAccessibility(MethodAttributes attr)
{
switch (attr & MethodAttributes.MemberAccessMask) {
case MethodAttributes.Public:
return Accessibility.Public;
case MethodAttributes.Assembly:
return Accessibility.Internal;
case MethodAttributes.Private:
return Accessibility.Private;
case MethodAttributes.Family:
return Accessibility.Protected;
case MethodAttributes.FamANDAssem:
return Accessibility.ProtectedAndInternal;
case MethodAttributes.FamORAssem:
return Accessibility.ProtectedOrInternal;
default:
return Accessibility.None;
}
}
public bool IsStatic => (attributes & MethodAttributes.Static) != 0;
public bool IsAbstract => (attributes & MethodAttributes.Abstract) != 0;
public bool IsSealed => (attributes & (MethodAttributes.Abstract | MethodAttributes.Final | MethodAttributes.NewSlot | MethodAttributes.Static)) == MethodAttributes.Final;
public bool IsVirtual => (attributes & (MethodAttributes.Abstract | MethodAttributes.Virtual | MethodAttributes.NewSlot)) == (MethodAttributes.Virtual | MethodAttributes.NewSlot);
public bool IsOverride => (attributes & (MethodAttributes.NewSlot | MethodAttributes.Static)) == 0;
public bool IsOverridable
=> (attributes & (MethodAttributes.Abstract | MethodAttributes.Virtual)) != 0
&& (attributes & MethodAttributes.Final) == 0;
bool IEntity.IsShadowing => throw new NotImplementedException();
public string FullName => $"{DeclaringType?.FullName}.{Name}";
public string ReflectionName => $"{DeclaringType?.ReflectionName}.{Name}";
public string Namespace => DeclaringType?.Namespace ?? string.Empty;
bool IMember.Equals(IMember obj, TypeVisitor typeNormalization)
{
return obj == this;
}
public IMethod Specialize(TypeParameterSubstitution substitution)
{
return SpecializedMethod.Create(this, substitution);
}
IMember IMember.Specialize(TypeParameterSubstitution substitution)
{
return SpecializedMethod.Create(this, substitution);
}
}
}

73
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs

@ -0,0 +1,73 @@ @@ -0,0 +1,73 @@
// Copyright (c) 2018 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.Generic;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Text;
namespace ICSharpCode.Decompiler.TypeSystem.Implementation
{
sealed class MetadataParameter : IParameter
{
readonly MetadataAssembly assembly;
readonly ParameterHandle handle;
readonly ParameterAttributes attributes;
public IType Type { get; }
public IParameterizedMember Owner { get; }
internal MetadataParameter(MetadataAssembly assembly, IParameterizedMember owner, IType type, ParameterHandle handle)
{
this.assembly = assembly;
this.Owner = owner;
this.Type = type;
this.handle = handle;
var param = assembly.metadata.GetParameter(handle);
this.attributes = param.Attributes;
}
public EntityHandle MetadataToken => handle;
public IReadOnlyList<IAttribute> Attributes => throw new NotImplementedException();
const ParameterAttributes inOut = ParameterAttributes.In | ParameterAttributes.Out;
public bool IsRef => Type.Kind == TypeKind.ByReference && (attributes & inOut) != ParameterAttributes.Out;
public bool IsOut => Type.Kind == TypeKind.ByReference && (attributes & inOut) == ParameterAttributes.Out;
public bool IsParams => throw new NotImplementedException();
public bool IsOptional => (attributes & ParameterAttributes.HasDefault) != 0;
public string Name => throw new NotImplementedException();
bool IVariable.IsConst => false;
public object ConstantValue => throw new NotImplementedException();
SymbolKind ISymbol.SymbolKind => SymbolKind.Parameter;
public override string ToString()
{
return $"{MetadataTokens.GetToken(handle):X8} {DefaultParameter.ToString(this)}";
}
}
}

125
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeDefinition.cs

@ -82,7 +82,11 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -82,7 +82,11 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
this.Kind = TypeKind.Enum;
this.EnumUnderlyingType = assembly.Compilation.FindType(underlyingType.ToKnownTypeCode());
} else if (td.IsValueType(metadata)) {
this.Kind = TypeKind.Struct;
if (KnownTypeCode == KnownTypeCode.Void) {
this.Kind = TypeKind.Void;
} else {
this.Kind = TypeKind.Struct;
}
} else if (td.IsDelegate(metadata)) {
this.Kind = TypeKind.Delegate;
} else {
@ -97,8 +101,24 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -97,8 +101,24 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
return $"{MetadataTokens.GetToken(handle):X8} {fullTypeName}";
}
public IReadOnlyList<ITypeDefinition> NestedTypes => throw new NotImplementedException();
ITypeDefinition[] nestedTypes;
public IReadOnlyList<ITypeDefinition> NestedTypes {
get {
var nestedTypes = LazyInit.VolatileRead(ref this.nestedTypes);
if (nestedTypes != null)
return nestedTypes;
var metadata = assembly.metadata;
var nestedTypeCollection = metadata.GetTypeDefinition(handle).GetNestedTypes();
var nestedTypeList = new List<ITypeDefinition>(nestedTypeCollection.Length);
foreach (TypeDefinitionHandle h in nestedTypeCollection) {
nestedTypeList.Add(assembly.GetDefinition(h));
}
return LazyInit.GetOrSet(ref this.nestedTypes, nestedTypeList.ToArray());
}
}
#region Members
IMember[] members;
public IReadOnlyList<IMember> Members {
@ -132,13 +152,57 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -132,13 +152,57 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
}
public IEnumerable<IMethod> Methods => throw new NotImplementedException();
IProperty[] properties;
public IEnumerable<IProperty> Properties {
get {
var properties = LazyInit.VolatileRead(ref this.properties);
if (properties != null)
return properties;
var metadata = assembly.metadata;
var propertyCollection = metadata.GetTypeDefinition(handle).GetProperties();
var propertyList = new List<IProperty>(propertyCollection.Count);
foreach (PropertyDefinitionHandle h in propertyCollection) {
propertyList.Add(assembly.GetDefinition(h));
}
return LazyInit.GetOrSet(ref this.properties, propertyList.ToArray());
}
}
public IEnumerable<IProperty> Properties => throw new NotImplementedException();
IEvent[] events;
public IEnumerable<IEvent> Events => throw new NotImplementedException();
public IEnumerable<IEvent> Events {
get {
var events = LazyInit.VolatileRead(ref this.events);
if (events != null)
return events;
var metadata = assembly.metadata;
var eventCollection = metadata.GetTypeDefinition(handle).GetEvents();
var eventList = new List<IEvent>(eventCollection.Count);
foreach (EventDefinitionHandle h in eventCollection) {
eventList.Add(assembly.GetDefinition(h));
}
return LazyInit.GetOrSet(ref this.events, eventList.ToArray());
}
}
IMethod[] methods;
public IEnumerable<IMethod> Methods {
get {
var methods = LazyInit.VolatileRead(ref this.methods);
if (methods != null)
return methods;
var metadata = assembly.metadata;
var methodsCollection = metadata.GetTypeDefinition(handle).GetMethods();
var methodsList = new List<IMethod>(methodsCollection.Count);
foreach (MethodDefinitionHandle h in methodsCollection) {
methodsList.Add(assembly.GetDefinition(h));
}
return LazyInit.GetOrSet(ref this.methods, methodsList.ToArray());
}
}
#endregion
public IType DeclaringType => DeclaringTypeDefinition;
@ -161,7 +225,28 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -161,7 +225,28 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
IReadOnlyList<IType> IType.TypeArguments => TypeParameters;
public IEnumerable<IType> DirectBaseTypes => throw new NotImplementedException();
List<IType> directBaseTypes;
public IEnumerable<IType> DirectBaseTypes {
get {
var baseTypes = LazyInit.VolatileRead(ref this.directBaseTypes);
if (baseTypes != null)
return baseTypes;
var metadata = assembly.metadata;
var td = metadata.GetTypeDefinition(handle);
var context = new GenericContext(TypeParameters);
var interfaceImplCollection = td.GetInterfaceImplementations();
baseTypes = new List<IType>(1 + interfaceImplCollection.Count);
if (!td.BaseType.IsNil) {
baseTypes.Add(assembly.ResolveType(td.BaseType, context));
}
foreach (var h in interfaceImplCollection) {
var iface = metadata.GetInterfaceImplementation(h);
baseTypes.Add(assembly.ResolveType(iface.Interface, context, iface.GetCustomAttributes()));
}
return LazyInit.GetOrSet(ref this.directBaseTypes, baseTypes);
}
}
public EntityHandle MetadataToken => handle;
@ -285,7 +370,17 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -285,7 +370,17 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public ICompilation Compilation => assembly.Compilation;
public string FullName => throw new NotImplementedException();
public string FullName {
get {
if (DeclaringType != null)
return DeclaringType.FullName + "." + Name;
else if (!string.IsNullOrEmpty(this.Namespace))
return this.Namespace + "." + Name;
else
return Name;
}
}
public string ReflectionName => fullTypeName.ReflectionName;
public string Namespace => fullTypeName.TopLevelTypeName.Namespace;
@ -344,6 +439,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -344,6 +439,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public IEnumerable<IMethod> GetMethods(Predicate<IMethod> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if (Kind == TypeKind.Void)
return EmptyList<IMethod>.Instance;
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) {
return GetFiltered(this.Methods, ExtensionMethods.And(m => !m.IsConstructor, filter));
} else {
@ -353,11 +450,15 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -353,11 +450,15 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public IEnumerable<IMethod> GetMethods(IReadOnlyList<IType> typeArguments, Predicate<IMethod> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if (Kind == TypeKind.Void)
return EmptyList<IMethod>.Instance;
return GetMembersHelper.GetMethods(this, typeArguments, filter, options);
}
public IEnumerable<IMethod> GetConstructors(Predicate<IMethod> filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers)
{
if (Kind == TypeKind.Void)
return EmptyList<IMethod>.Instance;
if (ComHelper.IsComImport(this)) {
IType coClass = ComHelper.GetCoClass(this);
using (var busyLock = BusyManager.Enter(this)) {
@ -377,6 +478,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -377,6 +478,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public IEnumerable<IProperty> GetProperties(Predicate<IProperty> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if (Kind == TypeKind.Void)
return EmptyList<IProperty>.Instance;
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) {
return GetFiltered(this.Properties, filter);
} else {
@ -386,6 +489,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -386,6 +489,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public IEnumerable<IField> GetFields(Predicate<IField> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if (Kind == TypeKind.Void)
return EmptyList<IField>.Instance;
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) {
return GetFiltered(this.Fields, filter);
} else {
@ -395,6 +500,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -395,6 +500,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public IEnumerable<IEvent> GetEvents(Predicate<IEvent> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if (Kind == TypeKind.Void)
return EmptyList<IEvent>.Instance;
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) {
return GetFiltered(this.Events, filter);
} else {
@ -404,6 +511,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -404,6 +511,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public IEnumerable<IMember> GetMembers(Predicate<IMember> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if (Kind == TypeKind.Void)
return EmptyList<IMethod>.Instance;
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) {
return GetFiltered(this.Members, filter);
} else {
@ -413,6 +522,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -413,6 +522,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public IEnumerable<IMethod> GetAccessors(Predicate<IMethod> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if (Kind == TypeKind.Void)
return EmptyList<IMethod>.Instance;
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) {
return GetFilteredAccessors(filter);
} else {

13
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeParameter.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
@ -36,23 +37,25 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -36,23 +37,25 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
IReadOnlyList<IAttribute> customAttributes;
IReadOnlyList<IType> constraints;
public static IReadOnlyList<ITypeParameter> Create(MetadataAssembly assembly, IEntity owner, GenericParameterHandleCollection handles)
public static ITypeParameter[] Create(MetadataAssembly assembly, IEntity owner, GenericParameterHandleCollection handles)
{
if (handles.Count == 0)
return EmptyList<ITypeParameter>.Instance;
return Empty<ITypeParameter>.Array;
var tps = new ITypeParameter[handles.Count];
int i = 0;
foreach (var handle in handles) {
tps[i] = Create(assembly, owner, handle);
tps[i] = Create(assembly, owner, i, handle);
i++;
}
return tps;
}
public static MetadataTypeParameter Create(MetadataAssembly assembly, IEntity owner, GenericParameterHandle handle)
public static MetadataTypeParameter Create(MetadataAssembly assembly, IEntity owner, int index, GenericParameterHandle handle)
{
var metadata = assembly.metadata;
var gp = metadata.GetGenericParameter(handle);
return new MetadataTypeParameter(assembly, owner, gp.Index, assembly.GetString(gp.Name), handle, gp.Attributes);
Debug.Assert(gp.Index == index);
return new MetadataTypeParameter(assembly, owner, index, assembly.GetString(gp.Name), handle, gp.Attributes);
}
private MetadataTypeParameter(MetadataAssembly assembly, IEntity owner, int index, string name,

205
ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
@ -48,6 +49,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -48,6 +49,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
readonly MetadataNamespace rootNamespace;
readonly MetadataTypeDefinition[] typeDefs;
readonly MetadataField[] fieldDefs;
readonly MetadataMethod[] methodDefs;
internal MetadataAssembly(ICompilation compilation, Metadata.PEFile peFile, TypeSystemOptions options)
{
@ -67,9 +69,12 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -67,9 +69,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
this.AssemblyName = metadata.GetString(moddef.Name);
this.FullAssemblyName = this.AssemblyName;
}
this.rootNamespace = new MetadataNamespace(this, null, string.Empty, metadata.GetNamespaceDefinitionRoot());
// create arrays for resolved entities, indexed by row index
this.typeDefs = new MetadataTypeDefinition[metadata.TypeDefinitions.Count + 1];
this.fieldDefs = new MetadataField[metadata.FieldDefinitions.Count + 1];
this.methodDefs = new MetadataMethod[metadata.MethodDefinitions.Count + 1];
}
internal string GetString(StringHandle name)
@ -181,7 +186,14 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -181,7 +186,14 @@ namespace ICSharpCode.Decompiler.TypeSystem
public IMethod GetDefinition(MethodDefinitionHandle handle)
{
throw new NotImplementedException();
int row = MetadataTokens.GetRowNumber(handle);
if (row >= methodDefs.Length)
return null;
var method = LazyInit.VolatileRead(ref methodDefs[row]);
if (method != null || handle.IsNil)
return method;
method = new MetadataMethod(this, handle);
return LazyInit.GetOrSet(ref methodDefs[row], method);
}
public IProperty GetDefinition(PropertyDefinitionHandle handle)
@ -195,16 +207,199 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -195,16 +207,199 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
#endregion
public IMethod ResolveMethod(EntityHandle methodRefDefSpec, GenericContext context = default)
#region Resolve Type
public IType ResolveType(EntityHandle typeRefDefSpec, GenericContext context, CustomAttributeHandleCollection? typeAttributes = null)
{
throw new NotImplementedException();
return ResolveType(typeRefDefSpec, context, options, typeAttributes);
}
public IType ResolveType(SRM.EntityHandle typeRefDefSpec, GenericContext context, TypeSystemOptions customOptions, CustomAttributeHandleCollection? typeAttributes = null)
{
return MetadataTypeReference.Resolve(typeRefDefSpec, metadata, TypeProvider, context, customOptions, typeAttributes);
}
IType ResolveDeclaringType(SRM.EntityHandle declaringTypeReference, GenericContext context)
{
// resolve without substituting dynamic/tuple types
return ResolveType(declaringTypeReference, context,
options & ~(TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple));
}
#endregion
#region ResolveMethod
public IMethod ResolveMethod(EntityHandle methodReference, GenericContext context = default)
{
if (methodReference.IsNil)
throw new ArgumentNullException(nameof(methodReference));
switch (methodReference.Kind) {
case SRM.HandleKind.MethodDefinition:
return ResolveMethodDefinition(metadata, (SRM.MethodDefinitionHandle)methodReference, expandVarArgs: true);
case SRM.HandleKind.MemberReference:
return ResolveMethodReference(metadata, (SRM.MemberReferenceHandle)methodReference, context);
case SRM.HandleKind.MethodSpecification:
var methodSpec = metadata.GetMethodSpecification((SRM.MethodSpecificationHandle)methodReference);
var methodTypeArgs = methodSpec.DecodeSignature(TypeProvider, context);
IMethod method;
if (methodSpec.Method.Kind == SRM.HandleKind.MethodDefinition) {
// generic instance of a methoddef (=generic method in non-generic class in current assembly)
method = ResolveMethodDefinition(metadata, (SRM.MethodDefinitionHandle)methodSpec.Method, expandVarArgs: true);
method = method.Specialize(new TypeParameterSubstitution(context.ClassTypeParameters, methodTypeArgs));
} else {
method = ResolveMethodReference(metadata, (SRM.MemberReferenceHandle)methodSpec.Method, context, methodTypeArgs);
}
return method;
default:
throw new ArgumentException("HandleKind must be either a MethodDefinition, MemberReference or MethodSpecification", nameof(methodReference));
}
}
IMethod ResolveMethodDefinition(SRM.MetadataReader metadata, SRM.MethodDefinitionHandle methodDefHandle, bool expandVarArgs)
{
var method = GetDefinition(methodDefHandle);
if (method == null) {
throw new NotImplementedException();
}
if (expandVarArgs && method.Parameters.LastOrDefault()?.Type.Kind == TypeKind.ArgList) {
method = new VarArgInstanceMethod(method, EmptyList<IType>.Instance);
}
return method;
}
/// <summary>
/// Resolves a method reference.
/// </summary>
/// <remarks>
/// Class type arguments are provided by the declaring type stored in the memberRef.
/// Method type arguments are provided by the caller.
/// </remarks>
IMethod ResolveMethodReference(SRM.MetadataReader metadata, SRM.MemberReferenceHandle memberRefHandle, GenericContext context, IReadOnlyList<IType> methodTypeArguments = null)
{
var memberRef = metadata.GetMemberReference(memberRefHandle);
Debug.Assert(memberRef.GetKind() == SRM.MemberReferenceKind.Method);
SRM.MethodSignature<IType> signature;
IReadOnlyList<IType> classTypeArguments = null;
IMethod method;
if (memberRef.Parent.Kind == SRM.HandleKind.MethodDefinition) {
method = ResolveMethodDefinition(metadata, (SRM.MethodDefinitionHandle)memberRef.Parent, expandVarArgs: false);
signature = memberRef.DecodeMethodSignature(TypeProvider, context);
} else {
var declaringType = ResolveDeclaringType(memberRef.Parent, context);
var declaringTypeDefinition = declaringType.GetDefinition();
if (declaringType.TypeArguments.Count > 0) {
classTypeArguments = declaringType.TypeArguments;
}
// Note: declaringType might be parameterized, but the signature is for the original method definition.
// We'll have to search the member directly on declaringTypeDefinition.
string name = metadata.GetString(memberRef.Name);
signature = memberRef.DecodeMethodSignature(TypeProvider,
new GenericContext(declaringTypeDefinition?.TypeParameters));
if (declaringTypeDefinition != null) {
// Find the set of overloads to search:
IEnumerable<IMethod> methods;
if (name == ".ctor") {
methods = declaringTypeDefinition.GetConstructors();
} else if (name == ".cctor") {
methods = declaringTypeDefinition.Methods.Where(m => m.IsConstructor && m.IsStatic);
} else {
methods = declaringTypeDefinition.GetMethods(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers)
.Concat(declaringTypeDefinition.GetAccessors(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers));
}
// Determine the expected parameters from the signature:
ImmutableArray<IType> parameterTypes;
if (signature.Header.CallingConvention == SRM.SignatureCallingConvention.VarArgs) {
parameterTypes = signature.ParameterTypes
.Take(signature.RequiredParameterCount)
.Concat(new[] { SpecialType.ArgList })
.ToImmutableArray();
} else {
parameterTypes = signature.ParameterTypes;
}
// Search for the matching method:
method = null;
foreach (var m in methods) {
if (m.TypeParameters.Count != signature.GenericParameterCount)
continue;
if (CompareSignatures(m.Parameters, parameterTypes) && CompareTypes(m.ReturnType, signature.ReturnType)) {
method = m;
break;
}
}
} else {
method = null;
}
if (method == null) {
method = CreateFakeMethod(declaringType, name, signature);
}
}
if (classTypeArguments != null || methodTypeArguments != null) {
method = method.Specialize(new TypeParameterSubstitution(classTypeArguments, methodTypeArguments));
}
if (signature.Header.CallingConvention == SRM.SignatureCallingConvention.VarArgs) {
method = new VarArgInstanceMethod(method, signature.ParameterTypes.Skip(signature.RequiredParameterCount));
}
return method;
}
public IType ResolveType(EntityHandle typeRefDefSpec, GenericContext context = default, CustomAttributeHandleCollection? typeAttributes = null)
static readonly NormalizeTypeVisitor normalizeTypeVisitor = new NormalizeTypeVisitor {
ReplaceClassTypeParametersWithDummy = true,
ReplaceMethodTypeParametersWithDummy = true,
};
static bool CompareTypes(IType a, IType b)
{
return MetadataTypeReference.Resolve(typeRefDefSpec, metadata, TypeProvider, context, options, typeAttributes);
IType type1 = a.AcceptVisitor(normalizeTypeVisitor);
IType type2 = b.AcceptVisitor(normalizeTypeVisitor);
return type1.Equals(type2);
}
static bool CompareSignatures(IReadOnlyList<IParameter> parameters, ImmutableArray<IType> parameterTypes)
{
if (parameterTypes.Length != parameters.Count)
return false;
for (int i = 0; i < parameterTypes.Length; i++) {
if (!CompareTypes(parameterTypes[i], parameters[i].Type))
return false;
}
return true;
}
/// <summary>
/// Create a dummy IMethod from the specified MethodReference
/// </summary>
IMethod CreateFakeMethod(IType declaringType, string name, SRM.MethodSignature<IType> signature)
{
SymbolKind symbolKind = SymbolKind.Method;
if (name == ".ctor" || name == ".cctor")
symbolKind = SymbolKind.Constructor;
var m = new FakeMethod(Compilation, symbolKind);
m.DeclaringType = declaringType;
m.Name = name;
m.ReturnType = signature.ReturnType;
m.IsStatic = !signature.Header.IsInstance;
TypeParameterSubstitution substitution = null;
if (signature.GenericParameterCount > 0) {
var typeParameters = new List<ITypeParameter>();
for (int i = 0; i < signature.GenericParameterCount; i++) {
typeParameters.Add(new DefaultTypeParameter(m, i));
}
m.TypeParameters = typeParameters;
substitution = new TypeParameterSubstitution(null, typeParameters);
}
var parameters = new List<IParameter>();
for (int i = 0; i < signature.RequiredParameterCount; i++) {
var type = signature.ParameterTypes[i];
if (substitution != null) {
// replace the dummy method type parameters with the owned instances we just created
type = type.AcceptVisitor(substitution);
}
parameters.Add(new DefaultParameter(type, ""));
}
m.Parameters = parameters;
return m;
}
#endregion
#region Module / Assembly attributes
IAttribute[] assemblyAttributes;
IAttribute[] moduleAttributes;

3
ICSharpCode.Decompiler/TypeSystem/TypeProvider.cs

@ -144,8 +144,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -144,8 +144,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
public IType GetTypeFromSerializedName(string name)
{
// TODO: aren't we missing support for assembly-qualified names?
return new GetClassTypeReference(new FullTypeName(name))
return ReflectionHelper.ParseReflectionName(name)
.Resolve(assembly != null ? new SimpleTypeResolveContext(assembly) : new SimpleTypeResolveContext(compilation));
}

Loading…
Cancel
Save