Browse Source

#1085: Keep track of whether an unresolved type is a class type or a value type.

Also, fix a bug that caused specialization of a method on an unresolved type to be a no-op.
pull/1087/head
Daniel Grunwald 7 years ago
parent
commit
85314b494a
  1. 39
      ICSharpCode.Decompiler/TypeSystem/CecilLoader.cs
  2. 7
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
  3. 3
      ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedEvent.cs
  4. 3
      ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedField.cs
  5. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedMethod.cs
  6. 3
      ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedProperty.cs
  7. 6
      ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs
  8. 20
      ICSharpCode.Decompiler/TypeSystem/Implementation/GetClassTypeReference.cs
  9. 10
      ICSharpCode.Decompiler/TypeSystem/Implementation/NestedTypeReference.cs
  10. 13
      ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs
  11. 7
      ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs

39
ICSharpCode.Decompiler/TypeSystem/CecilLoader.cs

@ -301,16 +301,19 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -301,16 +301,19 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// a type system type reference.</param>
/// <param name="typeAttributes">Attributes associated with the Cecil type reference.
/// This is used to support the 'dynamic' type.</param>
public ITypeReference ReadTypeReference(TypeReference type, ICustomAttributeProvider typeAttributes = null)
/// <param name="isFromSignature">Whether this TypeReference is from a context where
/// IsValueType is set correctly.</param>
public ITypeReference ReadTypeReference(TypeReference type, ICustomAttributeProvider typeAttributes = null, bool isFromSignature=false)
{
int typeIndex = 0;
return CreateType(type, typeAttributes, ref typeIndex);
return CreateType(type, typeAttributes, ref typeIndex, isFromSignature);
}
ITypeReference CreateType(TypeReference type, ICustomAttributeProvider typeAttributes, ref int typeIndex)
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;
@ -322,29 +325,29 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -322,29 +325,29 @@ namespace ICSharpCode.Decompiler.TypeSystem
new ByReferenceTypeReference(
CreateType(
(type as Mono.Cecil.ByReferenceType).ElementType,
typeAttributes, ref typeIndex)));
typeAttributes, ref typeIndex, isFromSignature: true)));
} else if (type is Mono.Cecil.PointerType) {
typeIndex++;
return interningProvider.Intern(
new PointerTypeReference(
CreateType(
(type as Mono.Cecil.PointerType).ElementType,
typeAttributes, ref typeIndex)));
typeAttributes, ref typeIndex, isFromSignature: true)));
} else if (type is Mono.Cecil.ArrayType) {
typeIndex++;
return interningProvider.Intern(
new ArrayTypeReference(
CreateType(
(type as Mono.Cecil.ArrayType).ElementType,
typeAttributes, ref typeIndex),
typeAttributes, ref typeIndex, isFromSignature: true),
(type as Mono.Cecil.ArrayType).Rank));
} else if (type is GenericInstanceType) {
GenericInstanceType gType = (GenericInstanceType)type;
ITypeReference baseType = CreateType(gType.ElementType, typeAttributes, ref typeIndex);
ITypeReference baseType = CreateType(gType.ElementType, typeAttributes, ref typeIndex, isFromSignature: true);
ITypeReference[] para = new ITypeReference[gType.GenericArguments.Count];
for (int i = 0; i < para.Length; ++i) {
typeIndex++;
para[i] = CreateType(gType.GenericArguments[i], typeAttributes, ref typeIndex);
para[i] = CreateType(gType.GenericArguments[i], typeAttributes, ref typeIndex, isFromSignature: true);
}
return interningProvider.Intern(new ParameterizedTypeReference(baseType, para));
} else if (type is GenericParameter) {
@ -353,11 +356,14 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -353,11 +356,14 @@ namespace ICSharpCode.Decompiler.TypeSystem
} else if (type is FunctionPointerType) {
return KnownTypeReference.Get(KnownTypeCode.IntPtr);
} else if (type.IsNested) {
ITypeReference typeRef = CreateType(type.DeclaringType, typeAttributes, ref typeIndex);
ITypeReference typeRef = CreateType(type.DeclaringType, typeAttributes, ref typeIndex, isFromSignature);
int partTypeParameterCount;
string namepart = ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out partTypeParameterCount);
namepart = interningProvider.Intern(namepart);
return interningProvider.Intern(new NestedTypeReference(typeRef, namepart, partTypeParameterCount));
// 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);
string name = type.Name;
@ -375,7 +381,12 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -375,7 +381,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
if (c != null)
return c;
}
return interningProvider.Intern(new GetClassTypeReference(GetAssemblyReference(type.Scope), ns, name, typeParameterCount));
// 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));
}
}
}
@ -1323,7 +1334,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -1323,7 +1334,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
}
m.ReturnType = ReadTypeReference(method.ReturnType, typeAttributes: method.MethodReturnType);
m.ReturnType = ReadTypeReference(method.ReturnType, typeAttributes: method.MethodReturnType, isFromSignature: true);
if (HasAnyAttributes(method))
AddAttributes(method, m.Attributes, m.ReturnTypeAttributes);
@ -1431,7 +1442,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -1431,7 +1442,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
if (parameter == null)
throw new ArgumentNullException("parameter");
var type = ReadTypeReference(parameter.ParameterType, typeAttributes: parameter);
var type = ReadTypeReference(parameter.ParameterType, typeAttributes: parameter, isFromSignature: true);
var p = new DefaultUnresolvedParameter(type, interningProvider.Intern(parameter.Name));
if (parameter.ParameterType is Mono.Cecil.ByReferenceType) {
@ -1516,7 +1527,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -1516,7 +1527,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
f.Accessibility = GetAccessibility(field.Attributes);
f.IsReadOnly = field.IsInitOnly;
f.IsStatic = field.IsStatic;
f.ReturnType = ReadTypeReference(field.FieldType, typeAttributes: field);
f.ReturnType = ReadTypeReference(field.FieldType, typeAttributes: field, isFromSignature: true);
if (field.HasConstant) {
f.ConstantValue = CreateSimpleConstantValue(f.ReturnType, field.Constant);
}

7
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -223,6 +223,9 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -223,6 +223,9 @@ namespace ICSharpCode.Decompiler.TypeSystem
IMethod method;
if (!methodLookupCache.TryGetValue(methodReference, out method)) {
method = FindNonGenericMethod(methodReference.GetElementMethod());
if (method == null) {
method = CreateFakeMethod(methodReference);
}
if (methodReference.CallingConvention == MethodCallingConvention.VarArg) {
method = new VarArgInstanceMethod(
method,
@ -251,7 +254,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -251,7 +254,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
ITypeDefinition typeDef = Resolve(methodReference.DeclaringType).GetDefinition();
if (typeDef == null)
return CreateFakeMethod(methodReference);
return null;
IEnumerable<IMethod> methods;
if (methodReference.Name == ".ctor") {
methods = typeDef.GetConstructors();
@ -283,7 +286,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -283,7 +286,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
continue;
return method;
}
return CreateFakeMethod(methodReference);
return null;
}
static bool CompareTypes(IType a, IType b)

3
ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedEvent.cs

@ -60,8 +60,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -60,8 +60,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public override IMember Specialize(TypeParameterSubstitution substitution)
{
if (TypeParameterSubstitution.Identity.Equals(substitution)
|| DeclaringTypeDefinition == null
|| DeclaringTypeDefinition.TypeParameterCount == 0)
|| DeclaringType.TypeParameterCount == 0)
{
return this;
}

3
ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedField.cs

@ -73,8 +73,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -73,8 +73,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public override IMember Specialize(TypeParameterSubstitution substitution)
{
if (TypeParameterSubstitution.Identity.Equals(substitution)
|| DeclaringTypeDefinition == null
|| DeclaringTypeDefinition.TypeParameterCount == 0)
|| DeclaringType.TypeParameterCount == 0)
{
return this;
}

2
ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedMethod.cs

@ -253,7 +253,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -253,7 +253,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
if (DeclaringType is ArrayType)
return new SpecializedMethod(this, substitution);
if (TypeParameters.Count == 0) {
if (DeclaringTypeDefinition == null || DeclaringTypeDefinition.TypeParameterCount == 0)
if (DeclaringType.TypeParameterCount == 0)
return this;
if (substitution.MethodTypeArguments != null && substitution.MethodTypeArguments.Count > 0)
substitution = new TypeParameterSubstitution(substitution.ClassTypeArguments, EmptyList<IType>.Instance);

3
ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedProperty.cs

@ -100,8 +100,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -100,8 +100,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public override IMember Specialize(TypeParameterSubstitution substitution)
{
if (TypeParameterSubstitution.Identity.Equals(substitution)
|| DeclaringTypeDefinition == null
|| DeclaringTypeDefinition.TypeParameterCount == 0)
|| DeclaringType.TypeParameterCount == 0)
{
return this;
}

6
ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs

@ -674,7 +674,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -674,7 +674,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
{
ITypeDefinition declTypeDef = this.DeclaringTypeDefinition;
if (declTypeDef != null) {
return new NestedTypeReference(declTypeDef.ToTypeReference(), this.Name, this.TypeParameterCount - declTypeDef.TypeParameterCount);
return new NestedTypeReference(declTypeDef.ToTypeReference(),
this.Name, this.TypeParameterCount - declTypeDef.TypeParameterCount,
this.IsReferenceType);
} else {
IAssembly asm = this.ParentAssembly;
IAssemblyReference asmRef;
@ -682,7 +684,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -682,7 +684,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
asmRef = new DefaultAssemblyReference(asm.AssemblyName);
else
asmRef = null;
return new GetClassTypeReference(asmRef, this.Namespace, this.Name, this.TypeParameterCount);
return new GetClassTypeReference(asmRef, this.Namespace, this.Name, this.TypeParameterCount, this.IsReferenceType);
}
}

20
ICSharpCode.Decompiler/TypeSystem/Implementation/GetClassTypeReference.cs

@ -28,7 +28,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -28,7 +28,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
{
readonly IAssemblyReference assembly;
readonly FullTypeName fullTypeName;
readonly bool? isReferenceType;
/// <summary>
/// Creates a new GetClassTypeReference that searches a type definition.
/// </summary>
@ -37,10 +38,11 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -37,10 +38,11 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
/// If this parameter is null, the GetClassTypeReference will search in all
/// assemblies belonging to the compilation.
/// </param>
public GetClassTypeReference(FullTypeName fullTypeName, IAssemblyReference assembly = null)
public GetClassTypeReference(FullTypeName fullTypeName, IAssemblyReference assembly = null, bool? isReferenceType = null)
{
this.fullTypeName = fullTypeName;
this.assembly = assembly;
this.isReferenceType = isReferenceType;
}
/// <summary>
@ -49,11 +51,12 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -49,11 +51,12 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
/// <param name="namespaceName">The namespace name containing the type, e.g. "System.Collections.Generic".</param>
/// <param name="name">The name of the type, e.g. "List".</param>
/// <param name="typeParameterCount">The number of type parameters, (e.g. 1 for List&lt;T&gt;).</param>
public GetClassTypeReference(string namespaceName, string name, int typeParameterCount = 0)
public GetClassTypeReference(string namespaceName, string name, int typeParameterCount = 0, bool? isReferenceType = null)
{
this.fullTypeName = new TopLevelTypeName(namespaceName, name, typeParameterCount);
this.isReferenceType = isReferenceType;
}
/// <summary>
/// Creates a new GetClassTypeReference that searches a top-level type in the specified assembly.
/// </summary>
@ -62,12 +65,13 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -62,12 +65,13 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
/// <param name="namespaceName">The namespace name containing the type, e.g. "System.Collections.Generic".</param>
/// <param name="name">The name of the type, e.g. "List".</param>
/// <param name="typeParameterCount">The number of type parameters, (e.g. 1 for List&lt;T&gt;).</param>
public GetClassTypeReference(IAssemblyReference assembly, string namespaceName, string name, int typeParameterCount = 0)
public GetClassTypeReference(IAssemblyReference assembly, string namespaceName, string name, int typeParameterCount = 0, bool? isReferenceType = null)
{
this.assembly = assembly;
this.fullTypeName = new TopLevelTypeName(namespaceName, name, typeParameterCount);
this.isReferenceType = isReferenceType;
}
/// <summary>
/// Gets the assembly reference.
/// This property returns null if the GetClassTypeReference is searching in all assemblies
@ -117,7 +121,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -117,7 +121,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
type = ResolveInAllAssemblies(context);
}
}
return type ?? new UnknownType(fullTypeName);
return type ?? new UnknownType(fullTypeName, isReferenceType);
}
ISymbol ISymbolReference.Resolve(ITypeResolveContext context)
@ -143,7 +147,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -143,7 +147,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
GetClassTypeReference o = other as GetClassTypeReference;
return o != null && assembly == o.assembly && fullTypeName == o.fullTypeName;
return o != null && assembly == o.assembly && fullTypeName == o.fullTypeName && isReferenceType == o.isReferenceType;
}
}
}

10
ICSharpCode.Decompiler/TypeSystem/Implementation/NestedTypeReference.cs

@ -29,7 +29,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -29,7 +29,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
readonly ITypeReference declaringTypeRef;
readonly string name;
readonly int additionalTypeParameterCount;
readonly bool? isReferenceType;
/// <summary>
/// Creates a new NestedTypeReference.
/// </summary>
@ -40,7 +41,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -40,7 +41,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
/// <paramref name="declaringTypeRef"/> must be exactly the (unbound) declaring type, not a derived type, not a parameterized type.
/// NestedTypeReference thus always resolves to a type definition, never to (partially) parameterized types.
/// </remarks>
public NestedTypeReference(ITypeReference declaringTypeRef, string name, int additionalTypeParameterCount)
public NestedTypeReference(ITypeReference declaringTypeRef, string name, int additionalTypeParameterCount, bool? isReferenceType = null)
{
if (declaringTypeRef == null)
throw new ArgumentNullException("declaringTypeRef");
@ -49,6 +50,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -49,6 +50,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
this.declaringTypeRef = declaringTypeRef;
this.name = name;
this.additionalTypeParameterCount = additionalTypeParameterCount;
this.isReferenceType = isReferenceType;
}
public ITypeReference DeclaringTypeReference {
@ -100,7 +102,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -100,7 +102,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
NestedTypeReference o = other as NestedTypeReference;
return o != null && declaringTypeRef == o.declaringTypeRef && name == o.name && additionalTypeParameterCount == o.additionalTypeParameterCount;
return o != null && declaringTypeRef == o.declaringTypeRef && name == o.name
&& additionalTypeParameterCount == o.additionalTypeParameterCount
&& isReferenceType == o.isReferenceType;
}
}
}

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

@ -29,27 +29,30 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -29,27 +29,30 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
{
readonly bool namespaceKnown;
readonly FullTypeName fullTypeName;
readonly bool? isReferenceType = null;
/// <summary>
/// Creates a new unknown type.
/// </summary>
/// <param name="namespaceName">Namespace name, if known. Can be null if unknown.</param>
/// <param name="name">Name of the type, must not be null.</param>
/// <param name="typeParameterCount">Type parameter count, zero if unknown.</param>
public UnknownType(string namespaceName, string name, int typeParameterCount = 0)
public UnknownType(string namespaceName, string name, int typeParameterCount = 0, bool? isReferenceType = null)
{
if (name == null)
throw new ArgumentNullException("name");
this.namespaceKnown = namespaceName != null;
this.fullTypeName = new TopLevelTypeName(namespaceName ?? string.Empty, name, typeParameterCount);
this.isReferenceType = isReferenceType;
}
/// <summary>
/// Creates a new unknown type.
/// </summary>
/// <param name="fullTypeName">Full name of the unknown type.</param>
public UnknownType(FullTypeName fullTypeName)
public UnknownType(FullTypeName fullTypeName, bool? isReferenceType = null)
{
this.isReferenceType = isReferenceType;
if (fullTypeName.Name == null) {
Debug.Assert(fullTypeName == default(FullTypeName));
this.namespaceKnown = false;
@ -93,7 +96,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -93,7 +96,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
public override bool? IsReferenceType {
get { return null; }
get { return isReferenceType; }
}
public override int GetHashCode()
@ -106,7 +109,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -106,7 +109,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
UnknownType o = other as UnknownType;
if (o == null)
return false;
return this.namespaceKnown == o.namespaceKnown && this.fullTypeName == o.fullTypeName;
return this.namespaceKnown == o.namespaceKnown && this.fullTypeName == o.fullTypeName && this.isReferenceType == o.isReferenceType;
}
public override string ToString()

7
ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs

@ -218,11 +218,18 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -218,11 +218,18 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
switch (type.Kind) {
case TypeKind.Unknown:
if (type.IsReferenceType == true) {
return StackType.O;
}
return StackType.Unknown;
case TypeKind.ByReference:
return StackType.Ref;
case TypeKind.Pointer:
return StackType.I;
case TypeKind.TypeParameter:
// Type parameters are always considered StackType.O, even
// though they might be instantiated with primitive types.
return StackType.O;
}
ITypeDefinition typeDef = type.GetEnumUnderlyingType().GetDefinition();
if (typeDef == null)

Loading…
Cancel
Save