Browse Source

Fixed NullReferenceException errors caused by unresolved references.

pull/131/head
Artur Zgodziński 14 years ago
parent
commit
680a3730d1
  1. 40
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 54
      ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs
  3. 10
      ICSharpCode.Decompiler/CecilExtensions.cs
  4. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  5. 50
      ICSharpCode.Decompiler/ReferenceResolvingException.cs
  6. 25
      ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs
  7. 26
      ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs

40
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -624,10 +624,14 @@ namespace ICSharpCode.Decompiler.Ast
if (!methodDef.DeclaringType.IsInterface) { if (!methodDef.DeclaringType.IsInterface) {
if (!methodDef.HasOverrides) { if (!methodDef.HasOverrides) {
astMethod.Modifiers = ConvertModifiers(methodDef); astMethod.Modifiers = ConvertModifiers(methodDef);
if (methodDef.IsVirtual ^ !methodDef.IsNewSlot) { if (methodDef.IsVirtual ^ !methodDef.IsNewSlot)
if (TypesHierarchyHelpers.FindBaseMethods(methodDef).Any()) try {
astMethod.Modifiers |= Modifiers.New; if (TypesHierarchyHelpers.FindBaseMethods(methodDef).Any())
} astMethod.Modifiers |= Modifiers.New;
}
catch (ReferenceResolvingException) {
// TODO: add some kind of notification (a comment?) about possible problems with decompiled code due to unresolved references.
}
} else } else
astMethod.PrivateImplementationType = ConvertType(methodDef.Overrides.First().DeclaringType); astMethod.PrivateImplementationType = ConvertType(methodDef.Overrides.First().DeclaringType);
astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters); astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters);
@ -739,17 +743,23 @@ namespace ICSharpCode.Decompiler.Ast
getterModifiers = ConvertModifiers(propDef.GetMethod); getterModifiers = ConvertModifiers(propDef.GetMethod);
setterModifiers = ConvertModifiers(propDef.SetMethod); setterModifiers = ConvertModifiers(propDef.SetMethod);
astProp.Modifiers = FixUpVisibility(getterModifiers | setterModifiers); astProp.Modifiers = FixUpVisibility(getterModifiers | setterModifiers);
if (accessor.IsVirtual && !accessor.IsNewSlot && (propDef.GetMethod == null || propDef.SetMethod == null)) try {
foreach (var basePropDef in TypesHierarchyHelpers.FindBaseProperties(propDef)) if (accessor.IsVirtual && !accessor.IsNewSlot && (propDef.GetMethod == null || propDef.SetMethod == null))
if (basePropDef.GetMethod != null && basePropDef.SetMethod != null) { foreach (var basePropDef in TypesHierarchyHelpers.FindBaseProperties(propDef))
var propVisibilityModifiers = ConvertModifiers(basePropDef.GetMethod) | ConvertModifiers(basePropDef.SetMethod); if (basePropDef.GetMethod != null && basePropDef.SetMethod != null) {
astProp.Modifiers = FixUpVisibility((astProp.Modifiers & ~Modifiers.VisibilityMask) | (propVisibilityModifiers & Modifiers.VisibilityMask)); var propVisibilityModifiers = ConvertModifiers(basePropDef.GetMethod) | ConvertModifiers(basePropDef.SetMethod);
break; astProp.Modifiers = FixUpVisibility((astProp.Modifiers & ~Modifiers.VisibilityMask) | (propVisibilityModifiers & Modifiers.VisibilityMask));
} else if ((basePropDef.GetMethod ?? basePropDef.SetMethod).IsNewSlot) break;
break; } else if ((basePropDef.GetMethod ?? basePropDef.SetMethod).IsNewSlot)
if (accessor.IsVirtual ^ !accessor.IsNewSlot) { break;
if (TypesHierarchyHelpers.FindBaseProperties(propDef).Any())
astProp.Modifiers |= Modifiers.New; if (accessor.IsVirtual ^ !accessor.IsNewSlot) {
if (TypesHierarchyHelpers.FindBaseProperties(propDef).Any())
astProp.Modifiers |= Modifiers.New;
}
}
catch (ReferenceResolvingException) {
// TODO: add some kind of notification (a comment?) about possible problems with decompiled code due to unresolved references.
} }
} }
astProp.Name = CleanName(propDef.Name); astProp.Name = CleanName(propDef.Name);

54
ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs

@ -14,9 +14,9 @@ namespace ICSharpCode.Decompiler.Ast
if (resolveTypeArguments) if (resolveTypeArguments)
return BaseTypes(derivedType).Any(t => t.Item == baseType); return BaseTypes(derivedType).Any(t => t.Item == baseType);
else { else {
var comparableBaseType = baseType.Resolve(); var comparableBaseType = baseType.ResolveOrThrow();
while (derivedType.BaseType != null) { while (derivedType.BaseType != null) {
var resolvedBaseType = derivedType.BaseType.Resolve(); var resolvedBaseType = derivedType.BaseType.ResolveOrThrow();
if (resolvedBaseType == null) if (resolvedBaseType == null)
return false; return false;
if (comparableBaseType == resolvedBaseType) if (comparableBaseType == resolvedBaseType)
@ -29,11 +29,16 @@ namespace ICSharpCode.Decompiler.Ast
public static bool IsBaseMethod(MethodDefinition parentMethod, MethodDefinition childMethod) public static bool IsBaseMethod(MethodDefinition parentMethod, MethodDefinition childMethod)
{ {
if (parentMethod == null)
throw new ArgumentNullException("parentMethod");
if (childMethod == null)
throw new ArgumentNullException("childMethod");
if (parentMethod.Name != childMethod.Name) if (parentMethod.Name != childMethod.Name)
return false; return false;
if (parentMethod.HasParameters || childMethod.HasParameters) if (parentMethod.HasParameters || childMethod.HasParameters)
if(!parentMethod.HasParameters || ! childMethod.HasParameters || parentMethod.Parameters.Count != childMethod.Parameters.Count) if (!parentMethod.HasParameters || !childMethod.HasParameters || parentMethod.Parameters.Count != childMethod.Parameters.Count)
return false; return false;
return FindBaseMethods(childMethod).Any(m => m == parentMethod);// || (parentMethod.HasGenericParameters && m.); return FindBaseMethods(childMethod).Any(m => m == parentMethod);// || (parentMethod.HasGenericParameters && m.);
@ -41,6 +46,11 @@ namespace ICSharpCode.Decompiler.Ast
public static bool IsBaseProperty(PropertyDefinition parentProperty, PropertyDefinition childProperty) public static bool IsBaseProperty(PropertyDefinition parentProperty, PropertyDefinition childProperty)
{ {
if (parentProperty == null)
throw new ArgumentNullException("parentProperty");
if (childProperty == null)
throw new ArgumentNullException("childProperty");
if (parentProperty.Name != childProperty.Name) if (parentProperty.Name != childProperty.Name)
return false; return false;
@ -53,6 +63,9 @@ namespace ICSharpCode.Decompiler.Ast
public static IEnumerable<MethodDefinition> FindBaseMethods(MethodDefinition method) public static IEnumerable<MethodDefinition> FindBaseMethods(MethodDefinition method)
{ {
if (method == null)
throw new ArgumentNullException("method");
var typeContext = CreateGenericContext(method.DeclaringType); var typeContext = CreateGenericContext(method.DeclaringType);
var gMethod = typeContext.ApplyTo(method); var gMethod = typeContext.ApplyTo(method);
@ -65,8 +78,11 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
public static IEnumerable<PropertyDefinition> FindBaseProperties(PropertyDefinition property) public static IEnumerable<PropertyDefinition> FindBaseProperties(PropertyDefinition property, bool ignoreResolveExceptions = false)
{ {
if (property == null)
throw new ArgumentNullException("property");
var typeContext = CreateGenericContext(property.DeclaringType); var typeContext = CreateGenericContext(property.DeclaringType);
var gProperty = typeContext.ApplyTo(property); var gProperty = typeContext.ApplyTo(property);
@ -109,7 +125,7 @@ namespace ICSharpCode.Decompiler.Ast
if (mCandidate.HasOverrides) if (mCandidate.HasOverrides)
return false; return false;
if (!IsSameType(candidate.Resolve(mCandidate.ReturnType), method.Resolve(mMethod.ReturnType))) if (!IsSameType(candidate.ResolveWithContext(mCandidate.ReturnType), method.ResolveWithContext(mMethod.ReturnType)))
return false; return false;
if (mCandidate.HasGenericParameters || mMethod.HasGenericParameters) { if (mCandidate.HasGenericParameters || mMethod.HasGenericParameters) {
@ -140,7 +156,7 @@ namespace ICSharpCode.Decompiler.Ast
if ((mCandidate.GetMethod ?? mCandidate.SetMethod).HasOverrides) if ((mCandidate.GetMethod ?? mCandidate.SetMethod).HasOverrides)
return false; return false;
if (!IsSameType(candidate.Resolve(mCandidate.PropertyType), property.Resolve(mProperty.PropertyType))) if (!IsSameType(candidate.ResolveWithContext(mCandidate.PropertyType), property.ResolveWithContext(mProperty.PropertyType)))
return false; return false;
if (mCandidate.HasParameters || mProperty.HasParameters) { if (mCandidate.HasParameters || mProperty.HasParameters) {
@ -158,8 +174,8 @@ namespace ICSharpCode.Decompiler.Ast
private static bool MatchParameters(GenericContext<ParameterDefinition> baseParameterType, GenericContext<ParameterDefinition> parameterType) private static bool MatchParameters(GenericContext<ParameterDefinition> baseParameterType, GenericContext<ParameterDefinition> parameterType)
{ {
var baseParam = baseParameterType.Resolve(baseParameterType.Item.ParameterType); var baseParam = baseParameterType.ResolveWithContext(baseParameterType.Item.ParameterType);
var param = parameterType.Resolve(parameterType.Item.ParameterType); var param = parameterType.ResolveWithContext(parameterType.Item.ParameterType);
return IsSameType(baseParam, param); return IsSameType(baseParam, param);
} }
@ -186,10 +202,10 @@ namespace ICSharpCode.Decompiler.Ast
var baseType = type.Item.BaseType; var baseType = type.Item.BaseType;
var genericBaseType = baseType as GenericInstanceType; var genericBaseType = baseType as GenericInstanceType;
if (genericBaseType != null) { if (genericBaseType != null) {
type = new GenericContext<TypeDefinition>(genericBaseType.Resolve(), type = new GenericContext<TypeDefinition>(genericBaseType.ResolveOrThrow(),
genericBaseType.GenericArguments.Select(t => type.Resolve(t))); genericBaseType.GenericArguments.Select(t => type.ResolveWithContext(t)));
} else } else
type = new GenericContext<TypeDefinition>(baseType.Resolve()); type = new GenericContext<TypeDefinition>(baseType.ResolveOrThrow());
yield return type; yield return type;
} }
} }
@ -201,7 +217,7 @@ namespace ICSharpCode.Decompiler.Ast
: new GenericContext<TypeDefinition>(type); : new GenericContext<TypeDefinition>(type);
} }
struct GenericContext<T> struct GenericContext<T> where T : class
{ {
private static readonly ReadOnlyCollection<TypeReference> Empty = new ReadOnlyCollection<TypeReference>(new List<TypeReference>()); private static readonly ReadOnlyCollection<TypeReference> Empty = new ReadOnlyCollection<TypeReference>(new List<TypeReference>());
@ -210,12 +226,18 @@ namespace ICSharpCode.Decompiler.Ast
public GenericContext(T item) public GenericContext(T item)
{ {
if (item == null)
throw new ArgumentNullException("item");
Item = item; Item = item;
TypeArguments = Empty; TypeArguments = Empty;
} }
public GenericContext(T item, IEnumerable<TypeReference> typeArguments) public GenericContext(T item, IEnumerable<TypeReference> typeArguments)
{ {
if (item == null)
throw new ArgumentNullException("item");
Item = item; Item = item;
var list = new List<TypeReference>(); var list = new List<TypeReference>();
foreach (var arg in typeArguments) { foreach (var arg in typeArguments) {
@ -231,7 +253,7 @@ namespace ICSharpCode.Decompiler.Ast
TypeArguments = typeArguments; TypeArguments = typeArguments;
} }
public TypeReference Resolve(TypeReference type) public TypeReference ResolveWithContext(TypeReference type)
{ {
var genericParameter = type as GenericParameter; var genericParameter = type as GenericParameter;
if (genericParameter != null && genericParameter.Owner.GenericParameterType == GenericParameterType.Type) { if (genericParameter != null && genericParameter.Owner.GenericParameterType == GenericParameterType.Type) {
@ -239,7 +261,7 @@ namespace ICSharpCode.Decompiler.Ast
} }
var arrayType = type as ArrayType; var arrayType = type as ArrayType;
if (arrayType != null) { if (arrayType != null) {
var resolvedElementType = Resolve(arrayType.ElementType); var resolvedElementType = ResolveWithContext(arrayType.ElementType);
if (resolvedElementType == null) if (resolvedElementType == null)
return null; return null;
if (resolvedElementType == arrayType.ElementType) if (resolvedElementType == arrayType.ElementType)
@ -249,10 +271,10 @@ namespace ICSharpCode.Decompiler.Ast
newArrayType.Dimensions[dimension] = arrayType.Dimensions[dimension]; newArrayType.Dimensions[dimension] = arrayType.Dimensions[dimension];
return newArrayType; return newArrayType;
} }
return type.Resolve(); return type.ResolveOrThrow();
} }
public GenericContext<T2> ApplyTo<T2>(T2 item) public GenericContext<T2> ApplyTo<T2>(T2 item) where T2 : class
{ {
return new GenericContext<T2>(item, this.TypeArguments); return new GenericContext<T2>(item, this.TypeArguments);
} }

10
ICSharpCode.Decompiler/CecilExtensions.cs

@ -185,7 +185,15 @@ namespace ICSharpCode.Decompiler
else else
return null; return null;
} }
public static TypeDefinition ResolveOrThrow(this TypeReference typeReference)
{
var resolved = typeReference.Resolve();
if (resolved == null)
throw new ReferenceResolvingException();
return resolved;
}
public static bool IsCompilerGenerated(this ICustomAttributeProvider provider) public static bool IsCompilerGenerated(this ICustomAttributeProvider provider)
{ {
if (provider != null && provider.HasCustomAttributes) { if (provider != null && provider.HasCustomAttributes) {

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -110,6 +110,7 @@
<Compile Include="ITextOutput.cs" /> <Compile Include="ITextOutput.cs" />
<Compile Include="PlainTextOutput.cs" /> <Compile Include="PlainTextOutput.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReferenceResolvingException.cs" />
<Compile Include="TextOutputWriter.cs" /> <Compile Include="TextOutputWriter.cs" />
<None Include="Properties\AssemblyInfo.template.cs" /> <None Include="Properties\AssemblyInfo.template.cs" />
</ItemGroup> </ItemGroup>

50
ICSharpCode.Decompiler/ReferenceResolvingException.cs

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ICSharpCode.Decompiler
{
/// <summary>
/// Represents an error while resolving a reference to a type or a member.
/// </summary>
[Serializable]
public class ReferenceResolvingException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="T:ResolveException"/> class
/// </summary>
public ReferenceResolvingException()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:ResolveException"/> class
/// </summary>
/// <param name="message">A <see cref="T:System.String"/> that describes the error. The content of message is intended to be understood by humans. The caller of this constructor is required to ensure that this string has been localized for the current system culture.</param>
public ReferenceResolvingException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:ResolveException"/> class
/// </summary>
/// <param name="message">A <see cref="T:System.String"/> that describes the error. The content of message is intended to be understood by humans. The caller of this constructor is required to ensure that this string has been localized for the current system culture.</param>
/// <param name="inner">The exception that is the cause of the current exception. If the innerException parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception.</param>
public ReferenceResolvingException(string message, Exception inner)
: base(message, inner)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:ResolveException"/> class
/// </summary>
/// <param name="info">The object that holds the serialized object data.</param>
/// <param name="context">The contextual information about the source or destination.</param>
protected ReferenceResolvingException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
: base(info, context)
{
}
}
}

25
ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast; using ICSharpCode.Decompiler.Ast;
using ICSharpCode.NRefactory.Utils; using ICSharpCode.NRefactory.Utils;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
@ -69,18 +70,26 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) { foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) {
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
if (!TypesHierarchyHelpers.IsBaseType(analyzedProperty.DeclaringType, type, resolveTypeArguments: false)) SharpTreeNode newNode = null;
continue; try {
if (!TypesHierarchyHelpers.IsBaseType(analyzedProperty.DeclaringType, type, resolveTypeArguments: false))
continue;
foreach (PropertyDefinition property in type.Properties) { foreach (PropertyDefinition property in type.Properties) {
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
if (TypesHierarchyHelpers.IsBaseProperty(analyzedProperty, property)) { if (TypesHierarchyHelpers.IsBaseProperty(analyzedProperty, property)) {
MethodDefinition anyAccessor = property.GetMethod ?? property.SetMethod; MethodDefinition anyAccessor = property.GetMethod ?? property.SetMethod;
bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot; bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot;
yield return new AnalyzedPropertyTreeNode(property, hidesParent ? "(hides) " : ""); newNode = new AnalyzedPropertyTreeNode(property, hidesParent ? "(hides) " : "");
}
} }
} }
catch (ReferenceResolvingException) {
// ignore this type definition.
}
if (newNode != null)
yield return newNode;
} }
} }

26
ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast; using ICSharpCode.Decompiler.Ast;
using ICSharpCode.NRefactory.Utils; using ICSharpCode.NRefactory.Utils;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
@ -73,20 +74,25 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes))
{ {
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
SharpTreeNode newNode = null;
try {
if (!TypesHierarchyHelpers.IsBaseType(analyzedMethod.DeclaringType, type, resolveTypeArguments: false))
continue;
if (!TypesHierarchyHelpers.IsBaseType(analyzedMethod.DeclaringType, type, resolveTypeArguments: false)) foreach (MethodDefinition method in type.Methods) {
continue; ct.ThrowIfCancellationRequested();
foreach (MethodDefinition method in type.Methods) if (TypesHierarchyHelpers.IsBaseMethod(analyzedMethod, method)) {
{ bool hidesParent = !method.IsVirtual ^ method.IsNewSlot;
ct.ThrowIfCancellationRequested(); newNode = new AnalyzedMethodTreeNode(method, hidesParent ? "(hides) " : "");
}
if (TypesHierarchyHelpers.IsBaseMethod(analyzedMethod, method))
{
bool hidesParent = !method.IsVirtual ^ method.IsNewSlot;
yield return new AnalyzedMethodTreeNode(method, hidesParent ? "(hides) " : "");
} }
} }
catch (ReferenceResolvingException) {
// ignore this type definition. maybe add a notification about such cases.
}
if (newNode != null)
yield return newNode;
} }
} }

Loading…
Cancel
Save