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 @@ -624,10 +624,14 @@ namespace ICSharpCode.Decompiler.Ast
if (!methodDef.DeclaringType.IsInterface) {
if (!methodDef.HasOverrides) {
astMethod.Modifiers = ConvertModifiers(methodDef);
if (methodDef.IsVirtual ^ !methodDef.IsNewSlot) {
if (TypesHierarchyHelpers.FindBaseMethods(methodDef).Any())
astMethod.Modifiers |= Modifiers.New;
}
if (methodDef.IsVirtual ^ !methodDef.IsNewSlot)
try {
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
astMethod.PrivateImplementationType = ConvertType(methodDef.Overrides.First().DeclaringType);
astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters);
@ -739,17 +743,23 @@ namespace ICSharpCode.Decompiler.Ast @@ -739,17 +743,23 @@ namespace ICSharpCode.Decompiler.Ast
getterModifiers = ConvertModifiers(propDef.GetMethod);
setterModifiers = ConvertModifiers(propDef.SetMethod);
astProp.Modifiers = FixUpVisibility(getterModifiers | setterModifiers);
if (accessor.IsVirtual && !accessor.IsNewSlot && (propDef.GetMethod == null || propDef.SetMethod == null))
foreach (var basePropDef in TypesHierarchyHelpers.FindBaseProperties(propDef))
if (basePropDef.GetMethod != null && basePropDef.SetMethod != null) {
var propVisibilityModifiers = ConvertModifiers(basePropDef.GetMethod) | ConvertModifiers(basePropDef.SetMethod);
astProp.Modifiers = FixUpVisibility((astProp.Modifiers & ~Modifiers.VisibilityMask) | (propVisibilityModifiers & Modifiers.VisibilityMask));
break;
} else if ((basePropDef.GetMethod ?? basePropDef.SetMethod).IsNewSlot)
break;
if (accessor.IsVirtual ^ !accessor.IsNewSlot) {
if (TypesHierarchyHelpers.FindBaseProperties(propDef).Any())
astProp.Modifiers |= Modifiers.New;
try {
if (accessor.IsVirtual && !accessor.IsNewSlot && (propDef.GetMethod == null || propDef.SetMethod == null))
foreach (var basePropDef in TypesHierarchyHelpers.FindBaseProperties(propDef))
if (basePropDef.GetMethod != null && basePropDef.SetMethod != null) {
var propVisibilityModifiers = ConvertModifiers(basePropDef.GetMethod) | ConvertModifiers(basePropDef.SetMethod);
astProp.Modifiers = FixUpVisibility((astProp.Modifiers & ~Modifiers.VisibilityMask) | (propVisibilityModifiers & Modifiers.VisibilityMask));
break;
} else if ((basePropDef.GetMethod ?? basePropDef.SetMethod).IsNewSlot)
break;
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);

54
ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs

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

10
ICSharpCode.Decompiler/CecilExtensions.cs

@ -185,7 +185,15 @@ namespace ICSharpCode.Decompiler @@ -185,7 +185,15 @@ namespace ICSharpCode.Decompiler
else
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)
{
if (provider != null && provider.HasCustomAttributes) {

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

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

50
ICSharpCode.Decompiler/ReferenceResolvingException.cs

@ -0,0 +1,50 @@ @@ -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; @@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.TreeView;
@ -69,18 +70,26 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -69,18 +70,26 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) {
ct.ThrowIfCancellationRequested();
if (!TypesHierarchyHelpers.IsBaseType(analyzedProperty.DeclaringType, type, resolveTypeArguments: false))
continue;
SharpTreeNode newNode = null;
try {
if (!TypesHierarchyHelpers.IsBaseType(analyzedProperty.DeclaringType, type, resolveTypeArguments: false))
continue;
foreach (PropertyDefinition property in type.Properties) {
ct.ThrowIfCancellationRequested();
foreach (PropertyDefinition property in type.Properties) {
ct.ThrowIfCancellationRequested();
if (TypesHierarchyHelpers.IsBaseProperty(analyzedProperty, property)) {
MethodDefinition anyAccessor = property.GetMethod ?? property.SetMethod;
bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot;
yield return new AnalyzedPropertyTreeNode(property, hidesParent ? "(hides) " : "");
if (TypesHierarchyHelpers.IsBaseProperty(analyzedProperty, property)) {
MethodDefinition anyAccessor = property.GetMethod ?? property.SetMethod;
bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot;
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; @@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.TreeView;
@ -73,20 +74,25 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -73,20 +74,25 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes))
{
ct.ThrowIfCancellationRequested();
SharpTreeNode newNode = null;
try {
if (!TypesHierarchyHelpers.IsBaseType(analyzedMethod.DeclaringType, type, resolveTypeArguments: false))
continue;
if (!TypesHierarchyHelpers.IsBaseType(analyzedMethod.DeclaringType, type, resolveTypeArguments: false))
continue;
foreach (MethodDefinition method in type.Methods) {
ct.ThrowIfCancellationRequested();
foreach (MethodDefinition method in type.Methods)
{
ct.ThrowIfCancellationRequested();
if (TypesHierarchyHelpers.IsBaseMethod(analyzedMethod, method))
{
bool hidesParent = !method.IsVirtual ^ method.IsNewSlot;
yield return new AnalyzedMethodTreeNode(method, hidesParent ? "(hides) " : "");
if (TypesHierarchyHelpers.IsBaseMethod(analyzedMethod, method)) {
bool hidesParent = !method.IsVirtual ^ method.IsNewSlot;
newNode = 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