Browse Source

Use MetadataToken for type lookups within the current assembly.

pull/1108/head
Daniel Grunwald 7 years ago
parent
commit
bf64e754df
  1. 3
      ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
  2. 123
      ICSharpCode.Decompiler/TypeSystem/CecilLoader.cs
  3. 5
      ICSharpCode.Decompiler/TypeSystem/IAssembly.cs
  4. 61
      ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs

3
ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs

@ -271,9 +271,6 @@ namespace ICSharpCode.Decompiler.Tests @@ -271,9 +271,6 @@ namespace ICSharpCode.Decompiler.Tests
[Test]
public void LINQRaytracer([ValueSource("defaultOptions")] CSharpCompilerOptions options)
{
if (options.HasFlag(CSharpCompilerOptions.UseMcs)) {
Assert.Ignore("Decompiler bug with mono!");
}
RunCS(options: options);
}

123
ICSharpCode.Decompiler/TypeSystem/CecilLoader.cs

@ -301,29 +301,58 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -301,29 +301,58 @@ namespace ICSharpCode.Decompiler.TypeSystem
ITypeReference CreateType(TypeReference type, ICustomAttributeProvider typeAttributes, ref int typeIndex, bool isFromSignature)
{
while (type is OptionalModifierType || type is RequiredModifierType) {
type = ((TypeSpecification)type).ElementType;
isFromSignature = true;
}
if (type == null) {
return SpecialType.UnknownType;
}
if (type is Mono.Cecil.ByReferenceType) {
switch (type.MetadataType) {
case MetadataType.Void:
return KnownTypeReference.Get(KnownTypeCode.Void);
case MetadataType.Boolean:
return KnownTypeReference.Get(KnownTypeCode.Boolean);
case MetadataType.Char:
return KnownTypeReference.Get(KnownTypeCode.Char);
case MetadataType.SByte:
return KnownTypeReference.Get(KnownTypeCode.SByte);
case MetadataType.Byte:
return KnownTypeReference.Get(KnownTypeCode.Byte);
case MetadataType.Int16:
return KnownTypeReference.Get(KnownTypeCode.Int16);
case MetadataType.UInt16:
return KnownTypeReference.Get(KnownTypeCode.UInt16);
case MetadataType.Int32:
return KnownTypeReference.Get(KnownTypeCode.Int32);
case MetadataType.UInt32:
return KnownTypeReference.Get(KnownTypeCode.UInt32);
case MetadataType.Int64:
return KnownTypeReference.Get(KnownTypeCode.Int64);
case MetadataType.UInt64:
return KnownTypeReference.Get(KnownTypeCode.UInt64);
case MetadataType.Single:
return KnownTypeReference.Get(KnownTypeCode.Single);
case MetadataType.Double:
return KnownTypeReference.Get(KnownTypeCode.Double);
case MetadataType.String:
return KnownTypeReference.Get(KnownTypeCode.String);
case MetadataType.Pointer:
typeIndex++;
return interningProvider.Intern(
new ByReferenceTypeReference(
new PointerTypeReference(
CreateType(
(type as Mono.Cecil.ByReferenceType).ElementType,
(type as Mono.Cecil.PointerType).ElementType,
typeAttributes, ref typeIndex, isFromSignature: true)));
} else if (type is Mono.Cecil.PointerType) {
case MetadataType.ByReference:
typeIndex++;
return interningProvider.Intern(
new PointerTypeReference(
new ByReferenceTypeReference(
CreateType(
(type as Mono.Cecil.PointerType).ElementType,
(type as Mono.Cecil.ByReferenceType).ElementType,
typeAttributes, ref typeIndex, isFromSignature: true)));
} else if (type is Mono.Cecil.ArrayType) {
case MetadataType.Var:
return TypeParameterReference.Create(SymbolKind.TypeDefinition, ((GenericParameter)type).Position);
case MetadataType.MVar:
return TypeParameterReference.Create(SymbolKind.Method, ((GenericParameter)type).Position);
case MetadataType.Array:
typeIndex++;
return interningProvider.Intern(
new ArrayTypeReference(
@ -331,7 +360,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -331,7 +360,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
(type as Mono.Cecil.ArrayType).ElementType,
typeAttributes, ref typeIndex, isFromSignature: true),
(type as Mono.Cecil.ArrayType).Rank));
} else if (type is GenericInstanceType) {
case MetadataType.GenericInstance:
GenericInstanceType gType = (GenericInstanceType)type;
ITypeReference baseType = CreateType(gType.ElementType, typeAttributes, ref typeIndex, isFromSignature: true);
ITypeReference[] para = new ITypeReference[gType.GenericArguments.Count];
@ -340,19 +369,41 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -340,19 +369,41 @@ namespace ICSharpCode.Decompiler.TypeSystem
para[i] = CreateType(gType.GenericArguments[i], typeAttributes, ref typeIndex, isFromSignature: true);
}
return interningProvider.Intern(new ParameterizedTypeReference(baseType, para));
} else if (type is GenericParameter) {
GenericParameter typeGP = (GenericParameter)type;
return TypeParameterReference.Create(typeGP.Owner is MethodReference ? SymbolKind.Method : SymbolKind.TypeDefinition, typeGP.Position);
} else if (type is FunctionPointerType) {
case MetadataType.IntPtr:
return KnownTypeReference.Get(KnownTypeCode.IntPtr);
case MetadataType.UIntPtr:
return KnownTypeReference.Get(KnownTypeCode.UIntPtr);
case MetadataType.FunctionPointer:
// C# and the NR typesystem don't support function pointer types.
// Function pointer types map to StackType.I, so we'll use IntPtr instead.
return KnownTypeReference.Get(KnownTypeCode.IntPtr);
} else if (type.IsNested) {
case MetadataType.Object:
if (HasDynamicAttribute(typeAttributes, typeIndex)) {
return SpecialType.Dynamic;
} else {
return KnownTypeReference.Get(KnownTypeCode.Object);
}
case MetadataType.RequiredModifier:
case MetadataType.OptionalModifier:
// we don't store modopts/modreqs in the NR type system
return CreateType(((TypeSpecification)type).ElementType, typeAttributes, ref typeIndex, isFromSignature: true);
case MetadataType.Sentinel:
return SpecialType.ArgList;
case MetadataType.Pinned:
return CreateType(((PinnedType)type).ElementType, typeAttributes, ref typeIndex, isFromSignature: true);
}
// valuetype/class/typedbyreference
if (type is TypeDefinition) {
return new TypeDefTokenTypeReference(type.MetadataToken);
}
// type.IsValueType is only reliable if we got this TypeReference from a signature,
// or if it's a TypeSpecification.
bool? isReferenceType = isFromSignature ? (bool?)!type.IsValueType : null;
if (type.IsNested) {
ITypeReference typeRef = CreateType(type.DeclaringType, typeAttributes, ref typeIndex, isFromSignature);
int partTypeParameterCount;
string namepart = ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out partTypeParameterCount);
namepart = interningProvider.Intern(namepart);
// type.IsValueType is only reliable if we got this TypeReference from a signature,
// or if it's a TypeSpecification.
bool? isReferenceType = isFromSignature ? (bool?)!type.IsValueType : null;
return interningProvider.Intern(new NestedTypeReference(typeRef, namepart, partTypeParameterCount, isReferenceType));
} else {
string ns = interningProvider.Intern(type.Namespace ?? string.Empty);
@ -362,24 +413,15 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -362,24 +413,15 @@ namespace ICSharpCode.Decompiler.TypeSystem
if (name == "Object" && ns == "System" && HasDynamicAttribute(typeAttributes, typeIndex)) {
return SpecialType.Dynamic;
} else {
}
int typeParameterCount;
name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(name, out typeParameterCount);
name = interningProvider.Intern(name);
if (currentAssembly != null) {
IUnresolvedTypeDefinition c = currentAssembly.GetTypeDefinition(ns, name, typeParameterCount);
if (c != null)
return c;
}
// type.IsValueType is only reliable if we got this TypeReference from a signature,
// or if it's a TypeSpecification.
bool? isReferenceType = isFromSignature ? (bool?)!type.IsValueType : null;
return interningProvider.Intern(new GetClassTypeReference(
GetAssemblyReference(type.Scope), ns, name, typeParameterCount,
isReferenceType));
}
}
}
IAssemblyReference GetAssemblyReference(IMetadataScope scope)
{
@ -406,6 +448,26 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -406,6 +448,26 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
return false;
}
sealed class TypeDefTokenTypeReference : ITypeReference
{
readonly MetadataToken token;
public TypeDefTokenTypeReference(MetadataToken token)
{
if (token.TokenType != TokenType.TypeDef)
throw new ArgumentException(nameof(token), "must be TypeDef token");
this.token = token;
}
public IType Resolve(ITypeResolveContext context)
{
ITypeDefinition td = context.CurrentAssembly.ResolveTypeDefToken(token);
if (td != null)
return td;
return SpecialType.UnknownType;
}
}
#endregion
#region Read Attributes
@ -918,6 +980,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -918,6 +980,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
name = name.Substring(pos + 1);
name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(name);
var nestedType = new DefaultUnresolvedTypeDefinition(declaringTypeDefinition, name);
nestedType.MetadataToken = nestedTypeDef.MetadataToken;
InitTypeParameters(nestedTypeDef, nestedType.TypeParameters);
nestedTypes.Add(nestedType);
InitTypeDefinition(nestedTypeDef, nestedType);

5
ICSharpCode.Decompiler/TypeSystem/IAssembly.cs

@ -123,5 +123,10 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -123,5 +123,10 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// Gets all non-nested types in the assembly.
/// </summary>
IEnumerable<ITypeDefinition> TopLevelTypeDefinitions { get; }
/// <summary>
/// Gets the type definition from the metadata token, or null if not found.
/// </summary>
ITypeDefinition ResolveTypeDefToken(Mono.Cecil.MetadataToken token);
}
}

61
ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs

@ -284,6 +284,42 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -284,6 +284,42 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
#endregion
IUnresolvedTypeDefinition[] allTypesByMetadata;
IUnresolvedTypeDefinition[] BuildMetadataLookup()
{
Debug.Assert(IsFrozen);
uint maxRowId = 0;
foreach (var td in this.GetAllTypeDefinitions()) {
var token = td.MetadataToken;
if (token.TokenType == Mono.Cecil.TokenType.TypeDef && token.RID > maxRowId) {
maxRowId = token.RID;
}
}
var lookup = new IUnresolvedTypeDefinition[maxRowId + 1];
foreach (var td in this.GetAllTypeDefinitions()) {
var token = td.MetadataToken;
if (token.TokenType == Mono.Cecil.TokenType.TypeDef) {
lookup[token.RID] = td;
}
}
return lookup;
}
internal IUnresolvedTypeDefinition GetTypeDefByToken(Mono.Cecil.MetadataToken token)
{
if (token.TokenType != Mono.Cecil.TokenType.TypeDef)
throw new ArgumentException("Token must be typedef-token.");
var lookup = LazyInit.VolatileRead(ref allTypesByMetadata);
if (lookup == null) {
lookup = LazyInit.GetOrSet(ref allTypesByMetadata, BuildMetadataLookup());
}
if (token.RID < lookup.Length)
return lookup[token.RID];
else
return null;
}
sealed class DefaultResolvedAssembly : IAssembly
{
readonly DefaultUnresolvedAssembly unresolvedAssembly;
@ -417,6 +453,31 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -417,6 +453,31 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
}
public ITypeDefinition ResolveTypeDefToken(Mono.Cecil.MetadataToken token)
{
var td = unresolvedAssembly.GetTypeDefByToken(token);
if (td != null)
return GetPotentiallyNestedTypeDefinition(td);
return null;
}
ITypeDefinition GetPotentiallyNestedTypeDefinition(IUnresolvedTypeDefinition unresolved)
{
var outerUnresolvedType = unresolved.DeclaringTypeDefinition;
if (outerUnresolvedType == null) {
// GetTypeDefinition() may only be called for top-level types
return GetTypeDefinition(unresolved);
}
var outerType = GetPotentiallyNestedTypeDefinition(outerUnresolvedType);
if (outerType == null)
return null;
foreach (var nestedType in outerType.NestedTypes) {
if (nestedType.MetadataToken == unresolved.MetadataToken)
return nestedType;
}
return null;
}
public override string ToString()
{
return "[DefaultResolvedAssembly " + AssemblyName + "]";

Loading…
Cancel
Save