From 680a3730d1c78603aebe3e356644390535c43437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Sun, 17 Apr 2011 18:15:55 +0200 Subject: [PATCH] Fixed NullReferenceException errors caused by unresolved references. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 40 ++++++++------ .../Ast/TypesHierarchyHelpers.cs | 54 +++++++++++++------ ICSharpCode.Decompiler/CecilExtensions.cs | 10 +++- .../ICSharpCode.Decompiler.csproj | 1 + .../ReferenceResolvingException.cs | 50 +++++++++++++++++ .../AnalyzedPropertyOverridesTreeNode.cs | 25 ++++++--- .../AnalyzerMethodOverridesTreeNode.cs | 26 +++++---- 7 files changed, 156 insertions(+), 50 deletions(-) create mode 100644 ICSharpCode.Decompiler/ReferenceResolvingException.cs diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 02e73d4d4..1d7859793 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -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 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); diff --git a/ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs b/ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs index 4668b1f8f..c9105d4e7 100644 --- a/ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs +++ b/ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs @@ -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 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 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 public static IEnumerable 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 } } - public static IEnumerable FindBaseProperties(PropertyDefinition property) + public static IEnumerable 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 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 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 private static bool MatchParameters(GenericContext baseParameterType, GenericContext 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 var baseType = type.Item.BaseType; var genericBaseType = baseType as GenericInstanceType; if (genericBaseType != null) { - type = new GenericContext(genericBaseType.Resolve(), - genericBaseType.GenericArguments.Select(t => type.Resolve(t))); + type = new GenericContext(genericBaseType.ResolveOrThrow(), + genericBaseType.GenericArguments.Select(t => type.ResolveWithContext(t))); } else - type = new GenericContext(baseType.Resolve()); + type = new GenericContext(baseType.ResolveOrThrow()); yield return type; } } @@ -201,7 +217,7 @@ namespace ICSharpCode.Decompiler.Ast : new GenericContext(type); } - struct GenericContext + struct GenericContext where T : class { private static readonly ReadOnlyCollection Empty = new ReadOnlyCollection(new List()); @@ -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 typeArguments) { + if (item == null) + throw new ArgumentNullException("item"); + Item = item; var list = new List(); foreach (var arg in typeArguments) { @@ -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 } 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 newArrayType.Dimensions[dimension] = arrayType.Dimensions[dimension]; return newArrayType; } - return type.Resolve(); + return type.ResolveOrThrow(); } - public GenericContext ApplyTo(T2 item) + public GenericContext ApplyTo(T2 item) where T2 : class { return new GenericContext(item, this.TypeArguments); } diff --git a/ICSharpCode.Decompiler/CecilExtensions.cs b/ICSharpCode.Decompiler/CecilExtensions.cs index 5e806e7af..46d471957 100644 --- a/ICSharpCode.Decompiler/CecilExtensions.cs +++ b/ICSharpCode.Decompiler/CecilExtensions.cs @@ -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) { diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 6e8d0eae8..072171276 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -110,6 +110,7 @@ + diff --git a/ICSharpCode.Decompiler/ReferenceResolvingException.cs b/ICSharpCode.Decompiler/ReferenceResolvingException.cs new file mode 100644 index 000000000..acd53b499 --- /dev/null +++ b/ICSharpCode.Decompiler/ReferenceResolvingException.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ICSharpCode.Decompiler +{ + /// + /// Represents an error while resolving a reference to a type or a member. + /// + [Serializable] + public class ReferenceResolvingException : Exception + { + /// + /// Initializes a new instance of the class + /// + public ReferenceResolvingException() + { + } + + /// + /// Initializes a new instance of the class + /// + /// A 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. + public ReferenceResolvingException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class + /// + /// A 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. + /// 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. + public ReferenceResolvingException(string message, Exception inner) + : base(message, inner) + { + } + + /// + /// Initializes a new instance of the class + /// + /// The object that holds the serialized object data. + /// The contextual information about the source or destination. + protected ReferenceResolvingException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs index a4d028dc1..43601694a 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs @@ -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 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; } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs index 4244c595d..4200c78db 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs @@ -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 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; } }